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 java.util.Enumeration;
016    import java.util.Vector;
017    import org.jikesrvm.VM;
018    import org.jikesrvm.compilers.opt.InstrumentedEventCounterManager;
019    import 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     */
027    public 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.addElement(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       * Sort a 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 & Ritchie, p. 116
242       */
243      private void sort(Vector<?> v) {
244        int n = v.size();
245        for (int gap = n / 2; gap > 0; gap /= 2) {
246          for (int i = gap; i < n; ++i) {
247            for (int j = i - gap; j >= 0; j -= gap) {
248              double a = ((Counter) v.elementAt(j)).count;
249              double b = ((Counter) v.elementAt(j + gap)).count;
250              if (a >= b) break;
251              swap(v, j, j + gap);
252            }
253          }
254        }
255      }
256    
257      // Interchange vec[i] with vec[j]
258      private <T> void swap(Vector<T> vec, int i, int j) {
259        T t = vec.elementAt(i);
260        vec.setElementAt(vec.elementAt(j), i);
261        vec.setElementAt(t, j);
262      }
263    
264      /* -----   Implementation   ---- */
265    
266      /**
267       * How many counters are needed by this data?
268       **/
269      protected int numCounters = 0;
270    
271      /**
272       *  When a data object is registered with a counter manager, it is
273       *  given an id, which is stored here.
274       **/
275      protected int handle = -1;
276    
277      /**
278       * Basic block instrumentation stores its counters using an
279       * abstracted counter allocation technique (a counterManager)
280       **/
281      protected InstrumentedEventCounterManager counterManager = null;
282    
283      protected boolean automaticallyGrowCounters = false;
284    
285      /**
286       * Auxiliary class
287       */
288      static final class Counter {
289        final String name;
290        final double count;
291    
292        Counter(String s, double c) {
293          name = s;
294          count = c;
295        }
296      }
297    
298    }
299