/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * 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/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.adaptive.measurements.instrumentation; import java.util.Enumeration; import java.util.Vector; import org.jikesrvm.VM; import org.jikesrvm.compilers.opt.InstrumentedEventCounterManager; import org.jikesrvm.compilers.opt.ir.Instruction; /** * This class provides the basic functionality for instrumented data * that use counters allocated from a InstrumentedEventCounterManager. * It provides the basic interface to access counters, forwarding * those requests to the counter manager. */ public class ManagedCounterData { /** * @param counterManager The counterManager that will provide the counter space */ ManagedCounterData(InstrumentedEventCounterManager counterManager) { // Basic block instrumentation is performed using a common counter // allocation for the whole method. It requests that space here. this.counterManager = counterManager; } /** * This method must be called before creating any counters for this * data. It registers this data with the counter manager and gets a * "handle" that is coded into the counter instruction. If you need * to change the number of counters in this data AFTER you have * created counters, use void * ManagerdCounterData.resizeCounters(int) instead. * * @param countersNeeded How many counters are needed by this data */ public void initializeCounters(int countersNeeded) { // Confirm that this method is called only once. Once a handle is // assigned, it should not be changed. Use resizeCounters(int) to // change the size of the data. if (VM.VerifyAssertions) { VM._assert(handle == -1); } this.numCounters = countersNeeded; // Register this many counters with the counter manager this.handle = counterManager.registerCounterSpace(countersNeeded); } /** * Tell the data to automatically expand the counters if there is a * request to count an event that is greater than the current size. * * @param autoGrow Whether the counters should grow automatically. */ public void automaticallyGrowCounters(boolean autoGrow) { final int INITIAL_COUNTER_SIZE = 20; automaticallyGrowCounters = autoGrow; if (automaticallyGrowCounters) { initializeCounters(INITIAL_COUNTER_SIZE); } } /** * Used to reset the number of counters for this data * * @param countersNeeded The number of counters needed */ public void resizeCounters(int countersNeeded) { // Confirm that counters have been initialized (using initializeCounters(int)) if (VM.VerifyAssertions) { VM._assert(handle != -1); } counterManager.resizeCounterSpace(this.getHandle(), countersNeeded); numCounters = countersNeeded; } /** * Return the count for the given (relative) index * * @param counterNumber The event number within the data * @return The count associated with this counter */ public double getCounter(int counterNumber) { // Confirm that counters have been initialized // (using initializeCounters(int)) if (VM.VerifyAssertions) { VM._assert(handle != -1); } return counterManager.getCounter(this.getHandle(), counterNumber); } /** * Set the count for the given index * * @param counterNumber The event number within the data * @param value The new value of the counter */ public void setCounter(int counterNumber, double value) { // Confirm that counters have been initialized (using initializeCounters(int)) if (VM.VerifyAssertions) { VM._assert(handle != -1); } if (counterNumber >= getNumCounters()) { if (automaticallyGrowCounters) { while (counterNumber >= getNumCounters()) { resizeCounters(getNumCounters() * 2); } } else { VM._assert(false); } } counterManager.setCounter(this.getHandle(), counterNumber, value); } /** * Return the number of counters currently allocated for this data * * @return the number of counters */ public int getNumCounters() { // Confirm that counters have been initialized (using initializeCounters(int)) if (VM.VerifyAssertions) { VM._assert(handle != -1); } return numCounters; } /** * Counter Managers give id's that identify the counter space they * have given to each data. This method returns that ID. * * @return The handle given to this data object by the counter manager. **/ public int getHandle() { return handle; } /** * Return the counter manager for this data. * * @return the counter manager object */ public InstrumentedEventCounterManager getCounterManager() { return counterManager; } /** * Create a place holder instruction to represent an increment of a * particular counted event. Simply forwards the request to the * counter manager. * * @param counterNumber The number of the counter to increment * @return The instruction that will update the given counter */ public Instruction createEventCounterInstruction(int counterNumber) { return createEventCounterInstruction(counterNumber, 1.0); } /** * Create a place holder instruction to represent the counted event. * Simply forwards the request to the counter manager. * * @param counterNumber The number of the counter to increment * @param incrementValue The value to add to the given counter * @return The instruction that will update the given counter */ Instruction createEventCounterInstruction(int counterNumber, double incrementValue) { // Confirm that counters have been initialized if (VM.VerifyAssertions) { VM._assert(handle != -1); } // If we automatically growing counters, see if we need to. if (counterNumber >= numCounters) { if (automaticallyGrowCounters) { while (counterNumber >= numCounters) { resizeCounters(getNumCounters() * 2); } } else { // Should we put a warning here?? Not sure. } } return getCounterManager().createEventCounterInstruction(getHandle(), counterNumber, incrementValue); } /** * This method prints the (sorted) nonzero elements a counter * array. * * @param f a function that gets the "name" for each counter */ final void report(CounterNameFunction f) { double sum = 0; Vector<Counter> vec = new Vector<Counter>(); // set up a vector of non-zero counts for (int i = 0; i < getNumCounters(); i++) { double count = getCounter(i); if (count > 0.0) { sum += count; String s = f.getName(i); vec.addElement(new Counter(s, count)); } } // sort the vector in decreasing order sort(vec); // print for (Enumeration<Counter> e = vec.elements(); e.hasMoreElements();) { Counter c = e.nextElement(); String s = c.name; double count = c.count; double percent = (100 * count) / sum; VM.sysWrite(count + "/" + sum + " = " + percent + "% " + s + "\n"); } } /** * Sort a Vector<Counter> by decreasing count. * (code borrowed from InstructionSampler.java) * Shell sort * Reference: "The C Programming Language", Kernighan & Ritchie, p. 116 */ private void sort(Vector<?> v) { int n = v.size(); for (int gap = n / 2; gap > 0; gap /= 2) { for (int i = gap; i < n; ++i) { for (int j = i - gap; j >= 0; j -= gap) { double a = ((Counter) v.elementAt(j)).count; double b = ((Counter) v.elementAt(j + gap)).count; if (a >= b) break; swap(v, j, j + gap); } } } } // Interchange vec[i] with vec[j] private <T> void swap(Vector<T> vec, int i, int j) { T t = vec.elementAt(i); vec.setElementAt(vec.elementAt(j), i); vec.setElementAt(t, j); } /* ----- Implementation ---- */ /** * How many counters are needed by this data? **/ protected int numCounters = 0; /** * When a data object is registered with a counter manager, it is * given an id, which is stored here. **/ protected int handle = -1; /** * Basic block instrumentation stores its counters using an * abstracted counter allocation technique (a counterManager) **/ protected InstrumentedEventCounterManager counterManager = null; protected boolean automaticallyGrowCounters = false; /** * Auxiliary class */ static final class Counter { final String name; final double count; Counter(String s, double c) { name = s; count = c; } } }