changeset 4456:f4c82dd4619e

inlining bugfixes and cleanup
author Christian Haeubl <christian.haeubl@oracle.com>
date Tue, 31 Jan 2012 11:37:16 -0800
parents b788ebbb7ef8
children 5acf4a974e4a
files graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java
diffstat 5 files changed, 51 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- 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}.
      */
--- 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;
--- 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<RiResolvedMethod> 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) {
--- 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 {
--- 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());
                 }
             }
         }