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 java.util.Enumeration;
016import java.util.Vector;
017import org.jikesrvm.VM;
018import org.jikesrvm.compilers.opt.InstrumentedEventCounterManager;
019import org.jikesrvm.compilers.opt.ir.Instruction;
020
021/**
022 * This class provides the basic functionality for instrumented data
023 * that use counters allocated from a InstrumentedEventCounterManager.
024 * It provides the basic interface to access counters,  forwarding
025 * those requests to the counter manager.
026 */
027public class ManagedCounterData {
028
029  /**
030   * @param counterManager The counterManager that will provide the counter space
031   */
032  ManagedCounterData(InstrumentedEventCounterManager counterManager) {
033    // Basic block instrumentation is performed using a common counter
034    // allocation for the whole method.  It requests that space here.
035    this.counterManager = counterManager;
036  }
037
038  /**
039   * This method must be called before creating any counters for this
040   * data.  It registers this data with the counter manager and gets a
041   * "handle" that is coded into the counter instruction.  If you need
042   * to change the number of counters in this data AFTER you have
043   * created counters, use void
044   * ManagerdCounterData.resizeCounters(int) instead.
045   *
046   * @param countersNeeded How many counters are needed by this data
047   */
048  public void initializeCounters(int countersNeeded) {
049    // Confirm that this method is called only once.  Once a handle is
050    // assigned, it should not be changed.  Use resizeCounters(int) to
051    // change the size of the data.
052    if (VM.VerifyAssertions) {
053      VM._assert(handle == -1);
054    }
055
056    this.numCounters = countersNeeded;
057    // Register  this many counters with the counter manager
058    this.handle = counterManager.registerCounterSpace(countersNeeded);
059  }
060
061  /**
062   * Tell the data to automatically expand the counters if there is a
063   * request to count an event that is greater than the current size.
064   *
065   * @param autoGrow Whether the counters should grow automatically.
066   */
067  public void automaticallyGrowCounters(boolean autoGrow) {
068
069    final int INITIAL_COUNTER_SIZE = 20;
070
071    automaticallyGrowCounters = autoGrow;
072    if (automaticallyGrowCounters) {
073      initializeCounters(INITIAL_COUNTER_SIZE);
074    }
075  }
076
077  /**
078   * Used to reset the number of counters for this data
079   *
080   * @param countersNeeded The number of counters needed
081   */
082  public void resizeCounters(int countersNeeded) {
083    // Confirm that counters have been initialized (using initializeCounters(int))
084    if (VM.VerifyAssertions) {
085      VM._assert(handle != -1);
086    }
087
088    counterManager.resizeCounterSpace(this.getHandle(), countersNeeded);
089    numCounters = countersNeeded;
090  }
091
092  /**
093   * Return the count for the given (relative) index
094   *
095   * @param counterNumber The event number within the data
096   * @return The count associated with this counter
097   */
098  public double getCounter(int counterNumber) {
099    // Confirm that counters have been initialized
100    //  (using initializeCounters(int))
101    if (VM.VerifyAssertions) {
102      VM._assert(handle != -1);
103    }
104    return counterManager.getCounter(this.getHandle(), counterNumber);
105  }
106
107  /**
108   * Set the count for the given index
109   *
110   * @param counterNumber The event number within the data
111   * @param value The new value of the counter
112   */
113  public void setCounter(int counterNumber, double value) {
114    // Confirm that counters have been initialized (using initializeCounters(int))
115    if (VM.VerifyAssertions) {
116      VM._assert(handle != -1);
117    }
118    if (counterNumber >= getNumCounters()) {
119      if (automaticallyGrowCounters) {
120        while (counterNumber >= getNumCounters()) {
121          resizeCounters(getNumCounters() * 2);
122        }
123      } else {
124        if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
125      }
126    }
127
128    counterManager.setCounter(this.getHandle(), counterNumber, value);
129  }
130
131  /**
132   * Return the number of counters currently allocated for this data
133   *
134   *  @return the number of counters
135   */
136  public int getNumCounters() {
137    // Confirm that counters have been initialized (using initializeCounters(int))
138    if (VM.VerifyAssertions) {
139      VM._assert(handle != -1);
140    }
141    return numCounters;
142  }
143
144  /**
145   * Counter Managers give id's that identify the counter space they
146   * have given to each data. This method returns that ID.
147   *
148   * @return The handle given to this data object by the counter manager.
149   **/
150  public int getHandle() {
151    return handle;
152  }
153
154  /**
155   * Return the counter manager for this data.
156   *
157   * @return the counter manager object
158   */
159  public InstrumentedEventCounterManager getCounterManager() {
160    return counterManager;
161  }
162
163  /**
164   * Create a place holder instruction to represent an increment of a
165   * particular counted event.  Simply forwards the request to the
166   * counter manager.
167   *
168   * @param counterNumber The number of the counter to increment
169   * @return The instruction that will update the given counter
170   */
171  public Instruction createEventCounterInstruction(int counterNumber) {
172    return createEventCounterInstruction(counterNumber, 1.0);
173  }
174
175  /**
176   * Create a place holder instruction to represent the counted event.
177   * Simply forwards the request to the counter manager.
178   *
179   * @param counterNumber The number of the counter to increment
180   * @param incrementValue The value to add to the given counter
181   * @return The instruction that will update the given counter
182   */
183  Instruction createEventCounterInstruction(int counterNumber, double incrementValue) {
184    // Confirm that counters have been initialized
185    if (VM.VerifyAssertions) {
186      VM._assert(handle != -1);
187    }
188
189    // If we automatically growing counters, see if we need to.
190    if (counterNumber >= numCounters) {
191      if (automaticallyGrowCounters) {
192        while (counterNumber >= numCounters) {
193          resizeCounters(getNumCounters() * 2);
194        }
195      } else {
196        // Should we put a warning here?? Not sure.
197      }
198    }
199    return getCounterManager().createEventCounterInstruction(getHandle(), counterNumber, incrementValue);
200  }
201
202  /**
203   *  This method prints the (sorted) nonzero elements a counter
204   *  array.
205   *
206   * @param f a function that gets the "name" for each counter
207   */
208  final void report(CounterNameFunction f) {
209    double sum = 0;
210    Vector<Counter> vec = new Vector<Counter>();
211
212    // set up a vector of non-zero counts
213    for (int i = 0; i < getNumCounters(); i++) {
214      double count = getCounter(i);
215      if (count > 0.0) {
216        sum += count;
217        String s = f.getName(i);
218        vec.add(new Counter(s, count));
219      }
220    }
221
222    // sort the vector in decreasing order
223    sort(vec);
224
225    // print
226    for (Enumeration<Counter> e = vec.elements(); e.hasMoreElements();) {
227      Counter c = e.nextElement();
228      String s = c.name;
229      double count = c.count;
230      double percent = (100 * count) / sum;
231      VM.sysWrite(count + "/" + sum + " = " + percent + "% " + s + "\n");
232    }
233  }
234
235  /**
236   * Sorts a {@code Vector<Counter>} by decreasing count.
237   * (code borrowed from InstructionSampler.java)
238   * <p>
239   * Shell sort
240   * <p>
241   * Reference: "The C Programming Language", Kernighan &amp; Ritchie, p. 116
242   *
243   * @param v the vector to sort
244   */
245  private void sort(Vector<?> v) {
246    int n = v.size();
247    for (int gap = n / 2; gap > 0; gap /= 2) {
248      for (int i = gap; i < n; ++i) {
249        for (int j = i - gap; j >= 0; j -= gap) {
250          double a = ((Counter) v.get(j)).count;
251          double b = ((Counter) v.get(j + gap)).count;
252          if (a >= b) break;
253          swap(v, j, j + gap);
254        }
255      }
256    }
257  }
258
259  // Interchange vec[i] with vec[j]
260  private <T> void swap(Vector<T> vec, int i, int j) {
261    T t = vec.get(i);
262    vec.set(i, vec.get(j));
263    vec.set(j, t);
264  }
265
266  /* -----   Implementation   ---- */
267
268  /**
269   * How many counters are needed by this data?
270   **/
271  protected int numCounters = 0;
272
273  /**
274   *  When a data object is registered with a counter manager, it is
275   *  given an id, which is stored here.
276   **/
277  protected int handle = -1;
278
279  /**
280   * Basic block instrumentation stores its counters using an
281   * abstracted counter allocation technique (a counterManager)
282   **/
283  protected InstrumentedEventCounterManager counterManager = null;
284
285  protected boolean automaticallyGrowCounters = false;
286
287  /**
288   * Auxiliary class
289   */
290  static final class Counter {
291    final String name;
292    final double count;
293
294    Counter(String s, double c) {
295      name = s;
296      count = c;
297    }
298  }
299
300}
301