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; 014 015 import java.util.Vector; 016 import org.jikesrvm.ArchitectureSpecific.StackframeLayoutConstants; 017 import org.jikesrvm.adaptive.controller.Controller; 018 import org.jikesrvm.adaptive.measurements.listeners.ContextListener; 019 import org.jikesrvm.adaptive.measurements.listeners.MethodListener; 020 import org.jikesrvm.adaptive.measurements.listeners.NullListener; 021 import org.jikesrvm.adaptive.util.AOSLogging; 022 import org.jikesrvm.compilers.common.CompiledMethod; 023 import org.jikesrvm.compilers.common.CompiledMethods; 024 import org.jikesrvm.runtime.Magic; 025 import org.vmmagic.pragma.Uninterruptible; 026 import org.vmmagic.unboxed.Address; 027 028 /** 029 * RuntimeMeasurements manages listeners, decayable objects, and 030 * reportable objects.<p> 031 * 032 * A listener is installed by an organizer, and activated at thread 033 * switch time by Thread. Depending on the update method that the 034 * listener supports, it can be either a method, context, or a null 035 * listener. Currently we have different registries for different 036 * listeners. An alternative design is to have one register with where 037 * entries are tagged.<p> 038 * 039 * A decayable object implements the Decayable interface. 040 * Anyone can register a decayable object, 041 * The DecayOrganizer periodically decays all objects that have 042 * been registers.<p> 043 * 044 * A reportable object implements the Reportable interface, and 045 * is typically registered and used by the instrumentation subsystem. 046 * A Reporable can be reset and reported. 047 */ 048 public abstract class RuntimeMeasurements { 049 050 ///////////////////////////////////////////////////////////////////////// 051 // Support for gathering profile data on timer ticks 052 ///////////////////////////////////////////////////////////////////////// 053 054 /** 055 * listeners on timer ticks for methods 056 */ 057 private static MethodListener[] timerMethodListeners = new MethodListener[0]; 058 059 /** 060 * listeners on timer ticks for contexts 061 */ 062 private static ContextListener[] timerContextListeners = new ContextListener[0]; 063 064 /** 065 * listeners on timer ticks for nulls 066 */ 067 private static NullListener[] timerNullListeners = new NullListener[0]; 068 069 /** 070 * Install a method listener on timer ticks 071 * @param s method listener to be installed 072 */ 073 public static synchronized void installTimerMethodListener(MethodListener s) { 074 int numListeners = timerMethodListeners.length; 075 MethodListener[] tmp = new MethodListener[numListeners + 1]; 076 for (int i = 0; i < numListeners; i++) { 077 tmp[i] = timerMethodListeners[i]; 078 } 079 tmp[numListeners] = s; 080 timerMethodListeners = tmp; 081 } 082 083 /** 084 * Install a context listener on timer ticks 085 * @param s context listener to be installed 086 */ 087 public static synchronized void installTimerContextListener(ContextListener s) { 088 int numListeners = timerContextListeners.length; 089 ContextListener[] tmp = new ContextListener[numListeners + 1]; 090 for (int i = 0; i < numListeners; i++) { 091 tmp[i] = timerContextListeners[i]; 092 } 093 tmp[numListeners] = s; 094 timerContextListeners = tmp; 095 } 096 097 /** 098 * Install a null listener on timer ticks 099 * @param s null listener to be installed 100 */ 101 public static synchronized void installTimerNullListener(NullListener s) { 102 int numListeners = timerNullListeners.length; 103 NullListener[] tmp = new NullListener[numListeners + 1]; 104 for (int i = 0; i < numListeners; i++) { 105 tmp[i] = timerNullListeners[i]; 106 } 107 tmp[numListeners] = s; 108 timerNullListeners = tmp; 109 } 110 111 /** 112 * Called from Thread.yieldpoint every time it is invoked due to 113 * a timer interrupt. 114 */ 115 @Uninterruptible 116 public static void takeTimerSample(int whereFrom, Address yieldpointServiceMethodFP) { 117 // We use timer ticks as a rough approximation of time. 118 // TODO: kill controller clock in favor of reportedTimerTicks 119 // PNT: huh? 120 Controller.controllerClock++; 121 122 Address ypTakenInFP = Magic.getCallerFramePointer(yieldpointServiceMethodFP); // method that took yieldpoint 123 124 // Get the cmid for the method in which the yieldpoint was taken. 125 int ypTakenInCMID = Magic.getCompiledMethodID(ypTakenInFP); 126 127 // Get the cmid for that method's caller. 128 Address ypTakenInCallerFP = Magic.getCallerFramePointer(ypTakenInFP); 129 int ypTakenInCallerCMID = Magic.getCompiledMethodID(ypTakenInCallerFP); 130 131 // Determine if ypTakenInCallerCMID corresponds to a real Java stackframe. 132 // If one of the following conditions is detected, set ypTakenInCallerCMID to -1 133 // Caller is out-of-line assembly (no RVMMethod object) or top-of-stack psuedo-frame 134 // Caller is a native method 135 CompiledMethod ypTakenInCM = CompiledMethods.getCompiledMethod(ypTakenInCMID); 136 if (ypTakenInCallerCMID == StackframeLayoutConstants.INVISIBLE_METHOD_ID || 137 ypTakenInCM.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { 138 ypTakenInCallerCMID = -1; 139 } 140 141 // Notify all registered listeners 142 for (NullListener aNl : timerNullListeners) { 143 if (aNl.isActive()) { 144 aNl.update(whereFrom); 145 } 146 } 147 for (MethodListener aMl : timerMethodListeners) { 148 if (aMl.isActive()) { 149 aMl.update(ypTakenInCMID, ypTakenInCallerCMID, whereFrom); 150 } 151 } 152 if (ypTakenInCallerCMID != -1) { 153 for (ContextListener aCl : timerContextListeners) { 154 if (aCl.isActive()) { 155 aCl.update(ypTakenInFP, whereFrom); 156 } 157 } 158 } 159 } 160 161 ///////////////////////////////////////////////////////////////////////// 162 // Support for gathering profile data on CBS samples 163 ///////////////////////////////////////////////////////////////////////// 164 165 /** 166 * method listeners that trigger on CBS Method yieldpoints 167 */ 168 private static MethodListener[] cbsMethodListeners = new MethodListener[0]; 169 170 /** 171 * context listeners that trigger on CBS call yieldpoints 172 */ 173 private static ContextListener[] cbsContextListeners = new ContextListener[0]; 174 175 /** 176 * Install a method listener on CBS ticks 177 * @param s method listener to be installed 178 */ 179 public static synchronized void installCBSMethodListener(MethodListener s) { 180 int numListeners = cbsMethodListeners.length; 181 MethodListener[] tmp = new MethodListener[numListeners + 1]; 182 for (int i = 0; i < numListeners; i++) { 183 tmp[i] = cbsMethodListeners[i]; 184 } 185 tmp[numListeners] = s; 186 cbsMethodListeners = tmp; 187 } 188 189 /** 190 * Install a context listener on CBS ticks 191 * @param s context listener to be installed 192 */ 193 public static synchronized void installCBSContextListener(ContextListener s) { 194 int numListeners = cbsContextListeners.length; 195 ContextListener[] tmp = new ContextListener[numListeners + 1]; 196 for (int i = 0; i < numListeners; i++) { 197 tmp[i] = cbsContextListeners[i]; 198 } 199 tmp[numListeners] = s; 200 cbsContextListeners = tmp; 201 } 202 203 /** 204 * Called from Thread.yieldpoint when it is time to take a CBS method sample. 205 */ 206 @Uninterruptible 207 public static void takeCBSMethodSample(int whereFrom, Address yieldpointServiceMethodFP) { 208 Address ypTakenInFP = Magic.getCallerFramePointer(yieldpointServiceMethodFP); // method that took yieldpoint 209 210 // Get the cmid for the method in which the yieldpoint was taken. 211 int ypTakenInCMID = Magic.getCompiledMethodID(ypTakenInFP); 212 213 // Get the cmid for that method's caller. 214 Address ypTakenInCallerFP = Magic.getCallerFramePointer(ypTakenInFP); 215 int ypTakenInCallerCMID = Magic.getCompiledMethodID(ypTakenInCallerFP); 216 217 // Determine if ypTakenInCallerCMID corresponds to a real Java stackframe. 218 // If one of the following conditions is detected, set ypTakenInCallerCMID to -1 219 // Caller is out-of-line assembly (no RVMMethod object) or top-of-stack psuedo-frame 220 // Caller is a native method 221 CompiledMethod ypTakenInCM = CompiledMethods.getCompiledMethod(ypTakenInCMID); 222 if (ypTakenInCallerCMID == StackframeLayoutConstants.INVISIBLE_METHOD_ID || 223 ypTakenInCM.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { 224 ypTakenInCallerCMID = -1; 225 } 226 227 // Notify all registered listeners 228 for (MethodListener methodListener : cbsMethodListeners) { 229 if (methodListener.isActive()) { 230 methodListener.update(ypTakenInCMID, ypTakenInCallerCMID, whereFrom); 231 } 232 } 233 } 234 235 /** 236 * Called from Thread.yieldpoint when it is time to take a CBS call sample. 237 */ 238 @Uninterruptible 239 public static void takeCBSCallSample(int whereFrom, Address yieldpointServiceMethodFP) { 240 Address ypTakenInFP = Magic.getCallerFramePointer(yieldpointServiceMethodFP); // method that took yieldpoint 241 242 // Get the cmid for the method in which the yieldpoint was taken. 243 int ypTakenInCMID = Magic.getCompiledMethodID(ypTakenInFP); 244 245 // Get the cmid for that method's caller. 246 Address ypTakenInCallerFP = Magic.getCallerFramePointer(ypTakenInFP); 247 int ypTakenInCallerCMID = Magic.getCompiledMethodID(ypTakenInCallerFP); 248 249 // Determine if ypTakenInCallerCMID corresponds to a real Java stackframe. 250 // If one of the following conditions is detected, set ypTakenInCallerCMID to -1 251 // Caller is out-of-line assembly (no RVMMethod object) or top-of-stack psuedo-frame 252 // Caller is a native method 253 CompiledMethod ypTakenInCM = CompiledMethods.getCompiledMethod(ypTakenInCMID); 254 if (ypTakenInCallerCMID == StackframeLayoutConstants.INVISIBLE_METHOD_ID || 255 ypTakenInCM.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { 256 // drop sample 257 } else { 258 // Notify all registered listeners 259 for (ContextListener listener : cbsContextListeners) { 260 if (listener.isActive()) { 261 listener.update(ypTakenInFP, whereFrom); 262 } 263 } 264 } 265 } 266 267 ///////////////////////////////////////////////////////////////////////// 268 // Support for decay 269 ///////////////////////////////////////////////////////////////////////// 270 271 /** 272 * The currently registered decayable objects 273 */ 274 static Vector<Decayable> decayObjects = new Vector<Decayable>(); 275 276 /** 277 * Counts the number of decay events 278 */ 279 static int decayEventCounter = 0; 280 281 /** 282 * Register an object that should be decayed. 283 * The passed object will have its decay method called when the 284 * decaying thread decides it is time for the system to decay. 285 */ 286 public static void registerDecayableObject(Decayable obj) { 287 decayObjects.add(obj); 288 } 289 290 /** 291 * Decay all registered decayable objects. 292 */ 293 public static void decayDecayableObjects() { 294 decayEventCounter++; 295 AOSLogging.logger.decayingCounters(); 296 297 for (Decayable obj : decayObjects) { 298 obj.decay(); 299 } 300 } 301 302 ///////////////////////////////////////////////////////////////////////// 303 // Support for reportable objects 304 ///////////////////////////////////////////////////////////////////////// 305 306 /** 307 * The currently registered reportable objects 308 */ 309 static Vector<Reportable> reportObjects = new Vector<Reportable>(); 310 311 /** 312 * Register an object that wants to have its report method called 313 * whenever RuntimeMeasurements.report is called 314 */ 315 public static void registerReportableObject(Reportable obj) { 316 reportObjects.add(obj); 317 } 318 319 /** 320 * Reset to all registered reportable objects 321 */ 322 public static void resetReportableObjects() { 323 for (Reportable obj : reportObjects) { 324 obj.reset(); 325 } 326 } 327 328 /** 329 * Report to all registered reportable objects 330 */ 331 private static void reportReportableObjects() { 332 for (Reportable obj : reportObjects) { 333 obj.report(); 334 } 335 } 336 337 /** 338 * Report the current state of runtime measurements 339 */ 340 public static void report() { 341 reportReportableObjects(); 342 343 AOSLogging.logger.decayStatistics(decayEventCounter); 344 } 345 346 /** 347 * Stop the runtime measurement subsystem 348 */ 349 public static synchronized void stop() { 350 timerMethodListeners = new MethodListener[0]; 351 timerContextListeners = new ContextListener[0]; 352 timerNullListeners = new NullListener[0]; 353 354 cbsMethodListeners = new MethodListener[0]; 355 cbsContextListeners = new ContextListener[0]; 356 } 357 358 /** 359 * Called when the VM is booting 360 */ 361 public static void boot() { } 362 } 363