# HG changeset patch # User Stefan Anzinger # Date 1427122716 -3600 # Node ID 422e60a2f4b96ceb57ada8a5a0eee2c2847b9bb3 # Parent 59c2d62927f7a232acf84a227bb1a294b51a8853 Implement dynamic instruction counters on assembly level diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java --- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java Mon Mar 23 15:58:36 2015 +0100 @@ -1741,4 +1741,20 @@ public void casxa(Register rs1, Register rs2, Register rd, Asi asi) { ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi); } + + @Override + public InstructionCounter getInstructionCounter() { + return new SPARCInstructionCounter(this); + } + + public void patchAddImmediate(int position, int simm13) { + int inst = getInt(position); + assert SPARCAssembler.isSimm13(simm13) : simm13; + assert (inst >>> 30) == 0b10 : String.format("0x%x", inst); + assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst); + assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst); + inst = inst & (~((1 << 13) - 1)); + inst |= simm13 & ((1 << 12) - 1); + emitInt(inst, position); + } } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCInstructionCounter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCInstructionCounter.java Mon Mar 23 15:58:36 2015 +0100 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009, 2015, 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.asm.sparc; + +import java.util.*; + +import com.oracle.graal.asm.Assembler.InstructionCounter; + +public class SPARCInstructionCounter implements InstructionCounter { + // Use a treemap to keep the order in the output + private static final TreeMap INSTRUCTION_MATCHER = new TreeMap<>(); + static { + // @formatter:off + INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000)); + INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf)); + INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd)); + INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0)); + // @formatter:on + } + private final SPARCAssembler asm; + + public SPARCInstructionCounter(SPARCAssembler asm) { + super(); + this.asm = asm; + } + + @Override + public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) { + SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length]; + for (int i = 0; i < instructionTypes.length; i++) { + String typeName = instructionTypes[i]; + matchers[i] = INSTRUCTION_MATCHER.get(typeName); + if (matchers[i] == null) { + throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet())); + } + } + return countBetween(matchers, beginPc, endPc); + } + + private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) { + int[] counts = new int[matchers.length]; + for (int p = startPc; p < endPc; p += 4) { + int instr = asm.getInt(p); + for (int i = 0; i < matchers.length; i++) { + SPARCInstructionMatch matcher = matchers[i]; + if (matcher.matches(instr)) { + counts[i]++; + } + } + } + return counts; + } + + @Override + public String[] getSupportedInstructionTypes() { + return INSTRUCTION_MATCHER.keySet().toArray(new String[0]); + } + + /** + * Tests the lower 3 bits of the op3 field. + */ + private static class OP3LowBitsMatcher extends SPARCInstructionMatch { + private final int[] op3b03; + private final int op; + + public OP3LowBitsMatcher(int op, int... op3b03) { + super(0, 0); + this.op = op; + this.op3b03 = op3b03; + } + + @Override + public boolean matches(int instruction) { + if (instruction >>> 30 != op) { + return false; + } + int op3lo = (instruction >> 19) & ((1 << 4) - 1); + for (int op3Part : op3b03) { + if (op3Part == op3lo) { + return true; + } + } + return false; + } + } + + private static class SPARCInstructionMatch { + private final int mask; + private final int[] patterns; + + public SPARCInstructionMatch(int mask, int... patterns) { + super(); + this.mask = mask; + this.patterns = patterns; + } + + public boolean matches(int instruction) { + for (int pattern : patterns) { + if ((instruction & mask) == pattern) { + return true; + } + } + return false; + } + } +} diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java --- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java Mon Mar 23 15:58:36 2015 +0100 @@ -213,6 +213,10 @@ return hint; } + public InstructionCounter getInstructionCounter() { + throw new UnsupportedOperationException("Instruction counter is not implemented for " + this); + } + public static class LabelHint { private Label label; private int forPosition; @@ -242,4 +246,14 @@ return capturedTarget >= 0; } } + + /** + * Instruction counter class which gives the user of the assembler to count different kinds of + * instructions in the generated assembler code. + */ + public interface InstructionCounter { + String[] getSupportedInstructionTypes(); + + int[] countInstructions(String[] instructionTypes, int beginPc, int endPc); + } } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Mon Mar 23 15:58:36 2015 +0100 @@ -46,6 +46,7 @@ import com.oracle.graal.lir.phases.*; import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; +import com.oracle.graal.lir.profiling.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.spi.*; @@ -320,7 +321,14 @@ throw Debug.handle(e); } FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig); - LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, graph.method(), stub); + String compilationUnitName; + ResolvedJavaMethod method = graph.method(); + if (method == null) { + compilationUnitName = ""; + } else { + compilationUnitName = method.format("%H.%n(%p)"); + } + LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, graph.method(), stub); LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes); NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen); diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java Mon Mar 23 15:58:36 2015 +0100 @@ -78,7 +78,7 @@ public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes); - public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub); + public abstract LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub); public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Mar 23 15:58:36 2015 +0100 @@ -78,8 +78,8 @@ } @Override - public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { - return new AMD64HotSpotLIRGenerationResult(lir, frameMapBuilder, stub); + public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { + return new AMD64HotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub); } @Override @@ -254,6 +254,9 @@ // Emit the suffix emitCodeSuffix(installedCodeOwner, crb, asm, frameMap); + + // Profile assembler instructions + profileInstructions(lir, crb); } /** diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java Mon Mar 23 15:58:36 2015 +0100 @@ -65,16 +65,16 @@ // load counters array masm.movptr(countersArrayReg, countersArrayAddr); - - forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment)); + CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement); + forEachCounter(emitProcedure, target); // restore scratch register masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot)); } - private void emitIncrement(AMD64MacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) { + private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value increment, int displacement) { // address for counter value - AMD64Address counterAddr = new AMD64Address(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment))); + AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement); // increment counter (in memory) if (isConstant(increment)) { masm.incrementl(counterAddr, asInt(asConstant(increment))); diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java Mon Mar 23 15:58:36 2015 +0100 @@ -48,8 +48,8 @@ */ private Map calleeSaveInfo = CollectionsFactory.newMap(); - public AMD64HotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { - super(lir, frameMapBuilder); + public AMD64HotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { + super(compilationUnitName, lir, frameMapBuilder); this.stub = stub; } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Mon Mar 23 15:58:36 2015 +0100 @@ -80,8 +80,8 @@ } @Override - public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { - return new SPARCHotSpotLIRGenerationResult(lir, frameMapBuilder, stub); + public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) { + return new SPARCHotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub); } @Override @@ -247,6 +247,8 @@ crb.emit(lir); } while (i++ < 1); + profileInstructions(lir, crb); + HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); if (!frameContext.isStub) { diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java Mon Mar 23 15:58:36 2015 +0100 @@ -23,11 +23,14 @@ package com.oracle.graal.hotspot.sparc; import static com.oracle.graal.api.code.ValueUtil.*; +import static com.oracle.graal.asm.sparc.SPARCAssembler.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.lir.*; @@ -37,12 +40,16 @@ public class SPARCHotSpotCounterOp extends HotSpotCounterOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class); + private int[] counterPatchOffsets; + public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) { super(TYPE, name, group, increment, registers, config); + this.counterPatchOffsets = new int[1]; } public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) { super(TYPE, names, groups, increments, registers, config); + this.counterPatchOffsets = new int[names.length]; } @Override @@ -57,19 +64,17 @@ // load counters array masm.ldx(countersArrayAddr, countersArrayReg); - - forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment)); + IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm); + forEachCounter(emitter, target); } } - private void emitIncrement(SPARCMacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) { - // address for counter - SPARCAddress counterAddr = new SPARCAddress(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment))); - + private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) { try (ScratchRegister scratch = masm.getScratchRegister()) { Register counterReg = scratch.getRegister(); // load counter value masm.ldx(counterAddr, counterReg); + counterPatchOffsets[counterIndex] = masm.position(); // increment counter if (isConstant(increment)) { masm.add(counterReg, asInt(asConstant(increment)), counterReg); @@ -80,4 +85,53 @@ masm.stx(counterReg, counterAddr); } } + + /** + * Patches the increment value in the instruction emitted by the + * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is + * used if patching is needed after assembly. + * + * @param asm + * @param increment + */ + @Override + public void patchCounterIncrement(Assembler asm, int[] increment) { + for (int i = 0; i < increment.length; i++) { + int inst = counterPatchOffsets[i]; + ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]); + } + } + + public int[] getCounterPatchOffsets() { + return counterPatchOffsets; + } + + private class IncrementEmitter implements CounterProcedure { + private int lastDisplacement = 0; + private final Register countersArrayReg; + private final SPARCMacroAssembler masm; + + public IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) { + super(); + this.countersArrayReg = countersArrayReg; + this.masm = masm; + } + + public void apply(int counterIndex, Value increment, int displacement) { + SPARCAddress counterAddr; + int relativeDisplacement = displacement - lastDisplacement; + if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction + counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement); + } else { + try (ScratchRegister scratch = masm.getScratchRegister()) { + Register tempOffsetRegister = scratch.getRegister(); + new Setx(relativeDisplacement, tempOffsetRegister, false).emit(masm); + masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg); + } + lastDisplacement = displacement; + counterAddr = new SPARCAddress(countersArrayReg, 0); + } + emitIncrement(counterIndex, masm, counterAddr, increment); + } + } } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java Mon Mar 23 15:58:36 2015 +0100 @@ -47,8 +47,8 @@ */ private Map calleeSaveInfo = new HashMap<>(); - public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { - super(lir, frameMapBuilder); + public SPARCHotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) { + super(compilationUnitName, lir, frameMapBuilder); this.stub = stub; } @@ -67,5 +67,4 @@ Map getCalleeSaveInfo() { return calleeSaveInfo; } - } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Mon Mar 23 15:58:36 2015 +0100 @@ -40,6 +40,7 @@ import com.oracle.graal.lir.LIRInstruction.OperandMode; import com.oracle.graal.lir.StandardOp.LabelOp; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; +import com.oracle.graal.lir.asm.*; import com.oracle.graal.lir.framemap.*; import com.oracle.graal.nodes.*; import com.oracle.graal.options.*; @@ -55,6 +56,9 @@ // @formatter:off @Option(help = "Use Graal stubs instead of HotSpot stubs where possible") public static final OptionValue PreferGraalStubs = new OptionValue<>(false); + @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + + " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) + public static final OptionValue ASMInstructionProfiling = new OptionValue<>(null); // @formatter:on } @@ -235,4 +239,10 @@ public DisassemblerProvider getDisassembler() { return getProviders().getDisassembler(); } + + protected void profileInstructions(LIR lir, CompilationResultBuilder crb) { + if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) { + HotSpotInstructionProfiling.countInstructions(lir, crb.asm); + } + } } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java Mon Mar 23 15:58:36 2015 +0100 @@ -24,6 +24,8 @@ import static com.oracle.graal.api.code.ValueUtil.*; +import java.util.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; @@ -67,12 +69,42 @@ } protected interface CounterProcedure { - void apply(String name, String group, Value increment); + /** + * Lambda interface for iterating over counters declared in this op. + * + * @param counterIndex Index in this CounterOp object. + * @param increment Value for increment + * @param displacement Displacement in bytes in the counter array + */ + void apply(int counterIndex, Value increment, int displacement); } - protected void forEachCounter(CounterProcedure proc) { - for (int i = 0; i < names.length; i++) { - proc.apply(names[i], groups[i], increments[i]); + /** + * Calls the {@link CounterProcedure} for each counter in ascending order of their displacement + * in the counter array. + * + * @param proc The procedure to be called + * @param target Target architecture (used to calculate the array displacements) + */ + protected void forEachCounter(CounterProcedure proc, TargetDescription target) { + if (names.length == 1) { // fast path + int arrayIndex = getIndex(names[0], groups[0], increments[0]); + int displacement = getDisplacementForLongIndex(target, arrayIndex); + proc.apply(0, increments[0], displacement); + } else { // Slow path with sort by displacements ascending + int[] displacements = new int[names.length]; + HashMap offsetMap = new HashMap<>(names.length); + for (int i = 0; i < names.length; i++) { + int arrayIndex = getIndex(names[i], groups[i], increments[i]); + displacements[i] = getDisplacementForLongIndex(target, arrayIndex); + offsetMap.put(displacements[i], i); + } + Arrays.sort(displacements); + // Now apply in order + for (int offset : displacements) { + int idx = offsetMap.get(offset); + proc.apply(idx, increments[idx], displacements[idx]); + } } } @@ -86,6 +118,17 @@ return BenchmarkCounters.getIndex(name, group, config); } + /** + * Patches the increment value in the instruction emitted by this instruction. Use only, if + * patching is needed after assembly. + * + * @param asm + * @param increment + */ + public void patchCounterIncrement(Assembler asm, int[] increment) { + throw GraalInternalError.unimplemented(); + } + private static long asLong(JavaConstant value) { Kind kind = value.getKind(); switch (kind) { @@ -109,4 +152,11 @@ return (int) l; } + public String[] getNames() { + return names; + } + + public String[] getGroups() { + return groups; + } } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java Mon Mar 23 15:58:36 2015 +0100 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015, 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; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.asm.Assembler.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.phases.*; + +public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase { + public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER"; + private final String[] instructionsToProfile; + + public HotSpotInstructionProfiling(String instructionsToProfile) { + this.instructionsToProfile = instructionsToProfile.split(","); + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, + BenchmarkCounterFactory counterFactory) { + new Analyzer(lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), counterFactory).run(); + } + + private class Analyzer { + private final LIR lir; + private final BenchmarkCounterFactory counterFactory; + private final LIRInsertionBuffer buffer; + private final String compilationUnitName; + + public Analyzer(String compilationUnitName, LIR lir, BenchmarkCounterFactory counterFactory) { + this.lir = lir; + this.compilationUnitName = compilationUnitName; + this.counterFactory = counterFactory; + this.buffer = new LIRInsertionBuffer(); + } + + public void run() { + for (AbstractBlockBase block : lir.getControlFlowGraph().getBlocks()) { + doBlock(block); + } + } + + public void doBlock(AbstractBlockBase block) { + List instructions = lir.getLIRforBlock(block); + assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions; + assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1); + assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2); + assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0); + assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1); + String[] names = new String[instructionsToProfile.length]; + String[] groups = new String[instructionsToProfile.length]; + Value[] increments = new Value[instructionsToProfile.length]; + for (int i = 0; i < instructionsToProfile.length; i++) { + names[i] = compilationUnitName; + groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i]; + increments[i] = JavaConstant.INT_0; + } + HotSpotCounterOp op = (HotSpotCounterOp) counterFactory.createMultiBenchmarkCounter(names, groups, increments); + LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile); + assert inst != null; + buffer.init(instructions); + buffer.append(1, inst); + buffer.finish(); + } + } + + /** + * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)} + * calls this method for patching the instruction counts into the coutner increment code. + */ + public static void countInstructions(LIR lir, Assembler asm) { + InstructionCounterOp lastOp = null; + InstructionCounter counter = asm.getInstructionCounter(); + for (AbstractBlockBase block : lir.codeEmittingOrder()) { + for (LIRInstruction inst : lir.getLIRforBlock(block)) { + if (inst instanceof InstructionCounterOp) { + InstructionCounterOp currentOp = (InstructionCounterOp) inst; + + if (lastOp != null) { + int beginPc = lastOp.countOffsetEnd; + int endPc = currentOp.countOffsetBegin; + int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc); + lastOp.delegate.patchCounterIncrement(asm, instructionCounts); + } + lastOp = ((InstructionCounterOp) inst); + } + } + } + if (lastOp != null) { + assert lastOp.countOffsetBegin < asm.position(); + int beginPc = lastOp.countOffsetBegin; + int endPc = asm.position(); + int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc); + lastOp.delegate.patchCounterIncrement(asm, instructionCounts); + } + } + + public static class InstructionCounterOp extends LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(InstructionCounterOp.class); + private final HotSpotCounterOp delegate; + private final String[] instructionsToProfile; + private int countOffsetBegin; + private int countOffsetEnd; + + public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) { + super(TYPE); + this.delegate = delegate; + this.instructionsToProfile = instructionsToProfile; + } + + @Override + public void emitCode(CompilationResultBuilder crb) { + countOffsetBegin = crb.asm.position(); + this.delegate.emitCode(crb); + countOffsetEnd = crb.asm.position(); + } + + public String[] getInstructionsToProfile() { + return instructionsToProfile; + } + } +} diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java Mon Mar 23 15:58:36 2015 +0100 @@ -132,7 +132,11 @@ } public LIRSuites createLIRSuites() { - return Suites.createDefaultLIRSuites(); + LIRSuites suites = Suites.createDefaultLIRSuites(); + String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue(); + if (profileInstructions != null) { + suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions)); + } + return suites; } - } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java Mon Mar 23 15:58:36 2015 +0100 @@ -56,4 +56,6 @@ boolean hasForeignCall(); void setForeignCall(boolean b); + + String getCompilationUnitName(); } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java Mon Mar 23 15:58:36 2015 +0100 @@ -34,10 +34,15 @@ * Records whether the code being generated makes at least one foreign call. */ private boolean hasForeignCall; + /** + * Human readable name of this compilation unit. + */ + private final String compilationUnitName; - public LIRGenerationResultBase(LIR lir, FrameMapBuilder frameMapBuilder) { + public LIRGenerationResultBase(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder) { this.lir = lir; this.frameMapBuilder = frameMapBuilder; + this.compilationUnitName = compilationUnitName; } public LIR getLIR() { @@ -69,4 +74,8 @@ assert frameMap != null : "getFrameMap() can only be used after calling buildFrameMap()!"; return frameMap; } + + public String getCompilationUnitName() { + return compilationUnitName; + } } diff -r 59c2d62927f7 -r 422e60a2f4b9 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java Thu Mar 19 10:28:28 2015 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java Mon Mar 23 15:58:36 2015 +0100 @@ -136,12 +136,13 @@ } String[] groups = new String[names.size()]; Arrays.fill(groups, "Move Operations"); - - LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0])); - assert inst != null; - buffer.init(instructions); - buffer.append(1, inst); - buffer.finish(); + if (names.size() > 0) { // Don't pollute LIR when nothing has to be done + LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0])); + assert inst != null; + buffer.init(instructions); + buffer.append(1, inst); + buffer.finish(); + } } }