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.util; 014 015import java.io.FileOutputStream; 016import java.io.IOException; 017import java.io.PrintStream; 018 019import org.jikesrvm.VM; 020import org.jikesrvm.adaptive.controller.Controller; 021import org.jikesrvm.adaptive.controller.ControllerMemory; 022import org.jikesrvm.adaptive.controller.ControllerPlan; 023import org.jikesrvm.adaptive.controller.HotMethodEvent; 024import org.jikesrvm.adaptive.recompilation.CompilerDNA; 025import org.jikesrvm.classloader.NormalMethod; 026import org.jikesrvm.classloader.RVMMethod; 027import org.jikesrvm.compilers.common.CompiledMethod; 028import org.jikesrvm.compilers.common.RuntimeCompiler; 029import org.jikesrvm.compilers.opt.driver.CompilationPlan; 030import org.jikesrvm.runtime.Time; 031 032/** 033 * This class provides logging functionality for the Adaptive Optimization System. 034 * <p> 035 * Right now this is fairly primitive, an evolving number of events are 036 * defined and log entries are quite unsophisticated. 037 * <p> 038 * Some obvious TODO items: 039 * <ul> 040 * <li>compact encoding of log entries 041 * <li>some notion of log format versions 042 * <li>When is the log file flushed and closed? 043 * <li>Do we want to put report() information in the log? 044 * <li> ... 045 * </ul> 046 * <p> 047 * NOTE: All code that writes to the log is synchronized on the PrintStream 048 * object to avoid interspersed messages, which can happen when the 049 * compilation thread and the controller thread try to log a message 050 * "at the same time". 051 * <p> 052 * The current logging levels are: 053 * <ul> 054 * <li>0 Do no logging 055 * <li>1 Do minimal logging at startup and VM exit. 056 * If at all possible, do not log anything during program execution. 057 * This logging level is supposed to produce minimal performance pertubation. 058 * <li>2 Log interesting AOS events and controller actions 059 * <li>3 Exhaustively log pretty much everything that is going on 060 * </ul> 061 */ 062public final class AOSLogging { 063 064 /** Singleton instance of the logger */ 065 public static final AOSLogging logger = new AOSLogging(); 066 067 /* 068 * The output file stream, where all log messages will go 069 */ 070 private PrintStream log; 071 072 public PrintStream getLog() { 073 return log; 074 } 075 076 /* 077 * Record that the AOS logging has been booted. 078 * Needed to allow fast exit from reporting to ensure 079 * that when no class is specified to be run but "-help" is specified, 080 * don't want null pointer exception to occur! 081 */ 082 private boolean booted = false; 083 084 /** 085 * @return whether AOS logging has booted 086 */ 087 public boolean booted() { 088 return booted; 089 } 090 091 /** 092 * @return the current time as a string 093 */ 094 private String getTime() { 095 return Controller.controllerClock + ":" + Time.nanoTime(); 096 } 097 098 /** 099 * Called from ControllerThread.run to initialize the logging subsystem 100 */ 101 public void boot() { 102 if (Controller.options.LOGGING_LEVEL >= 1) { 103 try { 104 log = new PrintStream(new FileOutputStream(Controller.options.LOGFILE_NAME)); 105 106 // This statement will force the compilation of println, so it 107 // is needed regardless of the particular content of the message! 108 synchronized (log) { 109 log.println(getTime() + " Logging enabled\n"); 110 log.println(Controller.options); 111 } 112 } catch (IOException e) { 113 VM.sysWrite("IOException caught in AOSLogging.java while trying to create and start log file.\n"); 114 VM.sysWrite("Please check for file permission problems\n"); 115 } 116 } 117 booted = true; 118 } 119 120 //////////////////////////////////////////////////////////////// 121 // Logging level 1 122 //////////////////////////////////////////////////////////////// 123 124 /** 125 * Call this method to dump statistics related to decaying 126 * @param decayCount the number of decay events 127 */ 128 public void decayStatistics(int decayCount) { 129 if (!booted) return; // fast exit 130 if (Controller.options.LOGGING_LEVEL >= 1) { 131 synchronized (log) { 132 log.print(getTime() + " Decay Organizer Statistics: \n\t" + " Num of Decay events: " + decayCount + "\n"); 133 } 134 } 135 } 136 137 /** 138 * Call this method when one run of the application begins 139 */ 140 public void recompilingAllDynamicallyLoadedMethods() { 141 if (Controller.options.LOGGING_LEVEL >= 1) { 142 synchronized (log) { 143 log.println(getTime() + " Recompiling all dynamically loaded methods"); 144 } 145 } 146 } 147 148 /** 149 * Dumps lots of controller statistics to the log file 150 */ 151 public void printControllerStats() { 152 if (Controller.options.LOGGING_LEVEL >= 1) { 153 int awoken = ControllerMemory.getNumAwoken(); 154 int didNothing = ControllerMemory.getNumDidNothing(); 155 int numMethodsConsidered = ControllerMemory.getNumMethodsConsidered(); 156 int numMethodsScheduledForRecomp = ControllerMemory.getNumMethodsScheduledForRecomp(); 157 int numOpt0 = ControllerMemory.getNumOpt0(); 158 int numOpt1 = ControllerMemory.getNumOpt1(); 159 int numOpt2 = ControllerMemory.getNumOpt2(); 160 int numOpt3 = ControllerMemory.getNumOpt3(); 161 162 synchronized (log) { 163 log.print(getTime() + 164 "\n Num times Controller thread is awoken: " + 165 awoken + 166 "\n Num times did nothing: " + 167 didNothing + 168 " (" + 169 ((int) ((float) didNothing / (float) awoken * 100)) + 170 "%)\n Num methods baseline compiled: " + 171 ControllerMemory.getNumBase() + 172 "\n Num methods considered for recompilation: " + 173 numMethodsConsidered + 174 "\n Num methods chosen to recompile: " + 175 numMethodsScheduledForRecomp + 176 " (" + 177 ((int) ((float) numMethodsScheduledForRecomp / numMethodsConsidered * 100)) + 178 "%)\n Opt Levels Chosen: " + 179 "\n\t Opt Level 0: " + 180 numOpt0 + 181 " (" + 182 ((int) ((float) numOpt0 / numMethodsScheduledForRecomp * 100)) + 183 "%)\n\t Opt Level 1: " + 184 numOpt1 + 185 " (" + 186 ((int) ((float) numOpt1 / numMethodsScheduledForRecomp * 100)) + 187 "%)\n" + 188 "\t Opt Level 2: " + 189 numOpt2 + 190 " (" + 191 ((int) ((float) numOpt2 / numMethodsScheduledForRecomp * 100)) + 192 "%)\n" + 193 "\t Opt Level 3: " + 194 numOpt3 + 195 " (" + 196 ((int) ((float) numOpt3 / numMethodsScheduledForRecomp * 100)) + 197 "%)\n\n"); 198 199 // Let the controller memory summarize itself to the log file 200 ControllerMemory.printFinalMethodStats(log); 201 } 202 } 203 } 204 205 /** 206 * This method reports the basic speedup rate for a compiler 207 * @param compiler the compiler you are reporting about 208 * @param rate the speedup rate 209 */ 210 public void reportSpeedupRate(int compiler, double rate) { 211 if (Controller.options.LOGGING_LEVEL >= 1) { 212 synchronized (log) { 213 log.println(getTime() + 214 " SpeedupRate for " + 215 CompilerDNA.getCompilerString(compiler) + 216 " compiler: " + 217 rate); 218 } 219 } 220 } 221 222 /** 223 * This method reports the basic compilation rate for a compiler 224 * @param compiler the compiler you are reporting about 225 * @param rate the compilation rate (bytecodes per millisecond) 226 */ 227 public void reportCompilationRate(int compiler, double rate) { 228 if (Controller.options.LOGGING_LEVEL >= 1) { 229 synchronized (log) { 230 log.println(getTime() + 231 " Compilation Rate (bytecode/msec) for " + 232 CompilerDNA.getCompilerString(compiler) + 233 " compiler: " + 234 rate); 235 } 236 } 237 } 238 239 /** 240 * This method reports the benefit ratio from one compiler to the other 241 * @param compiler1 the first compiler 242 * @param compiler2 the second compiler 243 * @param rate the improvement from going from a compiler1-compiled method 244 * to a compiler2-compiled method 245 */ 246 public void reportBenefitRatio(int compiler1, int compiler2, double rate) { 247 if (Controller.options.LOGGING_LEVEL >= 1) { 248 synchronized (log) { 249 log.println(getTime() + 250 " Benefit Ratio from " + 251 CompilerDNA.getCompilerString(compiler1) + 252 " compiler to " + 253 CompilerDNA.getCompilerString(compiler2) + 254 " compiler: " + 255 rate); 256 } 257 } 258 } 259 260 /** 261 * This method reports the compile time ratio from one compiler to 262 * the other 263 * @param compiler1 the first compiler 264 * @param compiler2 the second compiler 265 * @param rate the ratio of compiler1 compilation rate to 266 * compiler2 compilation rate 267 */ 268 public void reportCompileTimeRatio(int compiler1, int compiler2, double rate) { 269 if (Controller.options.LOGGING_LEVEL >= 1) { 270 synchronized (log) { 271 log.println(getTime() + 272 " Compile Time Ratio of " + 273 CompilerDNA.getCompilerString(compiler1) + 274 " compiler to " + 275 CompilerDNA.getCompilerString(compiler2) + 276 " compiler: " + 277 rate); 278 } 279 } 280 } 281 282 //////////////////////////////////////////////////////////////// 283 // Logging level 2 284 //////////////////////////////////////////////////////////////// 285 286 /** 287 * This method logs the scheduling of a recompilation, 288 * i.e., it being inserted in the compilation queue. 289 * @param plan the Compilation plan being executed. 290 * @param priority a number from 0.0 to 1.0 encoding the plan's priority. 291 */ 292 public void recompilationScheduled(CompilationPlan plan, double priority) { 293 if (Controller.options.LOGGING_LEVEL >= 2) { 294 synchronized (log) { 295 log.println(getTime() + " Scheduling level " + plan.options.getOptLevel() + " recompilation of " + plan 296 .method + " (plan has priority " + priority + ")"); 297 } 298 } 299 } 300 301 /** 302 * This method logs the beginning of an adaptively selected recompilation 303 * @param plan the Compilation plan being executed. 304 */ 305 public void recompilationStarted(CompilationPlan plan) { 306 if (Controller.options.LOGGING_LEVEL >= 2) { 307 synchronized (log) { 308 log.println(getTime() + " Recompiling (at level " + plan.options.getOptLevel() + ") " + plan.method); 309 } 310 } 311 } 312 313 /** 314 * This method logs the successful completion of an adaptively 315 * selected recompilation 316 * @param plan the Compilation plan being executed. 317 */ 318 public void recompilationCompleted(CompilationPlan plan) { 319 if (Controller.options.LOGGING_LEVEL >= 2) { 320 synchronized (log) { 321 // log.println(getTime() +" Recompiled (at level "+ 322 // plan.options.getOptLevel() +") " +plan.method); 323 log.println(getTime() + " Recompiled (at level " + plan.options.getOptLevel() + ") " + plan.method); 324 } 325 } 326 } 327 328 /** 329 * This method logs the abortion of an adaptively selected recompilation 330 * @param plan the Compilation plan being executed. 331 */ 332 public void recompilationAborted(CompilationPlan plan) { 333 if (Controller.options.LOGGING_LEVEL >= 2) { 334 synchronized (log) { 335 log.println(getTime() + " Failed recompiling (at level " + plan.options.getOptLevel() + " " + plan.method); 336 } 337 } 338 } 339 340 /** 341 * This method logs the actual compilation time for the given compiled method. 342 * @param cm the compiled method 343 * @param expectedCompilationTime the model-derived expected compilation time 344 */ 345 public void recordCompileTime(CompiledMethod cm, double expectedCompilationTime) { 346 if (log != null && Controller.options.LOGGING_LEVEL >= 2) { 347 synchronized (log) { 348 double compTime = cm.getCompilationTime(); 349 log.println(getTime() + 350 " Compiled " + 351 cm.getMethod() + 352 " with " + 353 cm.getCompilerName() + 354 " in " + 355 compTime + 356 " ms" + 357 ", model estimated: " + 358 expectedCompilationTime + 359 " ms" + 360 ", rate: " + 361 (((NormalMethod) cm.getMethod()).getBytecodeLength() / compTime)); 362 } 363 } 364 } 365 366 /** 367 * this method logs the event when the controller discovers a method that has 368 * been recompiled and the previous version is still regarded as hot, 369 * i.e., still on the stack and significant. 370 * 371 * @param hme the hot method event of the method that was recompiled 372 */ 373 public void oldVersionStillHot(HotMethodEvent hme) { 374 if (Controller.options.LOGGING_LEVEL >= 2) { 375 synchronized (log) { 376 log.println(getTime() + " Found a method with an old version still hot " + hme); 377 } 378 } 379 } 380 381 /** 382 * This method logs when the decay organizer runs. 383 */ 384 public void decayingCounters() { 385 if (Controller.options.LOGGING_LEVEL >= 2) { 386 synchronized (log) { 387 log.println(getTime() + " Decaying clock and decayable objects"); 388 } 389 } 390 } 391 392 /** 393 * This Method logs when the organizer thread has reached its 394 * sampling threshold 395 */ 396 public void organizerThresholdReached() { 397 if (Controller.options.LOGGING_LEVEL >= 2) { 398 synchronized (log) { 399 log.println(getTime() + " OrganizerThread reached sample size threshold\n"); 400 } 401 } 402 } 403 404 /** 405 * This method logs that the controller is notified of a 406 * candidate to be recompiled due to hotness; 407 * i.e., the method has been inserted in the controller queue. 408 * @param hotMethod method to be recompiled, and 409 * @param numSamples number of samples attributed to the method 410 */ 411 public void controllerNotifiedForHotness(CompiledMethod hotMethod, double numSamples) { 412 if (Controller.options.LOGGING_LEVEL >= 2) { 413 synchronized (log) { 414 log.println(getTime() + 415 " Controller notified that method " + 416 hotMethod.getMethod() + 417 "(" + 418 hotMethod.getId() + 419 ")" + 420 " has " + 421 numSamples + 422 " samples"); 423 } 424 } 425 } 426 427 //////////////////////////////////////////////////////////////// 428 // Logging level 3 429 //////////////////////////////////////////////////////////////// 430 431 /** 432 * This method logs a controller cost estimate for doing nothing. 433 * @param method the method of interest 434 * @param optLevel the opt level being estimated, -1 = baseline 435 * @param cost the computed cost for this method and level 436 */ 437 public void recordControllerEstimateCostDoNothing(RVMMethod method, int optLevel, double cost) { 438 if (Controller.options.LOGGING_LEVEL >= 3) { 439 synchronized (log) { 440 log.print(getTime() + " Estimated cost of doing nothing (leaving at "); 441 if (optLevel == -1) { 442 log.print("baseline"); 443 } else { 444 log.print("O" + optLevel); 445 } 446 log.println(") to " + method + " is " + cost); 447 } 448 } 449 } 450 451 /** 452 * This method logs a controller cost estimate. 453 * @param method the method of interest 454 * @param choiceDesc a String describing the choice point 455 * @param compilationTime the computed compilation cost for this method and level 456 * @param futureTime the computed future time, including cost and execution 457 */ 458 public void recordControllerEstimateCostOpt(RVMMethod method, String choiceDesc, double compilationTime, 459 double futureTime) { 460 if (Controller.options.LOGGING_LEVEL >= 3) { 461 synchronized (log) { 462 log.println(getTime() + 463 " Estimated cost of OPT compiling " + 464 method + 465 " at " + 466 choiceDesc + 467 " is " + 468 compilationTime + 469 ", total future time is " + 470 futureTime); 471 } 472 } 473 } 474 475 /** 476 * Records lots of details about the online computation of a compilation rate 477 * @param compiler compiler of interest 478 * @param method the method 479 * @param BCLength the number of bytecodes 480 * @param totalBCLength cumulative number of bytecodes 481 * @param MCLength size of machine code 482 * @param totalMCLength cumulative size of machine code 483 * @param compTime compilation time for this method 484 * @param totalCompTime cumulative compilation time for this method 485 * @param totalLogOfRates running sum of the natural logs of the rates 486 * @param totalLogValueMethods number of methods used in the log of rates 487 * @param totalMethods total number of methods 488 */ 489 public void recordUpdatedCompilationRates(byte compiler, RVMMethod method, int BCLength, int totalBCLength, 490 int MCLength, int totalMCLength, double compTime, 491 double totalCompTime, double totalLogOfRates, 492 int totalLogValueMethods, int totalMethods) { 493 494 if (Controller.options.LOGGING_LEVEL >= 3) { 495 synchronized (log) { 496 boolean backBranch = false; 497 if (method instanceof NormalMethod) { 498 backBranch = ((NormalMethod) method).hasBackwardsBranch(); 499 } 500 log.println(getTime() + 501 " Updated compilation rates for " + 502 RuntimeCompiler.getCompilerName(compiler) + 503 "compiler"); 504 log.println("\tmethod compiled: " + method); 505 log.println("\tbyte code length: " + BCLength + ", Total: " + totalBCLength); 506 log.println("\tmachine code length: " + MCLength + ", Total: " + totalMCLength); 507 log.println("\tbackwards branch: " + (backBranch ? "yes" : "no")); 508 log.println("\tcompilation time: " + compTime + ", Total: " + totalCompTime); 509 log.println("\tRate for this method: " + BCLength / compTime + ", Total of Logs: " + totalLogOfRates); 510 log.println("\tTotal Methods: " + totalMethods); 511 log.println("\tNew Rate: " + Math.exp(totalLogOfRates / totalLogValueMethods)); 512 } 513 } 514 } 515 516 public void compileAllMethodsCompleted() { 517 if (Controller.options.LOGGING_LEVEL >= 2) { 518 synchronized (log) { 519 log.println(Controller.controllerClock + " Compiled all methods finished. "); 520 } 521 } 522 } 523 524 //////////////////////////////////////////////////////////////// 525 // OSR-related code 526 //////////////////////////////////////////////////////////////// 527 528 /** 529 * This method logs the successful completion of an adaptively 530 * selected recompilation 531 * @param plan the Compilation plan being executed. 532 */ 533 public void recordOSRRecompilationDecision(ControllerPlan plan) { 534 CompilationPlan cplan = plan.getCompPlan(); 535 if (Controller.options.LOGGING_LEVEL >= 1) { 536 synchronized (log) { 537 log.println(getTime() + " recompile with OSR " + "( at level " + cplan.options.getOptLevel() + " ) " + cplan 538 .method); 539 } 540 } 541 } 542 543 public void onStackReplacementStarted(CompilationPlan plan) { 544 if (Controller.options.LOGGING_LEVEL >= 1) { 545 synchronized (log) { 546 log.println(getTime() + " OSR starts " + "( at level " + plan.options.getOptLevel() + " ) " + plan.method); 547 } 548 } 549 } 550 551 public void onStackReplacementCompleted(CompilationPlan plan) { 552 if (Controller.options.LOGGING_LEVEL >= 1) { 553 synchronized (log) { 554 log.println(getTime() + " OSR ends " + "( at level " + plan.options.getOptLevel() + " ) " + plan.method); 555 } 556 } 557 } 558 559 public void onStackReplacementAborted(CompilationPlan plan) { 560 if (Controller.options.LOGGING_LEVEL >= 1) { 561 synchronized (log) { 562 log.println(getTime() + " OSR failed " + "( at level " + plan.options.getOptLevel() + " ) " + plan.method); 563 } 564 } 565 } 566 567 public void logOsrEvent(String s) { 568 if (Controller.options.LOGGING_LEVEL >= 1) { 569 synchronized (log) { 570 log.println(getTime() + " " + s); 571 } 572 } 573 } 574 575 public void debug(String s) { 576 if (Controller.options.LOGGING_LEVEL >= 2) { 577 synchronized (log) { 578 log.println(getTime() + s); 579 } 580 } 581 } 582}