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