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