# HG changeset patch # User Christian Wimmer # Date 1335556599 25200 # Node ID b5cd7bc05695151de0d31cd7c46c6645ad471daf # Parent c8c234c0587792f15204789c4982906c19e67241 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. diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- 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; diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- 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]; diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- 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 } diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- 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 } diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- 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) { diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/counters/MethodEntryCounters.java --- /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 { + protected static ArrayList 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 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 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(); + } +} diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- 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 diff -r c8c234c05877 -r b5cd7bc05695 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java --- 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); + } }; } diff -r c8c234c05877 -r b5cd7bc05695 src/share/vm/graal/graalCompilerToVM.cpp --- 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() {