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 */ 013package org.jikesrvm.adaptive.measurements.instrumentation; 014 015import static org.jikesrvm.compilers.opt.driver.OptConstants.INSTRUMENTATION_BCI; 016import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ADD; 017import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ALOAD; 018import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_ASTORE; 019import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_LOAD; 020import static org.jikesrvm.compilers.opt.ir.Operators.DOUBLE_STORE; 021import static org.jikesrvm.compilers.opt.ir.Operators.INSTRUMENTED_EVENT_COUNTER; 022import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD; 023import static org.jikesrvm.compilers.opt.ir.Operators.REF_ALOAD; 024 025import org.jikesrvm.VM; 026import org.jikesrvm.adaptive.AosEntrypoints; 027import org.jikesrvm.classloader.TypeReference; 028import org.jikesrvm.compilers.opt.InstrumentedEventCounterManager; 029import org.jikesrvm.compilers.opt.hir2lir.ConvertToLowLevelIR; 030import org.jikesrvm.compilers.opt.ir.ALoad; 031import org.jikesrvm.compilers.opt.ir.AStore; 032import org.jikesrvm.compilers.opt.ir.IR; 033import org.jikesrvm.compilers.opt.ir.IRTools; 034import org.jikesrvm.compilers.opt.ir.Instruction; 035import org.jikesrvm.compilers.opt.ir.InstrumentedCounter; 036import org.jikesrvm.compilers.opt.ir.Operator; 037import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand; 038import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 039import org.jikesrvm.compilers.opt.ir.operand.Operand; 040import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 041import org.vmmagic.unboxed.Offset; 042 043import static org.jikesrvm.compilers.opt.ir.Operators.*; 044import static org.jikesrvm.compilers.opt.driver.OptConstants.*; 045 046/** 047 * An implementation of a InstrumentedEventCounterManager . It 048 * uses an unsynchronized two dimensional array of doubles to allocate 049 * its counters. (see InstrumentedEventCounterManager.java for a 050 * description of a counter manager) 051 * <p> 052 * NOTE: Much of this class was stolen from CounterArray.java, which 053 * is now gone. 054 */ 055public final class CounterArrayManager extends InstrumentedEventCounterManager { 056 057 static final boolean DEBUG = false; 058 059 /** 060 * This method is called by a {@link ManagedCounterData} object to obtain space 061 * in the counter manager. A handle or "ID" is returned for the 062 * data to identify its counter space. 063 * 064 * @param countersNeeded The number of counters being requested 065 * @return The handle for this data's counter space. 066 **/ 067 @Override 068 public synchronized int registerCounterSpace(int countersNeeded) { 069 if (counterArrays.length == numCounterArrays) { 070 expandCounterArrays(); 071 } 072 073 // return the handle of the next available counter array 074 int handle = numCounterArrays; 075 076 // resize the appropriate counter array 077 resizeCounterSpace(handle, countersNeeded); 078 079 numCounterArrays++; 080 081 return handle; 082 } 083 084 @Override 085 public synchronized void resizeCounterSpace(int handle, int countersNeeded) { 086 // allocate the new array 087 double[] temp = new double[countersNeeded]; 088 089 // transfer the old data to the new array 090 if (counterArrays[handle] != null) { 091 for (int i = 0; i < counterArrays[handle].length; i++) { 092 temp[i] = counterArrays[handle][i]; 093 } 094 } 095 096 // switch to the new counter array 097 counterArrays[handle] = temp; 098 } 099 100 @Override 101 public double getCounter(int handle, int index) { 102 return counterArrays[handle][index]; 103 } 104 105 @Override 106 public void setCounter(int handle, int index, double value) { 107 counterArrays[handle][index] = value; 108 } 109 110 /** 111 * Create a place holder instruction to represent the counted event. 112 * 113 * @param handle The handle of the array for the method 114 * @param index Index within that array 115 * @param incrementValue The value to add to the counter 116 * @return The counter instruction 117 **/ 118 @Override 119 public Instruction createEventCounterInstruction(int handle, int index, double incrementValue) { 120 // Now create the instruction to be returned. 121 Instruction c = 122 InstrumentedCounter.create(INSTRUMENTED_EVENT_COUNTER, 123 new IntConstantOperand(handle), 124 new IntConstantOperand(index), 125 new DoubleConstantOperand(incrementValue, Offset.zero())); 126 c.bcIndex = INSTRUMENTATION_BCI; 127 128 return c; 129 } 130 131 /** 132 * Take an event counter instruction and mutate it into IR 133 * instructions that will do the actual counting. 134 * 135 * Precondition: IR is in LIR 136 * 137 * @param counterInst The counter instruction to mutate 138 * @param ir The governing IR 139 **/ 140 @Override 141 public void mutateOptEventCounterInstruction(Instruction counterInst, IR ir) { 142 if (VM.VerifyAssertions) { 143 VM._assert(InstrumentedCounter.conforms(counterInst)); 144 } 145 146 IntConstantOperand intOp = InstrumentedCounter.getData(counterInst); 147 int handle = intOp.value; 148 intOp = InstrumentedCounter.getIndex(counterInst); 149 int index = intOp.value; 150 151 // Get the base of array 152 RegisterOperand counterArray = ConvertToLowLevelIR. 153 getStatic(counterInst, ir, AosEntrypoints.counterArrayManagerCounterArraysField); 154 155 // load counterArrays[handle] 156 RegisterOperand array2 = 157 InsertALoadOffset(counterInst, ir, REF_ALOAD, TypeReference.JavaLangObject, counterArray, handle); 158 ConvertToLowLevelIR. 159 doArrayLoad(counterInst.prevInstructionInCodeOrder(), ir, INT_LOAD, 2); 160 161 // load counterArrays[handle][index] 162 RegisterOperand origVal = 163 InsertALoadOffset(counterInst, ir, DOUBLE_ALOAD, TypeReference.Double, array2, index); 164 ConvertToLowLevelIR. 165 doArrayLoad(counterInst.prevInstructionInCodeOrder(), ir, DOUBLE_LOAD, 3); 166 167 Operand incOperand = InstrumentedCounter.getIncrement(counterInst); 168 // Insert increment instruction 169 RegisterOperand newValue = 170 ConvertToLowLevelIR.insertBinary(counterInst, 171 ir, 172 DOUBLE_ADD, 173 TypeReference.Double, 174 origVal, 175 incOperand.copy()); 176 177 // Store it 178 Instruction store = 179 AStore.mutate(counterInst, DOUBLE_ASTORE, newValue, array2.copyU2D(), IRTools.IC(index), null, null); 180 ConvertToLowLevelIR.doArrayStore(store, ir, DOUBLE_STORE, 3); 181 182 } 183 184 /** 185 * Insert array load off before s in the instruction stream. 186 * @param s the instruction to insert before 187 * @param ir the containing IR 188 * @param operator the operator to insert 189 * @param type the type of the result 190 * @param reg2 the base to load from 191 * @param offset the offset to load at 192 * @return the result operand of the inserted instruction 193 */ 194 static RegisterOperand InsertALoadOffset(Instruction s, IR ir, Operator operator, 195 TypeReference type, Operand reg2, int offset) { 196 RegisterOperand regTarget = ir.regpool.makeTemp(type); 197 Instruction s2 = ALoad.create(operator, regTarget, reg2, IRTools.IC(offset), null, null); 198 s.insertBefore(s2); 199 return regTarget.copyD2U(); 200 } 201 202 /** 203 * Still under construction. 204 */ 205 @Override 206 public void insertBaselineCounter() { 207 } 208 209 /** 210 * decay counters 211 * 212 * @param handle The identifier of the counter array to decay 213 * @param rate The rate at which to decay, i.e. a value of 2 will divide 214 * all values in half 215 */ 216 static void decay(int handle, double rate) { 217 int len = counterArrays[handle].length; 218 for (int i = 0; i < len; i++) { 219 counterArrays[handle][i] /= rate; 220 } 221 } 222 223 /** Implementation */ 224 static final int INITIAL_COUNT = 10; 225 static final int INCREMENT = 10; 226 static int numCounterArrays = 0; 227 static double[][] counterArrays = new double[INITIAL_COUNT][]; 228 229 /** 230 * increment the number of counter arrays 231 */ 232 private static void expandCounterArrays() { 233 // expand the number of counter arrays 234 double[][] temp = new double[counterArrays.length * 2][]; 235 236 // transfer the old counter arrays to the new storage 237 for (int i = 0; i < counterArrays.length; i++) { 238 temp[i] = counterArrays[i]; 239 } 240 counterArrays = temp; 241 } 242 243} // end of class 244 245 246