Mercurial > hg > truffle
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.
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() {