changeset 21473:923c37b10fb4

compute compiled bytecodes using method inlining recording instead of a DebugMetric remove complex initialization of DebugMetrics and DebugTimers to implement -XX:+CITime and -XX:+CITimeEach
author Doug Simon <doug.simon@oracle.com>
date Sun, 24 May 2015 00:21:20 +0200
parents c190ed6b84bf
children 43c2b3eb3d6d
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java src/share/vm/graal/graalRuntime.cpp src/share/vm/graal/graalRuntime.hpp
diffstat 8 files changed, 111 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 22 23:11:17 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Sun May 24 00:21:20 2015 +0200
@@ -32,7 +32,6 @@
 import static com.oracle.graal.hotspot.InitTimer.*;
 import static com.oracle.graal.hotspot.meta.HotSpotSuitesProvider.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
-import static com.oracle.graal.phases.common.inlining.InliningUtil.*;
 
 import java.lang.management.*;
 import java.util.concurrent.*;
@@ -126,7 +125,12 @@
     /**
      * Time spent in compilation.
      */
-    public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+    private static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
+
+    /**
+     * Meters the {@linkplain StructuredGraph#getBytecodeSize() bytecodes} compiled.
+     */
+    private static final DebugMetric CompiledBytecodes = Debug.metric("CompiledBytecodes");
 
     public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
 
@@ -161,8 +165,7 @@
     public void runCompilation() {
         HotSpotVMConfig config = backend.getRuntime().getConfig();
         final long threadId = Thread.currentThread().getId();
-        long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue();
-        long previousCompilationTime = CompilationTime.getCurrentValue();
+        long startCompilationTime = System.nanoTime();
         HotSpotInstalledCode installedCode = null;
         final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
 
@@ -193,14 +196,11 @@
                 // Begin the compilation event.
                 compilationEvent.begin();
 
-                boolean recordEvolMethodDeps = graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0;
-
                 HotSpotProviders providers = backend.getProviders();
                 graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
-                if (!recordEvolMethodDeps) {
+                if (shouldDisableMethodInliningRecording(config)) {
                     graph.disableInlinedMethodRecording();
                 }
-                InlinedBytecodes.add(method.getCodeSize());
                 CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
                 if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) {
                     // for OSR, only a pointer is passed to the method.
@@ -280,7 +280,8 @@
                 System.exit(-1);
             }
         } finally {
-            final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+            final int compiledBytecodes = graph.getBytecodeSize();
+            CompiledBytecodes.add(compiledBytecodes);
 
             // Log a compilation event.
             if (compilationEvent.shouldWrite() && installedCode != null) {
@@ -290,25 +291,40 @@
                 compilationEvent.setSucceeded(true);
                 compilationEvent.setIsOsr(isOSR);
                 compilationEvent.setCodeSize(installedCode.getSize());
-                compilationEvent.setInlinedBytes(processedBytes);
+                compilationEvent.setInlinedBytes(compiledBytecodes);
                 compilationEvent.commit();
             }
 
             if (graalEnv != 0) {
                 long ctask = unsafe.getAddress(graalEnv + config.graalEnvTaskOffset);
                 assert ctask != 0L;
-                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
+                unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, compiledBytecodes);
             }
+            long compilationTime = System.nanoTime() - startCompilationTime;
             if ((config.ciTime || config.ciTimeEach) && installedCode != null) {
-                long time = CompilationTime.getCurrentValue() - previousCompilationTime;
-                TimeUnit timeUnit = CompilationTime.getTimeUnit();
-                long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
+                long timeUnitsPerSecond = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
                 CompilerToVM c2vm = backend.getRuntime().getCompilerToVM();
-                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, processedBytes, time, timeUnitsPerSecond, installedCode);
+                c2vm.notifyCompilationStatistics(id, method, entryBCI != INVOCATION_ENTRY_BCI, compiledBytecodes, compilationTime, timeUnitsPerSecond, installedCode);
             }
         }
     }
 
