changeset 5318:b5cd7bc05695

Method entry counters: Enable the flag to collect an execution profile of compiled methods and their callers. This allows to, e.g., detect methods that should be inlined because they are called frequently.
author Christian Wimmer <Christian.Wimmer@Oracle.com>
date Fri, 27 Apr 2012 12:56:39 -0700
parents c8c234c05877
children 38a5a8615f2d
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/counters/MethodEntryCounters.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 9 files changed, 241 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri Apr 27 12:56:39 2012 -0700
@@ -207,6 +207,15 @@
     public static boolean OptSafepointElimination            = true;
 
     /**
+     * Insert a counter in the method prologue to track the most frequently called methods that were compiled by Graal.
+     */
+    public static boolean MethodEntryCounters               = false;
+    /**
+     * Number of caller program counters to distinguish when counting methods.
+     */
+    public static int     MethodEntryCountersCallers        = 20;
+
+    /**
      * Flag to turn on SSA-based register allocation, which is currently under development.
      */
     public static boolean AllocSSA                           = false;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Apr 27 12:56:39 2012 -0700
@@ -484,7 +484,7 @@
         return !(location instanceof IndexedLocationNode) && location.displacement() < 4096;
     }
 
-    private void emitPrologue() {
+    protected void emitPrologue() {
         CiCallingConvention incomingArguments = frameMap.registerConfig.getCallingConvention(JavaCallee, CiUtil.signatureToKinds(method), target, false);
 
         CiValue[] params = new CiValue[incomingArguments.locations.length];
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Apr 27 12:56:39 2012 -0700
@@ -119,5 +119,7 @@
 
     long[] getDeoptedLeafGraphIds();
 
+    String decodePC(long pc);
+
     // Checkstyle: resume
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Apr 27 12:56:39 2012 -0700
@@ -171,5 +171,8 @@
     @Override
     public native long[] getDeoptedLeafGraphIds();
 
+    @Override
+    public native String decodePC(long pc);
+
     // Checkstyle: resume
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri Apr 27 12:56:39 2012 -0700
@@ -35,6 +35,7 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.Compiler;
+import com.oracle.graal.hotspot.counters.*;
 import com.oracle.graal.hotspot.ri.*;
 import com.oracle.graal.hotspot.server.*;
 import com.oracle.graal.hotspot.snippets.*;
@@ -211,6 +212,7 @@
         }
         System.gc();
         CiCompilationStatistics.clear("bootstrap2");
+        MethodEntryCounters.printCounters(compiler);
     }
 
     private void enqueue(Method m) throws Throwable {
@@ -264,6 +266,7 @@
             }
         }
         CiCompilationStatistics.clear("final");
