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.SoftLatch;
034    import org.jikesrvm.scheduler.SystemThread;
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     * <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
050    public 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      public boolean earlyRestrictOptLevels() {
204        return dcgOrg != null && !dcgOrg.someDataAvailable();
205      }
206    
207      ///////////////////////
208      // Initialization.
209      //  Create AOS threads.
210      //  Initialize AOS data structures that depend on command line arguments.
211      ///////////////////////
212    
213      /**
214       *  Create the compilationThread and schedule it
215       */
216      private void createCompilationThread() {
217        CompilationThread ct = new CompilationThread();
218        Controller.compilationThread = ct;
219        ct.start();
220      }
221    
222      /**
223       * Create a dynamic call graph organizer of one doesn't already exist
224       */
225      private void createDynamicCallGraphOrganizer() {
226        if (dcgOrg == null) {
227          dcgOrg = new DynamicCallGraphOrganizer(new EdgeListener());
228          Controller.organizers.addElement(dcgOrg);
229        }
230      }
231    
232      /**
233       * Create profiling entities that are independent of whether or not
234       * adaptive recompilation is actually enabled.
235       */
236      private void createProfilers() {
237        AOSOptions opts = Controller.options;
238    
239        if (opts.GATHER_PROFILE_DATA) {
240          Controller.organizers.addElement(new AccumulatingMethodSampleOrganizer());
241    
242          createDynamicCallGraphOrganizer();
243        }
244      }
245    
246      /**
247       *  Create the organizerThreads and schedule them
248       */
249      private void createOrganizerThreads() {
250        AOSOptions opts = Controller.options;
251    
252        if (opts.sampling()) {
253          // Primary backing store for method sample data
254          Controller.methodSamples = new MethodCountData();
255    
256          // Install organizer to drive method recompilation
257          Controller.organizers.addElement(new MethodSampleOrganizer(opts.DERIVED_FILTER_OPT_LEVEL));
258          // Additional set up for feedback directed inlining
259          if (opts.ADAPTIVE_INLINING) {
260            Organizer decayOrganizer = new DecayOrganizer(new YieldCounterListener(opts.DECAY_FREQUENCY));
261            Controller.organizers.addElement(decayOrganizer);
262            createDynamicCallGraphOrganizer();
263          }
264        }
265    
266        if ((!Controller.options.ENABLE_PRECOMPILE) && (!Controller.options.ENABLE_BULK_COMPILE)) {
267          Controller.osrOrganizer = new OSROrganizerThread();
268          Controller.osrOrganizer.start();
269        }
270      }
271    
272      /**
273       * Final report
274       */
275      public static void report() {
276        AOSLogging.logger.printControllerStats();
277      }
278    
279    }