changeset 5330:678f31e9724e

added -G:+CheckcastCounters to profile the paths taken through a compiled checkcast
author Doug Simon <doug.simon@oracle.com>
date Tue, 01 May 2012 10:53:56 +0200
parents 7ceb3f3671b9
children 6e346160f104
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java
diffstat 6 files changed, 124 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Apr 30 20:40:40 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Tue May 01 10:53:56 2012 +0200
@@ -225,6 +225,11 @@
      */
     public static boolean PrintFlags                           = false;
 
+    /**
+     * Counts the various paths taken through a compiled checkcast.
+     */
+    public static boolean CheckcastCounters = false;
+
     static {
         // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this)
         assert (DetailedAsserts = true) == true;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java	Mon Apr 30 20:40:40 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/OptimisticOptimizations.java	Tue May 01 10:53:56 2012 +0200
@@ -82,7 +82,7 @@
         return GraalOptions.RemoveNeverExecutedCode && enabledOpts.contains(Optimization.RemoveNeverExecutedCode);
     }
 
-    public boolean useUseTypeCheckHints() {
+    public boolean useTypeCheckHints() {
         return GraalOptions.UseTypeCheckHints && enabledOpts.contains(Optimization.UseTypeCheckHints);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon Apr 30 20:40:40 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue May 01 10:53:56 2012 +0200
@@ -278,6 +278,7 @@
         }
         CiCompilationStatistics.clear("final");
         MethodEntryCounters.printCounters(compiler);
+        HotSpotXirGenerator.printCounters(TTY.out().out());
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Mon Apr 30 20:40:40 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Tue May 01 10:53:56 2012 +0200
@@ -25,10 +25,14 @@
 import static com.oracle.graal.hotspot.ri.TemplateFlag.*;
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.io.*;
 import java.util.*;
 import java.util.concurrent.*;
 
+import sun.misc.*;
+
 import com.oracle.graal.compiler.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.Compiler;
 import com.oracle.max.asm.target.amd64.*;
@@ -460,56 +464,141 @@
         }
     };
 
