changeset 8547:ca29d921a53a

GraalOptions.BenchmarkDynamicCounters to get counters for dacapo/specjvm2008 run
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 25 Mar 2013 11:09:40 +0100
parents f94baf373bcf
children 51d5999900e2
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java
diffstat 4 files changed, 209 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Thu Mar 21 13:35:45 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Mar 25 11:09:40 2013 +0100
@@ -44,6 +44,7 @@
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.printer.*;
@@ -76,6 +77,8 @@
 
     private boolean quietMeterAndTime;
 
+    private long compilerStartTime;
+
     public VMToCompilerImpl(HotSpotGraalRuntime compiler) {
         this.graalRuntime = compiler;
 
@@ -196,6 +199,95 @@
             t.setDaemon(true);
             t.start();
         }
+
+        if (GraalOptions.BenchmarkDynamicCounters) {
+            System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, " starting =====", " PASSED in ", "\n")));
+            System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, "Iteration ~ (~s) begins: ", "Iteration ~ (~s) ends:   ", "\n")));
+            DynamicCounterNode.excludedClassPrefix = "Lcom/oracle/graal/";
+            DynamicCounterNode.enabled = true;
+        }
+        if (GraalOptions.GenericDynamicCounters) {
+            DynamicCounterNode.enabled = true;
+        }
+        compilerStartTime = System.nanoTime();
+    }
+
+    private final class BenchmarkCountersOutputStream extends CallbackOutputStream {
+
+        private long startTime;
+        private boolean waitingForEnd;
+
+        private BenchmarkCountersOutputStream(PrintStream delegate, String... patterns) {
+            super(delegate, patterns);
+        }
+
+        @Override
+        protected void patternFound(int index) {
+            switch (index) {
+                case 0:
+                    startTime = System.nanoTime();
+                    DynamicCounterNode.clear();
+                    break;
+                case 1:
+                    waitingForEnd = true;
+                    break;
+                case 2:
+                    if (waitingForEnd) {
+                        waitingForEnd = false;
+                        DynamicCounterNode.dump(delegate, (System.nanoTime() - startTime) / 1000000000d);
+                    }
+                    break;
+            }
+        }
+    }
+
+    public abstract static class CallbackOutputStream extends OutputStream {
+
+        protected final PrintStream delegate;
+        private final byte[][] patterns;
+        private final int[] positions;
+
+        public CallbackOutputStream(PrintStream delegate, String... patterns) {
+            this.delegate = delegate;
+            this.positions = new int[patterns.length];
+            this.patterns = new byte[patterns.length][];
+            for (int i = 0; i < patterns.length; i++) {
+                this.patterns[i] = patterns[i].getBytes();
+            }
+        }
+
+        protected abstract void patternFound(int index);
+
+        @Override
+        public void write(int b) throws IOException {
+            try {
+                delegate.write(b);
+                for (int i = 0; i < patterns.length; i++) {
+                    int j = positions[i];
+                    byte[] cs = patterns[i];
+                    byte patternChar = cs[j];
+                    if (patternChar == '~' && Character.isDigit(b)) {
+                        // nothing to do...
+                    } else {
+                        if (patternChar == '~') {
+                            patternChar = cs[++positions[i]];
+                        }
+                        if (b == patternChar) {
+                            positions[i]++;
+                        } else {
+                            positions[i] = 0;
+                        }
+                    }
+                    if (positions[i] == patterns[i].length) {
+                        positions[i] = 0;
+                        patternFound(i);
+                    }
+                }
+            } catch (RuntimeException e) {
+                e.printStackTrace(delegate);
+                throw e;
+            }
+        }
     }
 
     /**
@@ -281,6 +373,7 @@
         }
         System.gc();
         phaseTransition("bootstrap2");
+
     }
 
     private MetricRateInPhase parsedBytecodesPerSecond;
@@ -353,6 +446,9 @@
         }
 
         SnippetCounter.printGroups(TTY.out().out());
+        if (GraalOptions.GenericDynamicCounters) {
+            DynamicCounterNode.dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d);
+        }
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Thu Mar 21 13:35:45 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Mon Mar 25 11:09:40 2013 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.debug;
 
+import java.io.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -45,30 +46,39 @@
     private static final int MAX_COUNTERS = 10 * 1024;
     private static final long[] COUNTERS = new long[MAX_COUNTERS];
     private static final HashMap<String, Integer> INDEXES = new HashMap<>();
+    public static String excludedClassPrefix = null;
+    public static boolean enabled = false;
+
     private final String name;
     private final long increment;
     private final boolean addContext;
 
     public DynamicCounterNode(String name, long increment, boolean addContext) {
         super(StampFactory.forVoid());
+        if (!enabled) {
+            throw new GraalInternalError("dynamic counters not enabled");
+        }
         this.name = name;
         this.increment = increment;
         this.addContext = addContext;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    public long getIncrement() {
+        return increment;
+    }
+
+    public boolean isAddContext() {
+        return addContext;
+    }
+
     private static synchronized int getIndex(String name) {
         Integer index = INDEXES.get(name);
         if (index == null) {
             index = INDEXES.size();
-            if (index == 0) {
-                Runtime.getRuntime().addShutdownHook(new Thread() {
-
-                    @Override
-                    public void run() {
-                        dump();
-                    }
-                });
-            }
             INDEXES.put(name, index);
             if (index >= MAX_COUNTERS) {
                 throw new GraalInternalError("too many dynamic counters");
@@ -79,44 +89,59 @@
         }
     }
 
-    private static synchronized void dump() {
+    public static synchronized void dump(PrintStream out, double seconds) {
         TreeMap<Long, String> sorted = new TreeMap<>();
 
         long sum = 0;
         for (int i = 0; i < MAX_COUNTERS; i++) {
             sum += COUNTERS[i];
         }
+        long cutoff = sum / 1000;
         int cnt = 0;
         for (Map.Entry<String, Integer> entry : INDEXES.entrySet()) {
-            sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey());
+            if (COUNTERS[entry.getValue()] > cutoff) {
+                sorted.put(COUNTERS[entry.getValue()] * MAX_COUNTERS + cnt++, entry.getKey());
+            }
         }
 
+        out.println("=========== dynamic counters, time = " + seconds + " s");
         for (Map.Entry<Long, String> entry : sorted.entrySet()) {
-            System.out.println((entry.getKey() / MAX_COUNTERS) + ": " + entry.getValue());
+            long counter = entry.getKey() / MAX_COUNTERS;
+            out.println((int) (counter / seconds) + "/s \t" + (counter * 100 / sum) + "% \t" + entry.getValue());
         }
-        System.out.println(sum + ": total");
+        out.println((int) (sum / seconds) + "/s: total");
+        out.println("============================");
 
+        clear();
+    }
+
+    public static void clear() {
+        Arrays.fill(COUNTERS, 0);
     }
 
     @Override
     public void lower(LoweringTool tool) {
-        int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name);
+        StructuredGraph graph = (StructuredGraph) graph();
+        if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
+            int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", ((StructuredGraph) graph()).method())) : getIndex(name);
 
-        StructuredGraph graph = (StructuredGraph) graph();
-        ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph);
-        ConstantNode indexConstant = ConstantNode.forInt(index, graph);
-        LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
-        IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph)));
-        StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
+            ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph);
+            ConstantNode indexConstant = ConstantNode.forInt(index, graph);
+            LoadIndexedNode load = graph.add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
+            IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph)));
+            StoreIndexedNode store = graph.add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
 
-        graph.addBeforeFixed(this, load);
-        graph.addBeforeFixed(this, store);
+            graph.addBeforeFixed(this, load);
+            graph.addBeforeFixed(this, store);
+        }
         graph.removeFixed(this);
     }
 
-    public static void createCounter(String name, FixedNode before, long increment, boolean addContext) {
-        StructuredGraph graph = (StructuredGraph) before.graph();
-        DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, increment, addContext));
-        graph.addBeforeFixed(before, counter);
+    public static void addCounterBefore(String name, long increment, boolean addContext, FixedNode position) {
+        if (enabled) {
+            StructuredGraph graph = (StructuredGraph) position.graph();
+            DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, increment, addContext));
+            graph.addBeforeFixed(position, counter);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java	Mon Mar 25 11:09:40 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.debug;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This is a special version of the dynamic counter node that removes itself as soon as it's the
+ * only usage of the associated node. This way it only increments the counter if the node is
+ * actually executed.
+ */
+public class SurvivingCounterNode extends DynamicCounterNode implements Simplifiable, Virtualizable {
+
+    @Input private ValueNode checkedValue;
+
+    public SurvivingCounterNode(String name, long increment, boolean addContext, ValueNode checkedValue) {
+        super(name, increment, addContext);
+        this.checkedValue = checkedValue;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        if (checkedValue instanceof FloatingNode && checkedValue.usages().count() == 1) {
+            tool.addToWorkList(checkedValue);
+            ((StructuredGraph) graph()).removeFixed(this);
+            // ((StructuredGraph) graph()).replaceFixedWithFixed(this, graph().add(new
+            // DynamicCounterNode("non-surviving " + getName(), getIncrement(), isAddContext())));
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(checkedValue);
+        if (state != null && state.getState() == EscapeState.Virtual) {
+            tool.delete();
+        }
+    }
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Mar 21 13:35:45 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Mar 25 11:09:40 2013 +0100
@@ -124,6 +124,8 @@
     public static String  LogFile                            = null;
     public static String  MethodFilter                       = null;
     public static boolean DumpOnError                        = ____;
+    public static boolean GenericDynamicCounters             = ____;
+    public static boolean BenchmarkDynamicCounters           = ____;
 
     // Ideal graph visualizer output settings
     public static boolean PrintBinaryGraphs                  = true;