# HG changeset patch # User Doug Simon # Date 1432419680 -7200 # Node ID 923c37b10fb4f3b2f93d417c89fa8a01342d9fba # Parent c190ed6b84bff0616fae5a9cd28a15e203216900 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 diff -r c190ed6b84bf -r 923c37b10fb4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- 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 + ") "); diff -r c190ed6b84bf -r 923c37b10fb4 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java --- 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. - *

- * 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); - } - } } diff -r c190ed6b84bf -r 923c37b10fb4 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- 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); } } diff -r c190ed6b84bf -r 923c37b10fb4 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- 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 inlinedMethods = new HashSet<>(); + private Map 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 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 otherInlinedMethods = other.inlinedMethods; + if (otherInlinedMethods != null) { + for (Map.Entry 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 e : inlinedMethods.entrySet()) { + int inlinedBytes = e.getValue() * e.getKey().getCodeSize(); + res += inlinedBytes; + } + } + return res; } /** diff -r c190ed6b84bf -r 923c37b10fb4 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java --- 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 returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions, - Set inlinedMethods, List canonicalizedNodes) { + StructuredGraph inlineGraph, List 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; } diff -r c190ed6b84bf -r 923c37b10fb4 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java --- 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 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; } diff -r c190ed6b84bf -r 923c37b10fb4 src/share/vm/graal/graalRuntime.cpp --- 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) { diff -r c190ed6b84bf -r 923c37b10fb4 src/share/vm/graal/graalRuntime.hpp --- 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);