001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.adaptive.recompilation.instrumentation;
014
015 import java.util.ArrayList;
016 import org.jikesrvm.adaptive.controller.Controller;
017 import org.jikesrvm.adaptive.database.AOSDatabase;
018 import org.jikesrvm.adaptive.measurements.instrumentation.Instrumentation;
019 import org.jikesrvm.adaptive.measurements.instrumentation.StringEventCounterData;
020 import org.jikesrvm.compilers.opt.OptOptions;
021 import org.jikesrvm.compilers.opt.driver.CompilerPhase;
022 import org.jikesrvm.compilers.opt.ir.BasicBlock;
023 import org.jikesrvm.compilers.opt.ir.BasicBlockEnumeration;
024 import org.jikesrvm.compilers.opt.ir.IR;
025 import org.jikesrvm.compilers.opt.ir.Instruction;
026 import static org.jikesrvm.compilers.opt.ir.Operators.LABEL;
027 import static org.jikesrvm.compilers.opt.ir.Operators.RETURN;
028 import org.jikesrvm.compilers.opt.ir.Prologue;
029
030 /**
031 * The following OPT phase inserts counters on all instructions in the
032 * IR. It maintians one counter for each operand type, so it output
033 * how many loads were executed, how many int_add's etc. This is
034 * useful for debugging and assessing the accuracy of optimizations.
035 *
036 * Note: The counters are added at the end of HIR, so the counts will
037 * NOT reflect any changes to the code that occur after HIR.
038 */
039 public class InsertInstructionCounters extends CompilerPhase {
040
041 /**
042 * Return this instance of this phase. This phase contains no
043 * per-compilation instance fields.
044 * @param ir not used
045 * @return this
046 */
047 public CompilerPhase newExecution(IR ir) {
048 return this;
049 }
050
051 public final boolean shouldPerform(OptOptions options) {
052 return Controller.options.INSERT_INSTRUCTION_COUNTERS;
053 }
054
055 public final String getName() { return "InsertInstructionCounters"; }
056
057 /**
058 * Insert a counter on every instruction, and group counts by
059 * opcode type.
060 *
061 * @param ir the governing IR
062 */
063 public final void perform(IR ir) {
064
065 // Don't insert counters in uninterruptible methods,
066 // the boot image, or when instrumentation is disabled
067 if (!ir.method.isInterruptible() ||
068 ir.method.getDeclaringClass().isInBootImage() ||
069 !Instrumentation.instrumentationEnabled()) {
070 return;
071 }
072
073 // Get the data object that handles the counters
074 StringEventCounterData data = AOSDatabase.instructionCounterData;
075
076 // Create a vector of basic blocks up front because the blocks
077 // are modified as we iterate below.
078 ArrayList<BasicBlock> bbList = new ArrayList<BasicBlock>();
079 for (BasicBlockEnumeration bbe = ir.getBasicBlocks(); bbe.hasMoreElements();) {
080 BasicBlock bb = bbe.next();
081 bbList.add(bb);
082 }
083
084 // Iterate through the basic blocks
085 for (BasicBlock bb : bbList) {
086 // Add instructions to vector so enumeration doesn't mess
087 // things up. There is probably a better way to do this, but
088 // it doesn't matter because this is a debugging phase.
089 ArrayList<Instruction> iList = new ArrayList<Instruction>();
090 Instruction inst = bb.firstInstruction();
091 while (inst != null && inst != bb.lastInstruction()) {
092 iList.add(inst);
093 inst = inst.nextInstructionInCodeOrder();
094 }
095
096 // Iterate through all the instructions in this block.
097 for (Instruction i : iList) {
098
099 // Skip dangerous instructions
100 if (i.operator() == LABEL || Prologue.conforms(i)) {
101 continue;
102 }
103
104 if (i.isBranch() || i.operator() == RETURN) {
105
106 // It's a branch, so you need to be careful how you insert the
107 // counter.
108 Instruction prev = i.prevInstructionInCodeOrder();
109
110 // If the instruction above this branch is also a branch,
111 // then we can't instrument as-is because a basic block
112 // must end with branches only. Solve by splitting block.
113 if (prev.isBranch()) {
114 // BasicBlock newBlock =
115 bb.splitNodeWithLinksAt(prev, ir);
116 bb.recomputeNormalOut(ir);
117 }
118
119 // Use the name of the operator as the name of the event
120 Instruction counterInst = data.
121 getCounterInstructionForEvent(i.operator().toString());
122
123 // Insert the new instruction into the code order
124 i.insertBefore(counterInst);
125 } else {
126 // It's a non-branching instruction. Insert counter before
127 // the instruction.
128
129 // Use the name of the operator as the name of the event
130 Instruction counterInst = data.
131 getCounterInstructionForEvent(i.operator().toString());
132
133 i.insertBefore(counterInst);
134 }
135 }
136 }
137 }
138 }