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