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    }