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