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