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