+    private static final CheckcastCounters checkcastCounters = GraalOptions.CheckcastCounters ? new CheckcastCounters() : null;
+
+    public static class CheckcastCounters {
+        long hintsHits;
+        long hintsMisses;
+        long exact;
+        long noHints;
+        long isNull;
+        long exceptions;
+
+        static final int hintsHitsOffset;
+        static final int hintsMissesOffset;
+        static final int exactOffset;
+        static final int noHintsOffset;
+        static final int isNullOffset;
+        static final int exceptionsOffset;
+
+        static {
+            Unsafe unsafe = Unsafe.getUnsafe();
+            try {
+                hintsHitsOffset = (int) unsafe.objectFieldOffset(CheckcastCounters.class.getDeclaredField("hintsHits"));
+                hintsMissesOffset = (int) unsafe.objectFieldOffset(CheckcastCounters.class.getDeclaredField("hintsMisses"));
+                exactOffset = (int) unsafe.objectFieldOffset(CheckcastCounters.class.getDeclaredField("exact"));
+                noHintsOffset = (int) unsafe.objectFieldOffset(CheckcastCounters.class.getDeclaredField("noHints"));
+                isNullOffset = (int) unsafe.objectFieldOffset(CheckcastCounters.class.getDeclaredField("isNull"));
+                exceptionsOffset = (int) unsafe.objectFieldOffset(CheckcastCounters.class.getDeclaredField("exceptions"));
+            } catch (Exception e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        private static void printCounter(PrintStream out, String label, long count, long total) {
+            double percent = ((double) (count * 100)) / total;
+            out.println(String.format("%16s: %5.2f%%%10d", label, percent, count));
+        }
+
+        public void printCounters(PrintStream out) {
+            long total = hintsHits + hintsMisses + exact + noHints + isNull + exceptions;
+            out.println();
+            out.println("** Checkcast counters **");
+            printCounter(out, "hintsHits", hintsHits, total);
+            printCounter(out, "hintsMisses", hintsMisses, total);
+            printCounter(out, "exact", exact, total);
+            printCounter(out, "noHints", noHints, total);
+            printCounter(out, "isNull", isNull, total);
+            printCounter(out, "exceptions", exceptions, total);
+        }
+    }
+
     private IndexTemplates checkCastTemplates = new IndexTemplates(NULL_CHECK, EXACT_HINTS) {
 
+        private void incCounter(CiXirAssembler asm, XirOperand counter, XirParameter counters, int offset) {
+            XirConstant offsetOp = asm.i(offset);
+            asm.pload(CiKind.Long, counter, counters, offsetOp, false);
+            asm.add(counter, counter, asm.i(1));
+            asm.pstore(CiKind.Long, counters, offsetOp, counter, false);
+        }
+
         @Override
         protected XirTemplate create(CiXirAssembler asm, long flags, int hintCount) {
             asm.restart(CiKind.Void);
+            boolean exact = is(EXACT_HINTS, flags);
+            XirParameter counters = GraalOptions.CheckcastCounters ? asm.createConstantInputParameter("counters", CiKind.Object) : null;
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
-            final XirOperand hub = is(EXACT_HINTS, flags) ? null : asm.createConstantInputParameter("hub", CiKind.Object);
+            final XirOperand hub = exact ? null : asm.createConstantInputParameter("hub", CiKind.Object);
 
             XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
+            XirOperand counter = counters != null ? asm.createTemp("counter", CiKind.Long) : null;
 
-            XirLabel end = asm.createInlineLabel("end");
+            XirLabel success = asm.createInlineLabel("success");
             XirLabel slowPath = asm.createOutOfLineLabel("slow path");
 
             if (is(NULL_CHECK, flags)) {
                 // null can be cast to anything
-                asm.jeq(end, object, asm.o(null));
+                if (counters != null) {
+                    XirLabel isNotNull = asm.createInlineLabel("isNull");
+                    asm.jneq(isNotNull, object, asm.o(null));
+                    incCounter(asm, counter, counters, CheckcastCounters.isNullOffset);
+                    asm.jmp(success);
+                    asm.bindInline(isNotNull);
+                } else {
+                    asm.jeq(success, object, asm.o(null));
+                }
+
             }
 
             asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
             if (hintCount == 0) {
-                assert !is(EXACT_HINTS, flags);
+                assert !exact;
+                if (counters != null) {
+                    incCounter(asm, counter, counters, CheckcastCounters.noHintsOffset);
+                }
+
                 checkSubtype(asm, objHub, objHub, hub);
                 asm.jeq(slowPath, objHub, asm.o(null));
-                asm.bindInline(end);
+                asm.bindInline(success);
 
                 // -- out of line -------------------------------------------------------
                 asm.bindOutOfLine(slowPath);
             } else {
+                XirLabel hintsSuccess = counters == null ? success : asm.createInlineLabel("hintsSuccess");
                 XirOperand scratchObject = asm.createRegisterTemp("scratch", CiKind.Object, AMD64.r10);
                 // if we get an exact match: succeed immediately
                 for (int i = 0; i < hintCount; i++) {
                     XirParameter hintHub = asm.createConstantInputParameter("hintHub" + i, CiKind.Object);
                     asm.mov(scratchObject, hintHub);
                     if (i < hintCount - 1) {
-                        asm.jeq(end, objHub, scratchObject);
+                        asm.jeq(hintsSuccess, objHub, scratchObject);
                     } else {
                         asm.jneq(slowPath, objHub, scratchObject);
                     }
                 }
-                asm.bindInline(end);
+
+                if (counters != null) {
+                    asm.bindInline(hintsSuccess);
+                    incCounter(asm, counter, counters, exact ? CheckcastCounters.exactOffset : CheckcastCounters.hintsHitsOffset);
+                }
+
+                asm.bindInline(success);
 
                 // -- out of line -------------------------------------------------------
                 asm.bindOutOfLine(slowPath);
-                if (!is(EXACT_HINTS, flags)) {
+                if (!exact) {
+                    if (counters != null) {
+                        incCounter(asm, counter, counters, CheckcastCounters.hintsMissesOffset);
+                    }
                     checkSubtype(asm, objHub, objHub, hub);
-                    asm.jneq(end, objHub, asm.o(null));
+                    asm.jneq(success, objHub, asm.o(null));
                 }
             }
 
-            RiDeoptReason deoptReason = is(EXACT_HINTS, flags) ? RiDeoptReason.OptimizedTypeCheckViolated : RiDeoptReason.ClassCastException;
+            if (counters != null) {
+                incCounter(asm, counter, counters, CheckcastCounters.exceptionsOffset);
+            }
+            RiDeoptReason deoptReason = exact ? RiDeoptReason.OptimizedTypeCheckViolated : RiDeoptReason.ClassCastException;
             XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10);
             asm.mov(scratch, wordConst(asm, compiler.getRuntime().encodeDeoptActionAndReason(RiDeoptAction.InvalidateReprofile, deoptReason)));
             asm.callRuntime(CiRuntimeCall.Deoptimize, null);
@@ -737,11 +826,19 @@
 
     @Override
     public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type, RiResolvedType[] hints, boolean hintsExact) {
+        final boolean useCounters = GraalOptions.CheckcastCounters;
         if (hints == null || hints.length == 0) {
-            return new XirSnippet(checkCastTemplates.get(site, 0), receiver, hub);
+            if (useCounters) {
+                return new XirSnippet(checkCastTemplates.get(site, 0), XirArgument.forObject(checkcastCounters), receiver, hub);
+            } else {
+                return new XirSnippet(checkCastTemplates.get(site, 0), receiver, hub);
+            }
         } else {
-            XirArgument[] params = new XirArgument[hints.length + (hintsExact ? 1 : 2)];
+            XirArgument[] params = new XirArgument[(useCounters ? 1 : 0) + hints.length + (hintsExact ? 1 : 2)];
             int i = 0;
+            if (useCounters) {
+                params[i++] = XirArgument.forObject(checkcastCounters);
+            }
             params[i++] = receiver;
             if (!hintsExact) {
                 params[i++] = hub;
@@ -917,4 +1014,10 @@
             return getInternal(getBits(kind.ordinal(), site, flags));
         }
     }
+
+    public static void printCounters(PrintStream out) {
+        if (GraalOptions.CheckcastCounters) {
+            checkcastCounters.printCounters(out);
+        }
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Apr 30 20:40:40 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue May 01 10:53:56 2012 +0200
@@ -591,7 +591,7 @@
     private static final RiResolvedType[] EMPTY_TYPE_ARRAY = new RiResolvedType[0];
 
     private RiResolvedType[] getTypeCheckHints(RiResolvedType type, int maxHints) {
-        if (!optimisticOpts.useUseTypeCheckHints() || Util.isFinalClass(type)) {
+        if (!optimisticOpts.useTypeCheckHints() || Util.isFinalClass(type)) {
             return new RiResolvedType[] {type};
         } else {
             RiResolvedType uniqueSubtype = type.uniqueConcreteSubtype();
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java	Mon Apr 30 20:40:40 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java	Tue May 01 10:53:56 2012 +0200
@@ -871,7 +871,7 @@
         return createConstant(CiConstant.forInt(v));
     }
 
-    public XirConstant l(int v) {
+    public XirConstant l(long v) {
         return createConstant(CiConstant.forLong(v));
     }