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