# HG changeset patch # User Christian Haeubl # Date 1328038636 28800 # Node ID f4c82dd4619eb3afae34309a6a1462dc416cdf60 # Parent b788ebbb7ef8f3fea1d99b1b420a5ea6da5194e9 inlining bugfixes and cleanup diff -r b788ebbb7ef8 -r f4c82dd4619e graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Mon Jan 30 17:02:27 2012 -0800 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java Tue Jan 31 11:37:16 2012 -0800 @@ -35,16 +35,18 @@ */ private static final long serialVersionUID = -6877016333706838441L; - private RiResolvedType[] types; - private double[] probabilities; + private final RiResolvedType[] types; + private final double notRecordedProbability; + private final double[] probabilities; - public RiTypeProfile(RiResolvedType[] types, double[] probabilites) { + public RiTypeProfile(RiResolvedType[] types, double notRecordedProbability, double[] probabilites) { this.types = types; + this.notRecordedProbability = notRecordedProbability; this.probabilities = probabilites; } /** - * The estimated probabilities of the different receivers. This array needs to have the same length as + * The estimated probabilities of the different receivers. This array needs to have the same length as the array returned by * {@link RiTypeProfile#types}. */ public double[] getProbabilities() { @@ -52,6 +54,14 @@ } /** + * Returns the estimated probability of all types that could not be recorded due to profiling limitations. + * @return double value >= 0.0 and <= 1.0 + */ + public double getNotRecordedProbability() { + return notRecordedProbability; + } + + /** * A list of receivers for which the runtime has recorded probability information. This array needs to have the same * length as {@link RiTypeProfile#probabilities}. */ diff -r b788ebbb7ef8 -r f4c82dd4619e graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Mon Jan 30 17:02:27 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Tue Jan 31 11:37:16 2012 -0800 @@ -43,6 +43,7 @@ public static boolean Intrinsify = true; public static boolean CacheGraphs = ____; public static boolean InlineWithTypeCheck = true; + public static boolean InlineMultipleMethods = true; public static int MaximumInlineSize = 35; public static int MaximumFreqInlineSize = 300; public static int FreqInlineRatio = 20; diff -r b788ebbb7ef8 -r f4c82dd4619e graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Mon Jan 30 17:02:27 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Tue Jan 31 11:37:16 2012 -0800 @@ -208,7 +208,7 @@ public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { MethodCallTargetNode callTargetNode = invoke.callTarget(); int numberOfMethods = concretes.size(); - boolean hasReturnValue = callTargetNode.kind() != CiKind.Void; + boolean hasReturnValue = invoke.node().kind() != CiKind.Void; // receiver null check must be the first node InliningUtil.receiverNullCheck(invoke); @@ -230,14 +230,14 @@ FixedNode continuation = invoke.next(); invoke.setNext(null); - // setup a merge and a phi nodes for results and exceptions + // setup merge and phi nodes for results and exceptions MergeNode returnMerge = graph.add(new MergeNode()); returnMerge.setStateAfter(invoke.stateAfter()); returnMerge.setNext(continuation); PhiNode returnValuePhi = null; if (hasReturnValue) { - returnValuePhi = graph.unique(new PhiNode(callTargetNode.kind(), returnMerge, PhiType.Value)); + returnValuePhi = graph.unique(new PhiNode(invoke.node().kind(), returnMerge, PhiType.Value)); } MergeNode exceptionMerge = null; @@ -255,7 +255,7 @@ exceptionObjectPhi = graph.unique(new PhiNode(CiKind.Object, exceptionMerge, PhiType.Value)); } - // create a separate block for each invoked method + // create one separate block for each invoked method BeginNode[] calleeEntryNodes = new BeginNode[numberOfMethods]; for (int i = 0; i < numberOfMethods; i++) { Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi); @@ -285,7 +285,6 @@ FixedNode dispatchOnType = createDispatchOnType(graph, calleeEntryNodes); invoke.node().replaceAtUsages(returnValuePhi); invoke.node().replaceAndDelete(dispatchOnType); - GraphUtil.killCFG(invoke.node()); // do the actual inlining for every invoke for (int i = 0; i < calleeEntryNodes.length; i++) { @@ -299,7 +298,8 @@ private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback) { assert concretes.size() == 1; - BeginNode calleeEntryNode = graph.add(new MergeNode()); + MergeNode calleeEntryNode = graph.add(new MergeNode()); + calleeEntryNode.setStateAfter(invoke.stateAfter()); FixedNode dispatchOnType = createDispatchOnType(graph, new BeginNode[] {calleeEntryNode}); FixedWithNextNode pred = (FixedWithNextNode) invoke.node().predecessor(); @@ -491,6 +491,7 @@ if (typeProfile != null) { RiResolvedType[] types = typeProfile.getTypes(); double[] probabilities = typeProfile.getProbabilities(); + double notRecordedProbability = typeProfile.getNotRecordedProbability(); if (types != null && probabilities != null && types.length > 0) { assert types.length == probabilities.length : "length must match"; if (GraalOptions.InlineWithTypeCheck) { @@ -503,10 +504,11 @@ return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); } return null; - } else { + } else if (GraalOptions.InlineMultipleMethods) { // TODO (ch) allow inlining only the most frequent calls (e.g. 8 different methods, inline only 2 and invoke others) // may affect peak performance negatively if immature profiling information is used // TODO (ch) sort types by probability + // determine concrete methods and map type to specific method ArrayList concreteMethods = new ArrayList<>(); int[] typesToConcretes = new int[types.length]; @@ -539,6 +541,10 @@ } return null; } + } else { + if (GraalOptions.TraceInlining) { + TTY.println("not inlining %s because GraalOptions.InlineMultipleMethods == false", methodName(callTarget.targetMethod(), invoke)); + } } } else { if (GraalOptions.TraceInlining) { diff -r b788ebbb7ef8 -r f4c82dd4619e graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java Mon Jan 30 17:02:27 2012 -0800 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java Tue Jan 31 11:37:16 2012 -0800 @@ -316,7 +316,7 @@ } } - private static class AbstractTypeData extends CounterData { + private abstract static class AbstractTypeData extends CounterData { private static final int RECEIVER_TYPE_DATA_ROW_SIZE = cellsToBytes(2); private static final int RECEIVER_TYPE_DATA_SIZE = cellIndexToOffset(1) + RECEIVER_TYPE_DATA_ROW_SIZE * config.typeProfileWidth; private static final int RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET = cellIndexToOffset(1); @@ -328,8 +328,6 @@ @Override public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) { - // TODO (ch) detect polymorphic case and return null and document interface accordingly - // is it really the best solution to return null? int typeProfileWidth = config.typeProfileWidth; RiResolvedType[] sparseTypes = new RiResolvedType[typeProfileWidth]; @@ -356,9 +354,12 @@ } } + totalCount += getTypesNotRecordedExecutionCount(data, position); return createRiTypeProfile(sparseTypes, counts, totalCount, entries); } + protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); + private static RiTypeProfile createRiTypeProfile(RiResolvedType[] sparseTypes, double[] counts, long totalCount, int entries) { RiResolvedType[] types; double[] probabilities; @@ -375,10 +376,15 @@ probabilities = counts; } + double totalProbability = 0.0; for (int i = 0; i < entries; i++) { - probabilities[i] = counts[i] / totalCount; + double p = counts[i] / totalCount; + probabilities[i] = p; + totalProbability += p; } - return new RiTypeProfile(types, probabilities); + + double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + return new RiTypeProfile(types, notRecordedTypeProbability, probabilities); } private static int getReceiverOffset(int row) { @@ -401,6 +407,12 @@ public int getExecutionCount(HotSpotMethodData data, int position) { return -1; } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + // TODO (ch) if types do not fit, profiling is skipped for typechecks + return 0; + } } private static class VirtualCallData extends AbstractTypeData { @@ -422,6 +434,11 @@ total += getCounterValue(data, position); return truncateLongToInt(total); } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } } private static class RetData extends CounterData { diff -r b788ebbb7ef8 -r f4c82dd4619e graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Mon Jan 30 17:02:27 2012 -0800 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Tue Jan 31 11:37:16 2012 -0800 @@ -255,7 +255,7 @@ for (int j = 0; j < types.length; j++) { TTY.print(" %s (%f)", types[j], probabilities[j]); } - TTY.println(); + TTY.println(" not recorded (%f)", typeProfile.getNotRecordedProbability()); } } }