1 /*
   2  * Copyright (c) 2015, 2016, 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.lir.profiling;
  24 
  25 import java.util.ArrayList;
  26 import java.util.List;
  27 
  28 import org.graalvm.compiler.core.common.LIRKind;
  29 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  30 import org.graalvm.compiler.core.common.cfg.BlockMap;
  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.gen.DiagnosticLIRGeneratorTool;
  36 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  37 import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
  38 import org.graalvm.compiler.lir.profiling.MoveProfiler.MoveStatistics;
  39 import org.graalvm.compiler.options.Option;
  40 import org.graalvm.compiler.options.OptionKey;
  41 import org.graalvm.compiler.options.OptionType;
  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 /**
  49  * Inserts counters into the {@link LIR} code to the number of move instruction dynamically
  50  * executed.
  51  */
  52 public class MoveProfilingPhase extends PostAllocationOptimizationPhase {
  53 
  54     public static class Options {
  55         // @formatter:off
  56         @Option(help = "Enable dynamic move profiling per method.", type = OptionType.Debug)
  57         public static final OptionKey<Boolean> LIRDynMoveProfileMethod = new OptionKey<>(false);
  58         // @formatter:on
  59     }
  60 
  61     private static final String MOVE_OPERATIONS = "MoveOperations";
  62 
  63     @Override
  64     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
  65         new Analyzer(target, lirGenRes, context.diagnosticLirGenTool).run();
  66     }
  67 
  68     static class Analyzer {
  69         private final TargetDescription target;
  70         private final LIRGenerationResult lirGenRes;
  71         private final DiagnosticLIRGeneratorTool diagnosticLirGenTool;
  72         private final LIRInsertionBuffer buffer;
  73         private String cachedGroupName;
  74         private final List<String> names;
  75         private final List<String> groups;
  76         private final List<Value> increments;
  77 
  78         Analyzer(TargetDescription target, LIRGenerationResult lirGenRes, DiagnosticLIRGeneratorTool diagnosticLirGenTool) {
  79             this.target = target;
  80             this.lirGenRes = lirGenRes;
  81             this.diagnosticLirGenTool = diagnosticLirGenTool;
  82             this.buffer = new LIRInsertionBuffer();
  83             this.names = new ArrayList<>();
  84             this.groups = new ArrayList<>();
  85             this.increments = new ArrayList<>();
  86         }
  87 
  88         public void run() {
  89             LIR lir = lirGenRes.getLIR();
  90             BlockMap<MoveStatistics> collected = MoveProfiler.profile(lir);
  91             for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
  92                 MoveStatistics moveStatistics = collected.get(block);
  93                 if (moveStatistics != null) {
  94                     names.clear();
  95                     groups.clear();
  96                     increments.clear();
  97                     doBlock(block, moveStatistics);
  98                 }
  99             }
 100         }
 101 
 102         public void doBlock(AbstractBlockBase<?> block, MoveStatistics moveStatistics) {
 103             // counter insertion phase
 104             for (MoveType type : MoveType.values()) {
 105                 String name = type.toString();
 106                 // current run
 107                 addEntry(name, getGroupName(), moveStatistics.get(type));
 108             }
 109             insertBenchmarkCounter(block);
 110         }
 111 
 112         protected final void addEntry(String name, String groupName, int count) {
 113             if (count > 0) {
 114                 names.add(name);
 115                 groups.add(groupName);
 116                 increments.add(new ConstantValue(LIRKind.fromJavaKind(target.arch, JavaKind.Int), JavaConstant.forInt(count)));
 117             }
 118         }
 119 
 120         protected final void insertBenchmarkCounter(AbstractBlockBase<?> block) {
 121             int size = names.size();
 122             if (size > 0) { // Don't pollute LIR when nothing has to be done
 123                 assert size > 0 && size == groups.size() && size == increments.size();
 124                 ArrayList<LIRInstruction> instructions = lirGenRes.getLIR().getLIRforBlock(block);
 125                 LIRInstruction inst = diagnosticLirGenTool.createMultiBenchmarkCounter(names.toArray(new String[size]), groups.toArray(new String[size]),
 126                                 increments.toArray(new Value[size]));
 127                 assert inst != null;
 128                 buffer.init(instructions);
 129                 buffer.append(1, inst);
 130                 buffer.finish();
 131             }
 132         }
 133 
 134         protected final String getGroupName() {
 135             if (cachedGroupName == null) {
 136                 cachedGroupName = createGroupName();
 137             }
 138             return cachedGroupName;
 139         }
 140 
 141         protected String createGroupName() {
 142             if (Options.LIRDynMoveProfileMethod.getValue(lirGenRes.getLIR().getOptions())) {
 143                 return new StringBuilder('"').append(MOVE_OPERATIONS).append(':').append(lirGenRes.getCompilationUnitName()).append('"').toString();
 144             }
 145             return MOVE_OPERATIONS;
 146         }
 147     }
 148 
 149 }