/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.adaptive.measurements.instrumentation; import org.jikesrvm.VM; import org.jikesrvm.adaptive.VM_AosEntrypoints; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.OPT_Constants; import org.jikesrvm.compilers.opt.OPT_ConvertToLowLevelIR; import org.jikesrvm.compilers.opt.OPT_InstrumentedEventCounterManager; import org.jikesrvm.compilers.opt.ir.ALoad; import org.jikesrvm.compilers.opt.ir.AStore; import org.jikesrvm.compilers.opt.ir.InstrumentedCounter; import org.jikesrvm.compilers.opt.ir.OPT_DoubleConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_IR; import org.jikesrvm.compilers.opt.ir.OPT_IRTools; import org.jikesrvm.compilers.opt.ir.OPT_Instruction; import org.jikesrvm.compilers.opt.ir.OPT_IntConstantOperand; import org.jikesrvm.compilers.opt.ir.OPT_Operand; import org.jikesrvm.compilers.opt.ir.OPT_Operator; import org.jikesrvm.compilers.opt.ir.OPT_Operators; import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand; import org.vmmagic.unboxed.Offset; /** * An implementation of a OPT_InstrumentedEventCounterManager . It * uses an unsynchronized two dimensional array of doubles to allocate * its counters. (see OPT_InstrumentedEventCounterManager.java for a * description of a counter manager) * * NOTE: Much of this class was stolen from VM_CounterArray.java, which * is now gone. */ public final class VM_CounterArrayManager extends OPT_InstrumentedEventCounterManager implements OPT_Operators, OPT_Constants { static final boolean DEBUG = false; /** * This method is called my a VM_ManagedData object to obtain space * in the counter manager. A handle or "ID" is returned for the * data to identify its counter space. * * @param countersNeeded The number of counters being requested * @return The handle for this data's counter space. **/ public synchronized int registerCounterSpace(int countersNeeded) { if (counterArrays.length == numCounterArrays) { expandCounterArrays(); } // return the handle of the next available counter array int handle = numCounterArrays; // resize the appropriate counter array resizeCounterSpace(handle, countersNeeded); numCounterArrays++; return handle; } /** * This method is called to change the number of counters needed by * a particular data. * * @param handle The handle describing which the data to be resized * @param countersNeeded The number of counters being requested **/ public synchronized void resizeCounterSpace(int handle, int countersNeeded) { // allocate the new array double[] temp = new double[countersNeeded]; // transfer the old data to the new array if (counterArrays[handle] != null) { for (int i = 0; i < counterArrays[handle].length; i++) { temp[i] = counterArrays[handle][i]; } } // switch to the new counter array counterArrays[handle] = temp; } /** * Return the value of a particular counter * * @param handle The handle describing which the data to look in * @param index The relative index number of the counter * @return The value of the counter */ public double getCounter(int handle, int index) { return counterArrays[handle][index]; } /** * Set the value of a particular counter * * @param handle The handle describing which the data to look in * @param index The relative index number of the counter * @param value The new value of the counter */ public void setCounter(int handle, int index, double value) { counterArrays[handle][index] = value; } /** * Create a place holder instruction to represent the counted event. * * @param handle The handle of the array for the method * @param index Index within that array * @param incrementValue The value to add to the counter * @return The counter instruction **/ public OPT_Instruction createEventCounterInstruction(int handle, int index, double incrementValue) { // Now create the instruction to be returned. OPT_Instruction c = InstrumentedCounter.create(INSTRUMENTED_EVENT_COUNTER, new OPT_IntConstantOperand(handle), new OPT_IntConstantOperand(index), new OPT_DoubleConstantOperand(incrementValue, Offset.zero())); c.bcIndex = INSTRUMENTATION_BCI; return c; } /** * Take an event counter instruction and mutate it into IR * instructions that will do the actual counting. * * Precondition: IR is in LIR * * @param counterInst The counter instruction to mutate * @param ir The governing IR **/ public void mutateOptEventCounterInstruction(OPT_Instruction counterInst, OPT_IR ir) { if (VM.VerifyAssertions) { VM._assert(InstrumentedCounter.conforms(counterInst)); } OPT_IntConstantOperand intOp = InstrumentedCounter.getData(counterInst); int handle = intOp.value; intOp = InstrumentedCounter.getIndex(counterInst); int index = intOp.value; // Get the base of array OPT_RegisterOperand counterArray = OPT_ConvertToLowLevelIR. getStatic(counterInst, ir, VM_AosEntrypoints.counterArrayManagerCounterArraysField); // load counterArrays[handle] OPT_RegisterOperand array2 = InsertALoadOffset(counterInst, ir, REF_ALOAD, VM_TypeReference.JavaLangObject, counterArray, handle); OPT_ConvertToLowLevelIR. doArrayLoad(counterInst.prevInstructionInCodeOrder(), ir, INT_LOAD, 2); // load counterArrays[handle][index] OPT_RegisterOperand origVal = InsertALoadOffset(counterInst, ir, DOUBLE_ALOAD, VM_TypeReference.Double, array2, index); OPT_ConvertToLowLevelIR. doArrayLoad(counterInst.prevInstructionInCodeOrder(), ir, DOUBLE_LOAD, 3); OPT_Operand incOperand = InstrumentedCounter.getIncrement(counterInst); // Insert increment instruction OPT_RegisterOperand newValue = OPT_ConvertToLowLevelIR.InsertBinary(counterInst, ir, DOUBLE_ADD, VM_TypeReference.Double, origVal, incOperand.copy()); // Store it OPT_Instruction store = AStore.mutate(counterInst, DOUBLE_ASTORE, newValue, array2.copyU2D(), OPT_IRTools.IC(index), null, null); OPT_ConvertToLowLevelIR.doArrayStore(store, ir, DOUBLE_STORE, 3); } /** * Insert array load off before s in the instruction stream. * @param s the instruction to insert before * @param ir the containing IR * @param operator the operator to insert * @param type the type of the result * @param reg2 the base to load from * @param offset the offset to load at * @return the result operand of the inserted instruction */ static OPT_RegisterOperand InsertALoadOffset(OPT_Instruction s, OPT_IR ir, OPT_Operator operator, VM_TypeReference type, OPT_Operand reg2, int offset) { OPT_RegisterOperand regTarget = ir.regpool.makeTemp(type); OPT_Instruction s2 = ALoad.create(operator, regTarget, reg2, OPT_IRTools.IC(offset), null, null); s.insertBefore(s2); return regTarget.copyD2U(); } /** * Still under construction. */ public void insertBaselineCounter() { } /** * decay counters * * @param handle The identifier of the counter array to decay * @param rate The rate at which to decay, i.e. a value of 2 will divide * all values in half */ static void decay(int handle, double rate) { int len = counterArrays[handle].length; for (int i = 0; i < len; i++) { counterArrays[handle][i] /= rate; } } /** Implementation */ static final int INITIAL_COUNT = 10; static final int INCREMENT = 10; static int numCounterArrays = 0; static double[][] counterArrays = new double[INITIAL_COUNT][]; /** * increment the number of counter arrays */ private static void expandCounterArrays() { // expand the number of counter arrays double[][] temp = new double[counterArrays.length * 2][]; // transfer the old counter arrays to the new storage for (int i = 0; i < counterArrays.length; i++) { temp[i] = counterArrays[i]; } counterArrays = temp; } } // end of class