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.controller; 014 015import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG; 016 017import java.util.Enumeration; 018import java.util.Vector; 019import org.jikesrvm.VM; 020import org.jikesrvm.adaptive.OSROrganizerThread; 021import org.jikesrvm.adaptive.database.AOSDatabase; 022import org.jikesrvm.adaptive.database.callgraph.PartialCallGraph; 023import org.jikesrvm.adaptive.database.methodsamples.MethodCountData; 024import org.jikesrvm.adaptive.measurements.RuntimeMeasurements; 025import org.jikesrvm.adaptive.measurements.instrumentation.Instrumentation; 026import org.jikesrvm.adaptive.measurements.organizers.Organizer; 027import org.jikesrvm.adaptive.recompilation.CompilationThread; 028import org.jikesrvm.adaptive.recompilation.instrumentation.CounterBasedSampling; 029import org.jikesrvm.adaptive.util.AOSLogging; 030import org.jikesrvm.adaptive.util.AOSOptions; 031import org.jikesrvm.adaptive.util.BlockingPriorityQueue; 032import org.jikesrvm.compilers.baseline.EdgeCounts; 033import org.jikesrvm.compilers.common.RecompilationManager; 034import org.jikesrvm.runtime.Callbacks; 035import org.jikesrvm.scheduler.RVMThread; 036import org.jikesrvm.scheduler.SoftLatch; 037 038/** 039 * This class contains top level adaptive compilation subsystem functions. 040 */ 041public class Controller implements Callbacks.ExitMonitor, 042 Callbacks.RecompileAllDynamicallyLoadedMethodsMonitor { 043 044 /** 045 * Signals when the options and (optional) logging mechanism are enabled 046 */ 047 public static boolean enabled = false; 048 049 /** 050 * Controller subsystem control options 051 */ 052 public static final AOSOptions options = new AOSOptions(); 053 054 /** 055 * Deferred command line arguments for the opt compiler 056 */ 057 private static String[] optCompilerOptions = new String[0]; 058 059 /** 060 * Adds a deferred command line argument. 061 * 062 * @param arg the deferred arguments 063 */ 064 public static void addOptCompilerOption(String arg) { 065 String[] tmp = new String[optCompilerOptions.length + 1]; 066 for (int i = 0; i < optCompilerOptions.length; i++) { 067 tmp[i] = optCompilerOptions[i]; 068 } 069 tmp[optCompilerOptions.length] = arg; 070 optCompilerOptions = tmp; 071 } 072 073 /** 074 * @return the deferred command line arguments 075 */ 076 public static String[] getOptCompilerOptions() { 077 return optCompilerOptions; 078 } 079 080 /** 081 * The controller thread, it makes all the decisions 082 * (the thread sets this field when it is created.) 083 */ 084 public static ControllerThread controllerThread = null; 085 086 /** 087 * Thread that will perform opt-compilations as directed by the controller 088 * (the thread sets this field when it is created.) 089 */ 090 public static CompilationThread compilationThread = null; 091 092 /** 093 * Thread collecting osr request and pass it to controllerThread 094 */ 095 public static OSROrganizerThread osrOrganizer = null; 096 097 /** 098 * Threads that will organize profile data as directed by the controller 099 */ 100 public static final Vector<Organizer> organizers = new Vector<Organizer>(); 101 102 /** 103 * A blocking priority queue where organizers place events to 104 * be processed by the controller 105 * (an input to the controller thread) 106 */ 107 public static BlockingPriorityQueue controllerInputQueue; 108 109 /** 110 * A blocking priority queue where the controller will place methods 111 * to be opt compiled 112 * (an output of the controller thread) 113 */ 114 public static BlockingPriorityQueue compilationQueue; 115 116 /** 117 * The strategy used to make recompilation decisions 118 */ 119 public static RecompilationStrategy recompilationStrategy; 120 121 /** 122 * Controller virtual clock, ticked every taken yieldpoint. 123 */ 124 public static int controllerClock = 0; 125 126 /** 127 * The main hot method raw data object. 128 */ 129 public static MethodCountData methodSamples; 130 /** 131 * The dynamic call graph 132 */ 133 public static PartialCallGraph dcg; 134 135 /** 136 * Used to shut down threads 137 */ 138 private static final ThreadDeath threadDeath = new ThreadDeath(); 139 140 /** 141 * Has the execution of boot completed successfully? 142 */ 143 private static boolean booted = false; 144 145 /** 146 * Initialize the controller subsystem (called from VM.boot) 147 * This method is called AFTER the command line options are processed. 148 */ 149 public static void boot() { 150 // Signal that the options and (optional) logging mechanism are set 151 // RuntimeCompiler checks this flag 152 enabled = true; 153 154 // Initialize the controller input queue 155 controllerInputQueue = new BlockingPriorityQueue(new BlockingPriorityQueue.CallBack() { 156 @Override 157 public void aboutToWait() { 158 controllerThread.aboutToWait(); 159 } 160 @Override 161 public void doneWaiting() { 162 controllerThread.doneWaiting(); 163 } 164 }); 165 166 compilationQueue = new BlockingPriorityQueue(); 167 168 // Create the analytic model used to make cost/benefit decisions. 169 recompilationStrategy = new MultiLevelAdaptiveModel(); 170 171 // boot the runtime measurement systems 172 RuntimeMeasurements.boot(); 173 174 // Initialize subsystems, if being used 175 AdaptiveInlining.boot(options); 176 177 // boot any instrumentation options 178 Instrumentation.boot(options); 179 180 // boot the AOS database 181 AOSDatabase.boot(options); 182 183 CounterBasedSampling.boot(options); 184 185 createControllerThread(); 186 187 Controller controller = new Controller(); 188 Callbacks.addExitMonitor(controller); 189 190 // make sure the user hasn't explicitly prohibited this functionality 191 if (!options.DISABLE_RECOMPILE_ALL_METHODS) { 192 Callbacks.addRecompileAllDynamicallyLoadedMethodsMonitor(controller); 193 } 194 195 booted = true; 196 } 197 198 /** 199 * To be called when the VM is about to exit. 200 * @param value the exit value 201 */ 202 @Override 203 public void notifyExit(int value) { 204 report(); 205 } 206 207 /** 208 * Called when the application wants to recompile all dynamically 209 * loaded methods. This can be expensive! 210 */ 211 @Override 212 public void notifyRecompileAll() { 213 AOSLogging.logger.recompilingAllDynamicallyLoadedMethods(); 214 RecompilationManager.recompileAllDynamicallyLoadedMethods(false); 215 } 216 217 // Create the ControllerThread 218 static void createControllerThread() { 219 SoftLatch sentinel = new SoftLatch(false); 220 ControllerThread tt = new ControllerThread(sentinel); 221 tt.start(); 222 // wait until controller threads are up and running. 223 try { 224 sentinel.waitAndClose(); 225 } catch (Exception e) { 226 e.printStackTrace(); 227 VM.sysFail("Failed to start up controller subsystem"); 228 } 229 } 230 231 /** 232 * Process any command line arguments passed to the controller subsystem. 233 * <p> 234 * This method has the responsibility of creating the options object 235 * if it does not already exist 236 * <p> 237 * NOTE: All command line argument processing should be handled via 238 * the automatically generated code in AOSOptions.java. 239 * Don't even think of adding handwritten stuff here! --dave 240 * 241 * @param arg the command line argument to be processed 242 */ 243 public static void processCommandLineArg(String arg) { 244 if (!options.processAsOption("-X:aos", arg)) { 245 VM.sysWrite("vm: illegal adaptive configuration directive \"" + arg + "\" specified as -X:aos:" + arg + "\n"); 246 VM.sysExit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); 247 } 248 } 249 250 /** 251 * This method is called when the VM is exiting to provide a hook to allow 252 * the adaptive optimization subsystem to generate a summary report. 253 * It can also be called directly from driver programs to allow 254 * reporting on a single run of a benchmark that the driver program 255 * is executing in a loop (in which case the adaptive system isn't actually 256 * exiting.....so some of the log messages may get a little weird). 257 */ 258 public static void report() { 259 if (!booted) return; 260 ControllerThread.report(); 261 RuntimeMeasurements.report(); 262 263 for (Enumeration<Organizer> e = organizers.elements(); e.hasMoreElements();) { 264 Organizer organizer = e.nextElement(); 265 organizer.report(); 266 } 267 268 if (options.FINAL_REPORT_LEVEL >= 2) { 269 EdgeCounts.dumpCounts(); 270 dcg.dumpGraph(); 271 } 272 273 if (options.REPORT_INTERRUPT_STATS) { 274 VM.sysWriteln("Timer Interrupt and Listener Stats"); 275 VM.sysWriteln("\tTotal number of clock ticks ", RVMThread.timerTicks); 276 VM.sysWriteln("\tController clock ", controllerClock); 277 VM.sysWriteln("\tNumber of method samples taken ", (int) methodSamples.getTotalNumberOfSamples()); 278 } 279 } 280 281 /** 282 * Stop all AOS threads and exit the adaptive system. 283 * Can be used to assess code quality in a steady state by 284 * allowing the adaptive system to run "for a while" and then 285 * stopping it 286 */ 287 public static void stop() { 288 if (!booted) return; 289 290 VM.sysWriteln("AOS: Killing all adaptive system threads"); 291 for (Enumeration<Organizer> e = organizers.elements(); e.hasMoreElements();) { 292 Organizer organizer = e.nextElement(); 293 organizer.stop(threadDeath); 294 } 295 compilationThread.stop(threadDeath); 296 controllerThread.stop(threadDeath); 297 RuntimeMeasurements.stop(); 298 report(); 299 } 300} 301