1 /*
   2  * Copyright (c) 2015, 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 package org.graalvm.compiler.hotspot;
  24 
  25 import java.util.List;
  26 
  27 import org.graalvm.compiler.asm.Assembler;
  28 import org.graalvm.compiler.asm.Assembler.InstructionCounter;
  29 import org.graalvm.compiler.core.common.LIRKind;
  30 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  31 import org.graalvm.compiler.lir.ConstantValue;
  32 import org.graalvm.compiler.lir.LIR;
  33 import org.graalvm.compiler.lir.LIRInsertionBuffer;
  34 import org.graalvm.compiler.lir.LIRInstruction;
  35 import org.graalvm.compiler.lir.LIRInstructionClass;
  36 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
  37 import org.graalvm.compiler.lir.StandardOp.LabelOp;
  38 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  39 import org.graalvm.compiler.lir.gen.DiagnosticLIRGeneratorTool;
  40 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  41 import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
  42 
  43 import jdk.vm.ci.code.TargetDescription;
  44 import jdk.vm.ci.meta.JavaConstant;
  45 import jdk.vm.ci.meta.JavaKind;
  46 import jdk.vm.ci.meta.Value;
  47 
  48 public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase {
  49     public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER";
  50     private final String[] instructionsToProfile;
  51 
  52     public HotSpotInstructionProfiling(String instructionsToProfile) {
  53         this.instructionsToProfile = instructionsToProfile.split(",");
  54     }
  55 
  56     @Override
  57     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
  58         new Analyzer(target, lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), context.diagnosticLirGenTool).run();
  59     }
  60 
  61     private class Analyzer {
  62         private final TargetDescription target;
  63         private final LIR lir;
  64         private final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
  65         private final LIRInsertionBuffer buffer;
  66         private final String compilationUnitName;
  67 
  68         Analyzer(TargetDescription target, String compilationUnitName, LIR lir, DiagnosticLIRGeneratorTool diagnosticLirGenTool) {
  69             this.target = target;
  70             this.lir = lir;
  71             this.compilationUnitName = compilationUnitName;
  72             this.diagnosticLirGenTool = diagnosticLirGenTool;
  73             this.buffer = new LIRInsertionBuffer();
  74         }
  75 
  76         public void run() {
  77             for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
  78                 doBlock(block);
  79             }
  80         }
  81 
  82         public void doBlock(AbstractBlockBase<?> block) {
  83             List<LIRInstruction> instructions = lir.getLIRforBlock(block);
  84             assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
  85             assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
  86             assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
  87             assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
  88             assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
  89             String[] names = new String[instructionsToProfile.length];
  90             String[] groups = new String[instructionsToProfile.length];
  91             Value[] increments = new Value[instructionsToProfile.length];
  92             for (int i = 0; i < instructionsToProfile.length; i++) {
  93                 names[i] = compilationUnitName;
  94                 groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i];
  95                 // Default is zero; this value is patched to the real instruction count after
  96                 // assembly in method HotSpotInstructionProfiling.countInstructions
  97                 increments[i] = new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.INT_0);
  98             }
  99             HotSpotCounterOp op = (HotSpotCounterOp) diagnosticLirGenTool.createMultiBenchmarkCounter(names, groups, increments);
 100             LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile);
 101             assert inst != null;
 102             buffer.init(instructions);
 103             buffer.append(1, inst);
 104             buffer.finish();
 105         }
 106     }
 107 
 108     /**
 109      * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)}
 110      * calls this method for patching the instruction counts into the counter increment code.
 111      */
 112     public static void countInstructions(LIR lir, Assembler asm) {
 113         InstructionCounterOp lastOp = null;
 114         InstructionCounter counter = asm.getInstructionCounter();
 115         for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
 116             if (block == null) {
 117                 continue;
 118             }
 119             for (LIRInstruction inst : lir.getLIRforBlock(block)) {
 120                 if (inst instanceof InstructionCounterOp) {
 121                     InstructionCounterOp currentOp = (InstructionCounterOp) inst;
 122 
 123                     if (lastOp != null) {
 124                         int beginPc = lastOp.countOffsetEnd;
 125                         int endPc = currentOp.countOffsetBegin;
 126                         int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
 127                         lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
 128                     }
 129                     lastOp = ((InstructionCounterOp) inst);
 130                 }
 131             }
 132         }
 133         if (lastOp != null) {
 134             assert lastOp.countOffsetBegin < asm.position();
 135             int beginPc = lastOp.countOffsetBegin;
 136             int endPc = asm.position();
 137             int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
 138             lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
 139         }
 140     }
 141 
 142     public static class InstructionCounterOp extends LIRInstruction {
 143         public static final LIRInstructionClass<InstructionCounterOp> TYPE = LIRInstructionClass.create(InstructionCounterOp.class);
 144         private final HotSpotCounterOp delegate;
 145         private final String[] instructionsToProfile;
 146         private int countOffsetBegin;
 147         private int countOffsetEnd;
 148 
 149         public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) {
 150             super(TYPE);
 151             this.delegate = delegate;
 152             this.instructionsToProfile = instructionsToProfile;
 153         }
 154 
 155         @Override
 156         public void emitCode(CompilationResultBuilder crb) {
 157             countOffsetBegin = crb.asm.position();
 158             this.delegate.emitCode(crb);
 159             countOffsetEnd = crb.asm.position();
 160         }
 161 
 162         public String[] getInstructionsToProfile() {
 163             return instructionsToProfile;
 164         }
 165     }
 166 }