+    /**
+     * Determines whether to {@linkplain StructuredGraph#disableInlinedMethodRecording() disable}
+     * method inlining recording for the method being compiled.
+     *
+     * @see StructuredGraph#getBytecodeSize()
+     */
+    private boolean shouldDisableMethodInliningRecording(HotSpotVMConfig config) {
+        if (config.ciTime || config.ciTimeEach || CompiledBytecodes.isEnabled()) {
+            return false;
+        }
+        if (graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0) {
+            return false;
+        }
+        return true;
+    }
+
     private String getMethodDescription() {
         return String.format("%-6d Graal %-70s %-45s %-50s %s", id, method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(),
                         entryBCI == StructuredGraph.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + entryBCI + ") ");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri May 22 23:11:17 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Sun May 24 00:21:20 2015 +0200
@@ -26,14 +26,10 @@
 import static com.oracle.graal.hotspot.HotSpotOptionsLoader.*;
 import static java.lang.Double.*;
 
-import java.lang.reflect.*;
-
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionUtils.OptionConsumer;
-import com.oracle.graal.phases.common.inlining.*;
 
 //JaCoCo Exclude
 
@@ -47,17 +43,10 @@
 
     /**
      * Parses the Graal specific options specified to HotSpot (e.g., on the command line).
-     *
-     * @return true if the CITime or CITimeEach HotSpot VM options are set
      */
-    private static native boolean parseVMOptions();
+    private static native void parseVMOptions();
 
     static {
-        boolean timeCompilations = parseVMOptions();
-        if (timeCompilations) {
-            unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
-            unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
-        }
         assert !Debug.Initialization.isDebugInitialized() : "The class " + Debug.class.getName() + " must not be initialized before the Graal runtime has been initialized. " +
                         "This can be fixed by placing a call to " + Graal.class.getName() + ".runtime() on the path that triggers initialization of " + Debug.class.getName();
         if (areDebugScopePatternsEnabled()) {
@@ -127,33 +116,4 @@
     public static boolean parseOption(String option, OptionConsumer setter) {
         return OptionUtils.parseOption(options, option, GRAAL_OPTION_PREFIX, setter);
     }
-
-    /**
-     * Sets the relevant system property such that a {@link DebugTimer} or {@link DebugMetric}
-     * associated with a field in a class will be unconditionally enabled when it is created.
-     * <p>
-     * This method verifies that the named field exists and is of an expected type. However, it does
-     * not verify that the timer or metric created has the same name of the field.
-     *
-     * @param c the class in which the field is declared
-     * @param name the name of the field
-     */
-    private static void unconditionallyEnableTimerOrMetric(Class<?> c, String name) {
-        try {
-            Field field = c.getDeclaredField(name);
-            String propertyName;
-            if (DebugTimer.class.isAssignableFrom(field.getType())) {
-                propertyName = Debug.ENABLE_TIMER_PROPERTY_NAME_PREFIX + name;
-            } else {
-                assert DebugMetric.class.isAssignableFrom(field.getType());
-                propertyName = Debug.ENABLE_METRIC_PROPERTY_NAME_PREFIX + name;
-            }
-            String previous = System.setProperty(propertyName, "true");
-            if (previous != null) {
-                System.err.println("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\"");
-            }
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 22 23:11:17 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sun May 24 00:21:20 2015 +0200
@@ -1613,9 +1613,7 @@
                     }
 
                     // Record inlined method dependency in the graph
-                    if (graph.isInlinedMethodRecordingEnabled()) {
-                        graph.getInlinedMethods().add(targetMethod);
-                    }
+                    graph.recordInlinedMethod(targetMethod);
                 }
             }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri May 22 23:11:17 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Sun May 24 00:21:20 2015 +0200
@@ -116,9 +116,10 @@
     private final Assumptions assumptions;
 
     /**
-     * The methods that were inlined while constructing this graph.
+     * Records the methods that were inlined while constructing this graph along with how many times
+     * each method was inlined.
      */
-    private Set<ResolvedJavaMethod> inlinedMethods = new HashSet<>();
+    private Map<ResolvedJavaMethod, Integer> inlinedMethods = new HashMap<>();
 
     /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
@@ -515,12 +516,12 @@
     }
 
     /**
-     * Disables recording of methods inlined while constructing this graph. This can be done at most
+     * Disables method inlining recording while constructing this graph. This can be done at most
      * once and must be done before any inlined methods are recorded.
      */
     public void disableInlinedMethodRecording() {
-        assert inlinedMethods != null : "cannot disable inlined method recording more than once";
-        assert inlinedMethods.isEmpty() : "cannot disable inlined method recording once methods have been recorded";
+        assert inlinedMethods != null : "cannot disable method inlining recording more than once";
+        assert inlinedMethods.isEmpty() : "cannot disable method inlining recording once methods have been recorded";
         inlinedMethods = null;
     }
 
@@ -531,11 +532,69 @@
     /**
      * Gets the methods that were inlined while constructing this graph.
      *
-     * @return {@code null} if inlined method recording has been
+     * @return {@code null} if method inlining recording has been
      *         {@linkplain #disableInlinedMethodRecording() disabled}
      */
     public Set<ResolvedJavaMethod> getInlinedMethods() {
-        return inlinedMethods;
+        return inlinedMethods == null ? null : inlinedMethods.keySet();
+    }
+
+    /**
+     * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording()
+     * disabled}, records that {@code inlinedMethod} was inlined to this graph. Otherwise, this
+     * method does nothing.
+     */
+    public void recordInlinedMethod(ResolvedJavaMethod inlinedMethod) {
+        if (inlinedMethods != null) {
+            Integer count = inlinedMethods.get(inlinedMethod);
+            if (count != null) {
+                inlinedMethods.put(inlinedMethod, count + 1);
+            } else {
+                inlinedMethods.put(inlinedMethod, 1);
+            }
+        }
+    }
+
+    /**
+     * If method inlining recording has not been {@linkplain #disableInlinedMethodRecording()
+     * disabled}, updates the {@linkplain #getInlinedMethods() inlined methods} of this graph with
+     * the inlined methods of another graph. Otherwise, this method does nothing.
+     */
+    public void updateInlinedMethods(StructuredGraph other) {
+        if (inlinedMethods != null) {
+            assert this != other;
+            Map<ResolvedJavaMethod, Integer> otherInlinedMethods = other.inlinedMethods;
+            if (otherInlinedMethods != null) {
+                for (Map.Entry<ResolvedJavaMethod, Integer> e : otherInlinedMethods.entrySet()) {
+                    ResolvedJavaMethod key = e.getKey();
+                    Integer count = inlinedMethods.get(key);
+                    if (count != null) {
+                        inlinedMethods.put(key, count + e.getValue());
+                    } else {
+                        inlinedMethods.put(key, e.getValue());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this
+     * graph is constructed. This ignores how many bytecodes in each constituent method are actually
+     * parsed (which may be none for methods whose IR is retrieved from a cache or less than the
+     * full amount for any given method due to profile guided branch pruning). If method inlining
+     * recording has been {@linkplain #disableInlinedMethodRecording() disabled} for this graph,
+     * bytecode counts for inlined methods are not included in the returned value.
+     */
+    public int getBytecodeSize() {
+        int res = method.getCodeSize();
+        if (inlinedMethods != null) {
+            for (Map.Entry<ResolvedJavaMethod, Integer> e : inlinedMethods.entrySet()) {
+                int inlinedBytes = e.getValue() * e.getKey().getCodeSize();
+                res += inlinedBytes;
+            }
+        }
+        return res;
     }
 
     /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Fri May 22 23:11:17 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Sun May 24 00:21:20 2015 +0200
@@ -53,12 +53,6 @@
 public class InliningUtil {
 
     private static final String inliningDecisionsScopeString = "InliningDecisions";
-    /**
-     * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
-     * and all inlined methods), irrespective of how many bytecodes in each method are actually
-     * parsed (which may be none for methods whose IR is retrieved from a cache).
-     */
-    public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
 
     /**
      * Print a HotSpot-style inlining message to the console.
@@ -321,7 +315,7 @@
             unwindNode = (UnwindNode) duplicates.get(unwindNode);
         }
 
-        finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph.getInlinedMethods(), canonicalizedNodes);
+        finishInlining(invoke, graph, firstCFGNode, returnNodes, unwindNode, inlineGraph.getAssumptions(), inlineGraph, canonicalizedNodes);
 
         GraphUtil.killCFG(invokeNode);
 
@@ -329,7 +323,7 @@
     }
 
     public static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List<ReturnNode> returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions,
-                    Set<ResolvedJavaMethod> inlinedMethods, List<Node> canonicalizedNodes) {
+                    StructuredGraph inlineGraph, List<Node> canonicalizedNodes) {
         FixedNode invokeNode = invoke.asNode();
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
@@ -401,9 +395,7 @@
         }
 
         // Copy inlined methods from inlinee to caller
-        if (inlinedMethods != null && graph.getInlinedMethods() != null) {
-            graph.getInlinedMethods().addAll(inlinedMethods);
-        }
+        graph.updateInlinedMethods(inlineGraph);
 
         return returnValue;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Fri May 22 23:11:17 2015 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Sun May 24 00:21:20 2015 +0200
@@ -57,11 +57,8 @@
         Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck, canonicalizeNodes);
         getInlinedParameterUsages(canonicalizeNodes, calleeGraph, duplicateMap);
 
-        InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
         StructuredGraph graph = invoke.asNode().graph();
-        if (graph.isInlinedMethodRecordingEnabled()) {
-            graph.getInlinedMethods().add(concrete);
-        }
+        graph.recordInlinedMethod(concrete);
         return canonicalizeNodes;
     }
 
--- a/src/share/vm/graal/graalRuntime.cpp	Fri May 22 23:11:17 2015 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Sun May 24 00:21:20 2015 +0200
@@ -725,12 +725,11 @@
   GraalRuntime::initialize_natives(env, c2vmClass);
 JVM_END
 
-// private static boolean HotSpotOptions.parseVMOptions()
-JVM_ENTRY(jboolean, JVM_ParseGraalOptions(JNIEnv *env, jclass c))
+// private static void HotSpotOptions.parseVMOptions()
+JVM_ENTRY(void, JVM_ParseGraalOptions(JNIEnv *env, jclass c))
   HandleMark hm;
   KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)));
-  bool result = GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false);
-  return result;
+  GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK);
 JVM_END
 
 
@@ -803,19 +802,18 @@
   return JNI_OK;
 }
 
-bool GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
+void GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
   ResourceMark rm(THREAD);
 
   // Process option overrides from graal.options first
-  parse_graal_options_file(hotSpotOptionsClass, CHECK_false);
+  parse_graal_options_file(hotSpotOptionsClass, CHECK);
 
   // Now process options on the command line
   int numOptions = Arguments::num_graal_args();
   for (int i = 0; i < numOptions; i++) {
     char* arg = Arguments::graal_args_array()[i];
-    parse_argument(hotSpotOptionsClass, arg, CHECK_false);
+    parse_argument(hotSpotOptionsClass, arg, CHECK);
   }
-  return CITime || CITimeEach;
 }
 
 void GraalRuntime::check_required_value(const char* name, size_t name_len, const char* value, TRAPS) {
--- a/src/share/vm/graal/graalRuntime.hpp	Fri May 22 23:11:17 2015 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Sun May 24 00:21:20 2015 +0200
@@ -231,10 +231,10 @@
   static jint check_arguments(TRAPS);
 
   /**
-   * Parses the Graal specific VM options that were presented by the launcher and sets
+   * Parses the JVMCI specific VM options that were presented by the launcher and sets
    * the relevants Java fields.
    */
-  static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
+  static void parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
 
   static BasicType kindToBasicType(jchar ch);