1 /*
2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 
25 package org.graalvm.compiler.hotspot;
26 
27 import java.util.ArrayList;
28 
29 import org.graalvm.compiler.asm.Assembler;
30 import org.graalvm.compiler.asm.Assembler.InstructionCounter;
31 import org.graalvm.compiler.core.common.LIRKind;
32 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
33 import org.graalvm.compiler.lir.ConstantValue;
34 import org.graalvm.compiler.lir.LIR;
35 import org.graalvm.compiler.lir.LIRInsertionBuffer;
36 import org.graalvm.compiler.lir.LIRInstruction;
37 import org.graalvm.compiler.lir.LIRInstructionClass;
38 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
39 import org.graalvm.compiler.lir.StandardOp.LabelOp;
40 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
41 import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
42 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
43 import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
44 
45 import jdk.vm.ci.code.TargetDescription;
46 import jdk.vm.ci.meta.JavaConstant;
47 import jdk.vm.ci.meta.JavaKind;
48 import jdk.vm.ci.meta.Value;
49 
50 public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase {
51     public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER";
52     private final String[] instructionsToProfile;
53 
HotSpotInstructionProfiling(String instructionsToProfile)54     public HotSpotInstructionProfiling(String instructionsToProfile) {
55         this.instructionsToProfile = instructionsToProfile.split(",");
56     }
57 
58     @Override
run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context)59     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
60         new Analyzer(target, lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), context.diagnosticLirGenTool).run();
61     }
62 
63     private class Analyzer {
64         private final TargetDescription target;
65         private final LIR lir;
66         private final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
67         private final LIRInsertionBuffer buffer;
68         private final String compilationUnitName;
69 
Analyzer(TargetDescription target, String compilationUnitName, LIR lir, DiagnosticLIRGeneratorTool diagnosticLirGenTool)70         Analyzer(TargetDescription target, String compilationUnitName, LIR lir, DiagnosticLIRGeneratorTool diagnosticLirGenTool) {
71             this.target = target;
72             this.lir = lir;
73             this.compilationUnitName = compilationUnitName;
74             this.diagnosticLirGenTool = diagnosticLirGenTool;
75             this.buffer = new LIRInsertionBuffer();
76         }
77 
run()78         public void run() {
79             for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
80                 doBlock(block);
81             }
82         }
83 
doBlock(AbstractBlockBase<?> block)84         public void doBlock(AbstractBlockBase<?> block) {
85             ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
86             assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
87             assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
88             assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
89             assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
90             assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
91             String[] names = new String[instructionsToProfile.length];
92             String[] groups = new String[instructionsToProfile.length];
93             Value[] increments = new Value[instructionsToProfile.length];
94             for (int i = 0; i < instructionsToProfile.length; i++) {
95                 names[i] = compilationUnitName;
96                 groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i];
97                 // Default is zero; this value is patched to the real instruction count after
98                 // assembly in method HotSpotInstructionProfiling.countInstructions
99                 increments[i] = new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.INT_0);
100             }
101             HotSpotCounterOp op = (HotSpotCounterOp) diagnosticLirGenTool.createMultiBenchmarkCounter(names, groups, increments);
102             LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile);
103             assert inst != null;
104             buffer.init(instructions);
105             buffer.append(1, inst);
106             buffer.finish();
107         }
108     }
109 
110     /**
111      * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)}
112      * calls this method for patching the instruction counts into the counter increment code.
113      */
countInstructions(LIR lir, Assembler asm)114     public static void countInstructions(LIR lir, Assembler asm) {
115         InstructionCounterOp lastOp = null;
116         InstructionCounter counter = asm.getInstructionCounter();
117         for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
118             if (block == null) {
119                 continue;
120             }
121             for (LIRInstruction inst : lir.getLIRforBlock(block)) {
122                 if (inst instanceof InstructionCounterOp) {
123                     InstructionCounterOp currentOp = (InstructionCounterOp) inst;
124 
125                     if (lastOp != null) {
126                         int beginPc = lastOp.countOffsetEnd;
127                         int endPc = currentOp.countOffsetBegin;
128                         int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
129                         lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
130                     }
131                     lastOp = ((InstructionCounterOp) inst);
132                 }
133             }
134         }
135         if (lastOp != null) {
136             assert lastOp.countOffsetBegin < asm.position();
137             int beginPc = lastOp.countOffsetBegin;
138             int endPc = asm.position();
139             int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
140             lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
141         }
142     }
143 
144     public static class InstructionCounterOp extends LIRInstruction {
145         public static final LIRInstructionClass<InstructionCounterOp> TYPE = LIRInstructionClass.create(InstructionCounterOp.class);
146         private final HotSpotCounterOp delegate;
147         private final String[] instructionsToProfile;
148         private int countOffsetBegin;
149         private int countOffsetEnd;
150 
151         public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) {
152             super(TYPE);
153             this.delegate = delegate;
154             this.instructionsToProfile = instructionsToProfile;
155         }
156 
157         @Override
158         public void emitCode(CompilationResultBuilder crb) {
159             countOffsetBegin = crb.asm.position();
160             this.delegate.emitCode(crb);
161             countOffsetEnd = crb.asm.position();
162         }
163 
164         public String[] getInstructionsToProfile() {
165             return instructionsToProfile;
166         }
167     }
168 }
169