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          public void aboutToWait() { controllerThread.aboutToWait(); }
151          public void doneWaiting() { controllerThread.doneWaiting(); }
152        });
153    
154        compilationQueue = new BlockingPriorityQueue();
155    
156        // Create the analytic model used to make cost/benefit decisions.
157        recompilationStrategy = new MultiLevelAdaptiveModel();
158    
159        // boot the runtime measurement systems
160        RuntimeMeasurements.boot();
161    
162        // Initialize subsystems, if being used
163        AdaptiveInlining.boot(options);
164    
165        // boot any instrumentation options
166        Instrumentation.boot(options);
167    
168        // boot the aos database
169        AOSDatabase.boot(options);
170    
171        CounterBasedSampling.boot(options);
172    
173        createControllerThread();
174    
175        Controller controller = new Controller();
176        Callbacks.addExitMonitor(controller);
177    
178        // make sure the user hasn't explicitly prohibited this functionality
179        if (!options.DISABLE_RECOMPILE_ALL_METHODS) {
180          Callbacks.addRecompileAllDynamicallyLoadedMethodsMonitor(controller);
181        }
182    
183        booted = true;
184      }
185    
186      /**
187       * To be called when the VM is about to exit.
188       * @param value the exit value
189       */
190      public void notifyExit(int value) {
191        report();
192      }
193    
194      /**
195       * Called when the application wants to recompile all dynamically
196       *  loaded methods.  This can be expensive!
197       */
198      public void notifyRecompileAll() {
199        AOSLogging.logger.recompilingAllDynamicallyLoadedMethods();
200        RecompilationManager.recompileAllDynamicallyLoadedMethods(false);
201      }
202    
203      // Create the ControllerThread
204      static void createControllerThread() {
205        SoftLatch sentinel = new SoftLatch(false);
206        ControllerThread tt = new ControllerThread(sentinel);
207        tt.start();
208        // wait until controller threads are up and running.
209        try {
210          sentinel.waitAndClose();
211        } catch (Exception e) {
212          e.printStackTrace();
213          VM.sysFail("Failed to start up controller subsystem");
214        }
215      }
216    
217      /**
218       * Process any command line arguments passed to the controller subsystem.
219       * <p>
220       * This method has the responsibility of creating the options object
221       * if it does not already exist
222       * <p>
223       * NOTE: All command line argument processing should be handled via
224       * the automatically generated code in AOSOptions.java.
225       * Don't even think of adding handwritten stuff here! --dave
226       *
227       * @param arg the command line argument to be processed
228       */
229      public static void processCommandLineArg(String arg) {
230        if (!options.processAsOption("-X:aos", arg)) {
231          VM.sysWrite("vm: illegal adaptive configuration directive \"" + arg + "\" specified as -X:aos:" + arg + "\n");
232          VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
233        }
234      }
235    
236      /**
237       * This method is called when the VM is exiting to provide a hook to allow
238       * the adpative optimization subsystem to generate a summary report.
239       * It can also be called directly from driver programs to allow
240       * reporting on a single run of a benchmark that the driver program
241       * is executing in a loop (in which case the adaptive system isn't actually
242       * exiting.....so some of the log messages may get a little wierd).
243       */
244      public static void report() {
245        if (!booted) return;
246        ControllerThread.report();
247        RuntimeMeasurements.report();
248    
249        for (Enumeration<Organizer> e = organizers.elements(); e.hasMoreElements();) {
250          Organizer organizer = e.nextElement();
251          organizer.report();
252        }
253    
254        if (options.FINAL_REPORT_LEVEL >= 2) {
255          EdgeCounts.dumpCounts();
256          dcg.dumpGraph();
257        }
258    
259        if (options.REPORT_INTERRUPT_STATS) {
260          VM.sysWriteln("Timer Interrupt and Listener Stats");
261          VM.sysWriteln("\tTotal number of clock ticks ", RVMThread.timerTicks);
262          VM.sysWriteln("\tController clock ", controllerClock);
263          VM.sysWriteln("\tNumber of method samples taken ", (int) methodSamples.getTotalNumberOfSamples());
264        }
265      }
266    
267      /**
268       * Stop all AOS threads and exit the adaptive system.
269       * Can be used to assess code quality in a steady state by
270       * allowing the adaptive system to run "for a while" and then
271       * stopping it
272       */
273      public static void stop() {
274        if (!booted) return;
275    
276        VM.sysWriteln("AOS: Killing all adaptive system threads");
277        for (Enumeration<Organizer> e = organizers.elements(); e.hasMoreElements();) {
278          Organizer organizer = e.nextElement();
279          organizer.stop(threadDeath);
280        }
281        compilationThread.stop(threadDeath);
282        controllerThread.stop(threadDeath);
283        RuntimeMeasurements.stop();
284        report();
285      }
286    }
287