+        MethodEntryCounters.printCounters(compiler);
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/counters/MethodEntryCounters.java	Fri Apr 27 12:56:39 2012 -0700
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.counters;
+
+import static com.oracle.max.cri.ci.CiValueUtil.*;
+
+import java.util.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.Compiler;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.criutils.*;
+
+
+public class MethodEntryCounters {
+    protected static final class Counter implements Comparable<Counter> {
+        protected static ArrayList<Counter> counters = new ArrayList<>();
+
+        protected final String method;
+        protected final long[] counts = new long[GraalOptions.MethodEntryCountersCallers * 2 + 2];
+
+        protected long sortCount;
+
+        protected Counter(RiResolvedMethod method) {
+            this.method = CiUtil.format("%H.%n", method);
+            counters.add(this);
+        }
+
+        @Override
+        public int compareTo(Counter o) {
+            return (int) (o.sortCount - sortCount);
+        }
+    }
+
+
+    protected static class AMD64MethodEntryOp extends AMD64LIRInstruction {
+        protected static int codeSize;
+
+        protected final Counter counter;
+
+        protected AMD64MethodEntryOp(Counter counter, CiValue counterArr, CiValue callerPc) {
+            super("ENTRY_COUNTER", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, new CiValue[] {counterArr, callerPc});
+            this.counter = counter;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            int start = masm.codeBuffer.position();
+
+            CiValue counterArr = temp(0);
+            CiValue callerPc = temp(1);
+
+            int off = Unsafe.getUnsafe().arrayBaseOffset(long[].class);
+            int scale = Unsafe.getUnsafe().arrayIndexScale(long[].class);
+
+            AMD64Move.move(tasm, masm, counterArr, CiConstant.forObject(counter.counts));
+            AMD64Move.load(tasm, masm, callerPc, new CiAddress(CiKind.Long, AMD64.rbp.asValue(CiKind.Long), 8), null);
+
+            Label done = new Label();
+            for (int i = 0; i < counter.counts.length - 2; i += 2) {
+                CiAddress counterPcAddr = new CiAddress(CiKind.Long, counterArr, i * scale + off);
+                CiAddress counterValueAddr = new CiAddress(CiKind.Long, counterArr, (i + 1) * scale + off);
+
+                Label skipClaim = new Label();
+                masm.cmpq(counterPcAddr, 0);
+                masm.jccb(ConditionFlag.notEqual, skipClaim);
+                AMD64Move.store(tasm, masm, counterPcAddr, callerPc, null);
+                masm.bind(skipClaim);
+
+                Label skipInc = new Label();
+                masm.cmpq(counterPcAddr, asRegister(callerPc));
+                masm.jccb(ConditionFlag.notEqual, skipInc);
+                masm.addq(counterValueAddr, 1);
+                masm.jmp(done);
+                masm.bind(skipInc);
+            }
+
+            CiAddress counterValueAddr = new CiAddress(CiKind.Long, counterArr, (counter.counts.length - 1) * scale + off);
+            masm.addq(counterValueAddr, 1);
+            masm.bind(done);
+
+            int size = masm.codeBuffer.position() - start;
+            assert codeSize == 0 || codeSize == size;
+            codeSize = size;
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+            if (mode == OperandMode.Temp && index == 0) {
+                return EnumSet.of(OperandFlag.Register);
+            } else if (mode == OperandMode.Temp && index == 1) {
+                return EnumSet.of(OperandFlag.Register);
+            }
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+
+    public static void emitCounter(LIRGenerator gen, RiResolvedMethod method) {
+        if (!GraalOptions.MethodEntryCounters) {
+            return;
+        }
+        gen.append(new AMD64MethodEntryOp(new Counter(method), gen.newVariable(CiKind.Long), gen.newVariable(CiKind.Long)));
+    }
+
+    public static int getCodeSize() {
+        if (!GraalOptions.MethodEntryCounters) {
+            return 0;
+        }
+        return AMD64MethodEntryOp.codeSize;
+    }
+
+
+    public static void printCounters(Compiler compiler) {
+        if (!GraalOptions.MethodEntryCounters) {
+            return;
+        }
+        ArrayList<Counter> copy = new ArrayList<>(Counter.counters);
+        long total = 0;
+        for (Counter counter : copy) {
+            long sum = 0;
+            for (int i = 0; i < counter.counts.length; i += 2) {
+                sum += counter.counts[i + 1];
+            }
+            counter.sortCount = sum;
+            total += sum;
+        }
+        Collections.sort(copy);
+
+        TTY.println();
+        TTY.println("** Compiled method invocation counters **");
+        for (Counter counter : copy) {
+            TTY.println("%16d %5.2f%%  %s", counter.sortCount, (double) counter.sortCount / total * 100d, counter.method);
+
+            if (counter.counts.length > 2) {
+                for (int i = 0; i < counter.counts.length; i += 2) {
+                    if (counter.counts[i] != 0 || counter.counts[i + 1] != 0) {
+                        TTY.print("              %16d  %5.2f%%", counter.counts[i + 1], (double) counter.counts[i + 1] / counter.sortCount * 100d);
+                        if (counter.counts[i] == 0) {
+                            TTY.println("  [other callers]");
+                        } else {
+                            TTY.println("  %x  %s", counter.counts[i], compiler.getCompilerToVM().decodePC(counter.counts[i]));
+                        }
+                        counter.counts[i] = 0;
+                        counter.counts[i + 1] = 0;
+                    }
+                }
+            }
+        }
+        TTY.println("** Compiled method invocation counters **");
+        TTY.println();
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Fri Apr 27 12:56:39 2012 -0700
@@ -32,6 +32,7 @@
 import com.oracle.max.criutils.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.counters.*;
 import com.oracle.graal.java.bytecode.*;
 
 /**
@@ -186,7 +187,12 @@
     }
 
     public int compiledCodeSize() {
-        return compiler.getCompilerToVM().RiMethod_getCompiledCodeSize(this);
+        int result = compiler.getCompilerToVM().RiMethod_getCompiledCodeSize(this);
+        if (result > 0) {
+            assert result > MethodEntryCounters.getCodeSize();
+            result =  result - MethodEntryCounters.getCodeSize();
+        }
+        return result;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Fri Apr 27 12:05:33 2012 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Fri Apr 27 12:56:39 2012 -0700
@@ -35,6 +35,7 @@
 import com.oracle.graal.compiler.target.amd64.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.counters.*;
 import com.oracle.graal.hotspot.ri.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
@@ -75,6 +76,12 @@
                 emitStore(pcAddress, CiConstant.LONG_0, false);
                 setResult(x, exception);
             }
+
+            @Override
+            protected void emitPrologue() {
+                super.emitPrologue();
+                MethodEntryCounters.emitCounter(this, method);
+            }
         };
     }
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Apr 27 12:05:33 2012 -0700
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri Apr 27 12:56:39 2012 -0700
@@ -1111,6 +1111,30 @@
   return JNIHandles::make_local(array);
 }
 
+JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_decodePC(JNIEnv *, jobject, jlong pc) {
+  TRACE_graal_3("CompilerToVM::decodePC");
+
+  VM_ENTRY_MARK;
+
+  stringStream(st);
+  CodeBlob* blob = CodeCache::find_blob_unsafe((void*) pc);
+  if (blob == NULL) {
+    st.print("[unidentified pc]");
+  } else {
+    st.print(blob->name());
+
+    nmethod* nm = blob->as_nmethod_or_null();
+    if (nm != NULL && nm->method() != NULL) {
+      st.print(" %s.", nm->method()->method_holder()->klass_part()->external_name());
+      nm->method()->name()->print_symbol_on(&st);
+      st.print("  @ %d", pc - (jlong) nm->entry_point());
+    }
+  }
+  Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL);
+  return JNIHandles::make_local(result());
+
+}
+
 
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_##f))
@@ -1179,6 +1203,7 @@
   {CC"executeCompiledMethodVarargs",      CC"("HS_COMP_METHOD "["OBJECT")"OBJECT,               FN_PTR(executeCompiledMethodVarargs)},
   {CC"RiMethod_vtableEntryOffset",        CC"("RESOLVED_METHOD")I",                             FN_PTR(RiMethod_vtableEntryOffset)},
   {CC"getDeoptedLeafGraphIds",            CC"()[J",                                             FN_PTR(getDeoptedLeafGraphIds)},
+  {CC"decodePC",                          CC"(J)"STRING,                                        FN_PTR(decodePC)},
 };
 
 int CompilerToVM_methods_count() {