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