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 org.jikesrvm.VM;
017 import org.jikesrvm.adaptive.OnStackReplacementEvent;
018 import org.jikesrvm.adaptive.OSROrganizerThread;
019 import org.jikesrvm.adaptive.database.methodsamples.MethodCountData;
020 import org.jikesrvm.adaptive.measurements.listeners.EdgeListener;
021 import org.jikesrvm.adaptive.measurements.listeners.YieldCounterListener;
022 import org.jikesrvm.adaptive.measurements.organizers.AccumulatingMethodSampleOrganizer;
023 import org.jikesrvm.adaptive.measurements.organizers.DecayOrganizer;
024 import org.jikesrvm.adaptive.measurements.organizers.DynamicCallGraphOrganizer;
025 import org.jikesrvm.adaptive.measurements.organizers.MethodSampleOrganizer;
026 import org.jikesrvm.adaptive.measurements.organizers.Organizer;
027 import org.jikesrvm.adaptive.recompilation.CompilationThread;
028 import org.jikesrvm.adaptive.recompilation.CompilerDNA;
029 import org.jikesrvm.adaptive.recompilation.InvocationCounts;
030 import org.jikesrvm.adaptive.util.AOSGenerator;
031 import org.jikesrvm.adaptive.util.AOSLogging;
032 import org.jikesrvm.adaptive.util.AOSOptions;
033 import org.jikesrvm.scheduler.RVMThread;
034 import org.jikesrvm.scheduler.SoftLatch;
035 import org.vmmagic.pragma.NonMoving;
036
037 /**
038 * This class implements the controller thread. This entity is the brains of
039 * the adaptive optimization system. It communicates with the runtime
040 * measurements subsystem to instruct and gather profiling information.
041 * It also talks to the compilation threads to generate
042 * a) instrumented executables;
043 * b) optimized executables;
044 * c) static information about a method; or
045 * d) all of the above.
046 */
047 @NonMoving
048 public final class ControllerThread extends RVMThread {
049
050 /**
051 * constructor
052 * @param sentinel An object to signal when up and running
053 */
054 ControllerThread(SoftLatch sentinel) {
055 super("ControllerThread");
056 this.sentinel = sentinel;
057 makeDaemon(true);
058 }
059
060 private final SoftLatch sentinel;
061
062 /**
063 * There are several ways in which a dcg organizer might
064 * be created; keep track of it once it is created so that
065 * we only create one instance of it.
066 */
067 private DynamicCallGraphOrganizer dcgOrg;
068
069 /**
070 * This method is the entry point to the controller, it is called when
071 * the controllerThread is created.
072 */
073 public void run() {
074 // save this object so others can access it, if needed
075 Controller.controllerThread = this;
076
077 // Bring up the logging system
078 AOSLogging.logger.boot();
079 if (Controller.options.ENABLE_ADVICE_GENERATION) {
080 AOSGenerator.boot();
081 }
082
083 // Create measurement entities that are NOT related to
084 // adaptive recompilation
085 createProfilers();
086
087 if (!Controller.options.ENABLE_RECOMPILATION) {
088 // We're running an AOS bootimage with a non-adaptive primary strategy.
089 // We already set up any requested profiling infrastructure, so nothing
090 // left to do but exit.
091 controllerInitDone();
092 VM.sysWriteln("AOS: In non-adaptive mode; controller thread exiting.");
093 return; // controller thread exits.
094 }
095
096 if ((Controller.options.ENABLE_REPLAY_COMPILE) || (Controller.options.ENABLE_PRECOMPILE)) {
097 // if we want to do precompile, we need to initial optimization plans
098 // just allow the advice to be the max opt level 2
099 Controller.options.DERIVED_MAX_OPT_LEVEL = 2;
100 if (Controller.options.sampling()) {
101 // Create our set of standard optimization plans.
102 Controller.recompilationStrategy.init();
103 } else if (Controller.options.counters()) {
104 InvocationCounts.init();
105 }
106 Controller.osrOrganizer = new OSROrganizerThread();
107 Controller.osrOrganizer.start();
108 createCompilationThread();
109 // We're running an AOS bootimage with a non-adaptive primary strategy.
110 // We already set up any requested profiling infrastructure, so nothing
111 // left to do but exit.
112 controllerInitDone();
113 // to have a fair comparison, we need to create the data structures
114 // of organizers
115 createOrganizerThreads();
116 VM.sysWriteln("AOS: In replay mode; controller thread only runs for OSR inlining.");
117 while (true) {
118 if (Controller.options.EARLY_EXIT && Controller.options.EARLY_EXIT_TIME < Controller.controllerClock) {
119 Controller.stop();
120 }
121 Object event = Controller.controllerInputQueue.deleteMin();
122 ((OnStackReplacementEvent) event).process();
123 }
124
125 }
126
127 // Initialize the CompilerDNA class
128 // This computes some internal options, must be done early in boot process
129 CompilerDNA.init();
130
131 // Create the organizerThreads and schedule them
132 createOrganizerThreads();
133
134 // Create the compilationThread and schedule it
135 createCompilationThread();
136
137 if (Controller.options.sampling()) {
138 // Create our set of standard optimization plans.
139 Controller.recompilationStrategy.init();
140 } else if (Controller.options.counters()) {
141 InvocationCounts.init();
142
143 }
144
145 controllerInitDone();
146
147 // Enter main controller loop.
148 // Pull an event to process off of
149 // Controller.controllerInputQueue and handle it.
150 // If no events are on the queue, then the deleteMin call will
151 // block until an event is available.
152 // Repeat forever.
153 while (true) {
154 if (Controller.options.EARLY_EXIT && Controller.options.EARLY_EXIT_TIME < Controller.controllerClock) {
155 Controller.stop();
156 }
157 Object event = Controller.controllerInputQueue.deleteMin();
158 ((ControllerInputEvent) event).process();
159 }
160 }
161
162 // Now that we're done initializing, Schedule all the organizer threads
163 // and signal the sentinel object.
164 private void controllerInitDone() {
165 for (Enumeration<Organizer> e = Controller.organizers.elements(); e.hasMoreElements();) {
166 Organizer o = e.nextElement();
167 o.start();
168 }
169 try {
170 sentinel.open();
171 } catch (Exception e) {
172 e.printStackTrace();
173 VM.sysFail("Failed to start up controller subsystem");
174 }
175 }
176
177 /**
178 * Called when the controller thread is about to wait on
179 * Controller.controllerInputQueue
180 */
181 public void aboutToWait() {
182 }
183
184 /**
185 * Called when the controller thread is woken after waiting on
186 * Controller.controllerInputQueue
187 */
188 public void doneWaiting() {
189 ControllerMemory.incrementNumAwoken();
190 }
191
192 /**
193 * If we're going to be gathering a dynamic call graph, then we don't
194 * want to let the opt compiler compile anything above O0 until we have
195 * some initial data in the call graph to work with. The goal of this
196 * restriction is to avoid making early bad decisions that we don't get
197 * a chance to revisit because methods get to maxOptLevel too quickly.
198 */
199 public boolean earlyRestrictOptLevels() {
200 return dcgOrg != null && !dcgOrg.someDataAvailable();
201 }
202
203 ///////////////////////
204 // Initialization.
205 // Create AOS threads.
206 // Initialize AOS data structures that depend on command line arguments.
207 ///////////////////////
208
209 /**
210 * Create the compilationThread and schedule it
211 */
212 private void createCompilationThread() {
213 CompilationThread ct = new CompilationThread();
214 Controller.compilationThread = ct;
215 ct.start();
216 }
217
218 /**
219 * Create a dynamic call graph organizer of one doesn't already exist
220 */
221 private void createDynamicCallGraphOrganizer() {
222 if (dcgOrg == null) {
223 dcgOrg = new DynamicCallGraphOrganizer(new EdgeListener());
224 Controller.organizers.addElement(dcgOrg);
225 }
226 }
227
228 /**
229 * Create profiling entities that are independent of whether or not
230 * adaptive recompilation is actually enabled.
231 */
232 private void createProfilers() {
233 AOSOptions opts = Controller.options;
234
235 if (opts.GATHER_PROFILE_DATA) {
236 Controller.organizers.addElement(new AccumulatingMethodSampleOrganizer());
237
238 createDynamicCallGraphOrganizer();
239 }
240 }
241
242 /**
243 * Create the organizerThreads and schedule them
244 */
245 private void createOrganizerThreads() {
246 AOSOptions opts = Controller.options;
247
248 if (opts.sampling()) {
249 // Primary backing store for method sample data
250 Controller.methodSamples = new MethodCountData();
251
252 // Install organizer to drive method recompilation
253 Controller.organizers.addElement(new MethodSampleOrganizer(opts.DERIVED_FILTER_OPT_LEVEL));
254 // Additional set up for feedback directed inlining
255 if (opts.ADAPTIVE_INLINING) {
256 Organizer decayOrganizer = new DecayOrganizer(new YieldCounterListener(opts.DECAY_FREQUENCY));
257 Controller.organizers.addElement(decayOrganizer);
258 createDynamicCallGraphOrganizer();
259 }
260 }
261
262 if ((!Controller.options.ENABLE_REPLAY_COMPILE) && (!Controller.options.ENABLE_PRECOMPILE)) {
263 Controller.osrOrganizer = new OSROrganizerThread();
264 Controller.osrOrganizer.start();
265 }
266 }
267
268 /**
269 * Final report
270 */
271 public static void report() {
272 AOSLogging.logger.printControllerStats();
273 }
274
275 }