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