/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.adaptive.controller;
import java.util.Enumeration;
import java.util.Vector;
import org.jikesrvm.VM;
import org.jikesrvm.VM_Callbacks;
import org.jikesrvm.adaptive.OSR_OrganizerThread;
import org.jikesrvm.adaptive.database.VM_AOSDatabase;
import org.jikesrvm.adaptive.database.callgraph.VM_PartialCallGraph;
import org.jikesrvm.adaptive.database.methodsamples.VM_MethodCountData;
import org.jikesrvm.adaptive.measurements.VM_RuntimeMeasurements;
import org.jikesrvm.adaptive.measurements.instrumentation.VM_Instrumentation;
import org.jikesrvm.adaptive.measurements.organizers.VM_Organizer;
import org.jikesrvm.adaptive.recompilation.VM_CompilationThread;
import org.jikesrvm.adaptive.recompilation.instrumentation.VM_CounterBasedSampling;
import org.jikesrvm.adaptive.util.VM_AOSLogging;
import org.jikesrvm.adaptive.util.VM_AOSOptions;
import org.jikesrvm.adaptive.util.VM_BlockingPriorityQueue;
import org.jikesrvm.compilers.baseline.VM_EdgeCounts;
import org.jikesrvm.compilers.common.VM_RecompilationManager;
import org.jikesrvm.scheduler.greenthreads.VM_GreenProcessor;
// TODO - deal with for subarch
/**
* This class contains top level adaptive compilation subsystem functions.
*/
public class VM_Controller implements VM_Callbacks.ExitMonitor,
VM_Callbacks.AppStartMonitor,
VM_Callbacks.AppCompleteMonitor,
VM_Callbacks.AppRunStartMonitor,
VM_Callbacks.AppRunCompleteMonitor,
VM_Callbacks.RecompileAllDynamicallyLoadedMethodsMonitor {
/**
* Signals when the options and (optional) logging mechanism are enabled
*/
public static boolean enabled = false;
/**
* Controller subsystem control options
*/
public static VM_AOSOptions options = new VM_AOSOptions();
/**
* Deferred command line arguments for the opt compiler
*/
private static String[] optCompilerOptions = new String[0];
/**
* Add a deferred command line argument
*/
public static void addOptCompilerOption(String arg) {
String[] tmp = new String[optCompilerOptions.length + 1];
for (int i = 0; i < optCompilerOptions.length; i++) {
tmp[i] = optCompilerOptions[i];
}
tmp[optCompilerOptions.length] = arg;
optCompilerOptions = tmp;
}
/**
* Get the deferred command line arguments
*/
public static String[] getOptCompilerOptions() {return optCompilerOptions;}
/**
* The controller thread, it makes all the decisions
* (the thread sets this field when it is created.)
*/
public static VM_ControllerThread controllerThread = null;
/**
* Thread that will perform opt-compilations as directed by the controller
* (the thread sets this field when it is created.)
*/
public static VM_CompilationThread compilationThread = null;
/**
* Thread collecting osr request and pass it to controllerThread
*/
public static OSR_OrganizerThread osrOrganizer = null;
/**
* Threads that will organize profile data as directed by the controller
*/
public static Vector<VM_Organizer> organizers = new Vector<VM_Organizer>();
/**
* A blocking priority queue where organizers place events to
* be processed by the controller
* (an input to the controller thread)
*/
public static VM_BlockingPriorityQueue controllerInputQueue;
/**
* A blocking priority queue where the controller will place methods
* to be opt compiled
* (an output of the controller thread)
*/
public static VM_BlockingPriorityQueue compilationQueue;
/**
* The strategy used to make recompilation decisions
*/
public static VM_RecompilationStrategy recompilationStrategy;
/**
* Controller virtual clock, ticked every taken yieldpoint.
*/
public static int controllerClock = 0;
/**
* The main hot method raw data object.
*/
public static VM_MethodCountData methodSamples;
/**
* The dynamic call graph
*/
public static VM_PartialCallGraph dcg;
/**
* Used to shut down threads
*/
private static final ThreadDeath threadDeath = new ThreadDeath();
/**
* Has the execution of boot completed successfully?
*/
private static boolean booted = false;
/**
* Initialize the controller subsystem (called from VM.boot)
* This method is called AFTER the command line options are processed.
*/
public static void boot() {
// Signal that the options and (optional) logging mechanism are set
// VM_RuntimeCompiler checks this flag
enabled = true;
// Initialize the controller input queue
controllerInputQueue = new VM_BlockingPriorityQueue(new VM_BlockingPriorityQueue.CallBack() {
public void aboutToWait() { controllerThread.aboutToWait(); }
public void doneWaiting() { controllerThread.doneWaiting(); }
});
compilationQueue = new VM_BlockingPriorityQueue();
// Create the analytic model used to make cost/benefit decisions.
recompilationStrategy = new VM_MultiLevelAdaptiveModel();
// boot the runtime measurement systems
VM_RuntimeMeasurements.boot();
// Initialize subsystems, if being used
VM_AdaptiveInlining.boot(options);
// boot any instrumentation options
VM_Instrumentation.boot(options);
// boot the aos database
VM_AOSDatabase.boot(options);
VM_CounterBasedSampling.boot(options);
createControllerThread();
VM_Controller controller = new VM_Controller();
VM_Callbacks.addExitMonitor(controller);
VM_Callbacks.addAppStartMonitor(controller);
VM_Callbacks.addAppCompleteMonitor(controller);
VM_Callbacks.addAppRunStartMonitor(controller);
VM_Callbacks.addAppRunCompleteMonitor(controller);
// make sure the user hasn't explicitly prohibited this functionality
if (!options.DISABLE_RECOMPILE_ALL_METHODS) {
VM_Callbacks.addRecompileAllDynamicallyLoadedMethodsMonitor(controller);
}
booted = true;
}
/**
* To be called when the VM is about to exit.
* @param value the exit value
*/
public void notifyExit(int value) {
report();
}
/**
* To be called when the application starts
* @param app the application name
*/
public void notifyAppStart(String app) {
VM_AOSLogging.appStart(app);
VM_AOSLogging.recordRecompAndThreadStats();
}
/**
* To be called when the application completes
* @param app the application name
*/
public void notifyAppComplete(String app) {
VM_AOSLogging.appComplete(app);
VM_AOSLogging.recordRecompAndThreadStats();
}
/**
* To be called when the application completes one of its run
* @param app the application name
* @param run the run number, i.e. what iteration of the app we have started
*/
public void notifyAppRunStart(String app, int run) {
VM_AOSLogging.appRunStart(app, run);
VM_AOSLogging.recordRecompAndThreadStats();
}
/**
* To be called when the application completes one of its run
* @param app the application name
* @param run the run number, i.e. what iteration of the app we have completed
*/
public void notifyAppRunComplete(String app, int run) {
VM_AOSLogging.appRunComplete(app, run);
VM_AOSLogging.recordRecompAndThreadStats();
}
/**
* Called when the application wants to recompile all dynamically
* loaded methods. This can be expensive!
*/
public void notifyRecompileAll() {
VM_AOSLogging.recompilingAllDynamicallyLoadedMethods();
VM_RecompilationManager.recompileAllDynamicallyLoadedMethods(false, false);
}
// Create the ControllerThread
static void createControllerThread() {
Object sentinel = new Object();
VM_ControllerThread tt = new VM_ControllerThread(sentinel);
tt.start();
// wait until controller threads are up and running.
try {
synchronized (sentinel) {
sentinel.wait();
}
} catch (Exception e) {
e.printStackTrace();
VM.sysFail("Failed to start up controller subsystem");
}
}
/**
* Process any command line arguments passed to the controller subsystem.
* <p>
* This method has the responsibility of creating the options object
* if it does not already exist
* <p>
* NOTE: All command line argument processing should be handled via
* the automatically generated code in VM_AOSOptions.java.
* Don't even think of adding handwritten stuff here! --dave
*
* @param arg the command line argument to be processed
*/
public static void processCommandLineArg(String arg) {
if (!options.processAsOption("-X:aos", arg)) {
VM.sysWrite("vm: illegal adaptive configuration directive \"" + arg + "\" specified as -X:aos:" + arg + "\n");
VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
}
}
/**
* This method is called when the VM is exiting to provide a hook to allow
* the adpative optimization subsystem to generate a summary report.
* It can also be called directly from driver programs to allow
* reporting on a single run of a benchmark that the driver program
* is executing in a loop (in which case the adaptive system isn't actually
* exiting.....so some of the log messages may get a little wierd).
*/
public static void report() {
if (!booted) return;
VM_ControllerThread.report();
VM_RuntimeMeasurements.report();
for (Enumeration<VM_Organizer> e = organizers.elements(); e.hasMoreElements();) {
VM_Organizer organizer = e.nextElement();
organizer.report();
}
if (options.FINAL_REPORT_LEVEL >= 2) {
VM_EdgeCounts.dumpCounts();
dcg.dumpGraph();
}
if (options.REPORT_INTERRUPT_STATS) {
VM.sysWriteln("Timer Interrupt and Listener Stats");
VM.sysWriteln("\tTotal number of clock ticks ", VM_GreenProcessor.timerTicks);
VM.sysWriteln("\tReported clock ticks ", VM_GreenProcessor.reportedTimerTicks);
VM.sysWriteln("\tController clock ", controllerClock);
VM.sysWriteln("\tNumber of method samples taken ", (int) methodSamples.getTotalNumberOfSamples());
}
VM_AOSLogging.systemExiting();
}
/**
* Stop all AOS threads and exit the adaptive system.
* Can be used to assess code quality in a steady state by
* allowing the adaptive system to run "for a while" and then
* stoppping it
*/
public static void stop() {
if (!booted) return;
VM.sysWriteln("AOS: Killing all adaptive system threads");
for (Enumeration<VM_Organizer> e = organizers.elements(); e.hasMoreElements();) {
VM_Organizer organizer = e.nextElement();
organizer.kill(threadDeath, true);
}
compilationThread.kill(threadDeath, true);
controllerThread.kill(threadDeath, true);
VM_RuntimeMeasurements.stop();
report();
}
}