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