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