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 & 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