/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.adaptive.controller; import java.util.Enumeration; import org.jikesrvm.VM; import org.jikesrvm.adaptive.OnStackReplacementEvent; import org.jikesrvm.adaptive.OSROrganizerThread; import org.jikesrvm.adaptive.database.methodsamples.MethodCountData; import org.jikesrvm.adaptive.measurements.listeners.EdgeListener; import org.jikesrvm.adaptive.measurements.listeners.YieldCounterListener; import org.jikesrvm.adaptive.measurements.organizers.AccumulatingMethodSampleOrganizer; import org.jikesrvm.adaptive.measurements.organizers.DecayOrganizer; import org.jikesrvm.adaptive.measurements.organizers.DynamicCallGraphOrganizer; import org.jikesrvm.adaptive.measurements.organizers.MethodSampleOrganizer; import org.jikesrvm.adaptive.measurements.organizers.Organizer; import org.jikesrvm.adaptive.recompilation.CompilationThread; import org.jikesrvm.adaptive.recompilation.CompilerDNA; import org.jikesrvm.adaptive.recompilation.InvocationCounts; import org.jikesrvm.adaptive.util.AOSExternalOptions; import org.jikesrvm.adaptive.util.AOSGenerator; import org.jikesrvm.adaptive.util.AOSLogging; import org.jikesrvm.adaptive.util.AOSOptions; import org.jikesrvm.scheduler.SoftLatch; import org.jikesrvm.scheduler.SystemThread; import org.vmmagic.pragma.NonMoving; /** * This class implements the controller thread. This entity is the brains of * the adaptive optimization system. It communicates with the runtime * measurements subsystem to instruct and gather profiling information. * It also talks to the compilation threads to generate * <ul> * <li>instrumented executables; * <li>optimized executables; * <li>static information about a method; or * <li>all of the above. * </ul> */ @NonMoving public final class ControllerThread extends SystemThread { /** * constructor * @param sentinel An object to signal when up and running */ ControllerThread(SoftLatch sentinel) { super("ControllerThread"); this.sentinel = sentinel; } private final SoftLatch sentinel; /** * There are several ways in which a dcg organizer might * be created; keep track of it once it is created so that * we only create one instance of it. */ private DynamicCallGraphOrganizer dcgOrg; /** * This method is the entry point to the controller, it is called when * the controllerThread is created. */ @Override public void run() { // save this object so others can access it, if needed Controller.controllerThread = this; // Cache option object because it'll be accessed often AOSExternalOptions opts = Controller.options; // Bring up the logging system AOSLogging.logger.boot(); if (opts.ENABLE_ADVICE_GENERATION) { AOSGenerator.boot(); } // Create measurement entities that are NOT related to // adaptive recompilation createProfilers(); if (!opts.ENABLE_RECOMPILATION) { // We're running an AOS bootimage with a non-adaptive primary strategy. // We already set up any requested profiling infrastructure, so nothing // left to do but exit. if (opts.ENABLE_BULK_COMPILE || opts.ENABLE_PRECOMPILE) { Controller.options.DERIVED_MAX_OPT_LEVEL = 2; Controller.recompilationStrategy.init(); } controllerInitDone(); AOSLogging.logger.reportThatAOSIsInNonAdaptiveMode(); return; // controller thread exits. } if (opts.ENABLE_PRECOMPILE) { if (Controller.options.sampling()) { // Create our set of standard optimization plans. Controller.recompilationStrategy.init(); } else if (Controller.options.counters()) { InvocationCounts.init(); } Controller.osrOrganizer = new OSROrganizerThread(); Controller.osrOrganizer.start(); createCompilationThread(); // We're running an AOS bootimage with a non-adaptive primary strategy. // We already set up any requested profiling infrastructure, so nothing // left to do but exit. controllerInitDone(); // to have a fair comparison, we need to create the data structures // of organizers createOrganizerThreads(); AOSLogging.logger.reportThatAOSIsInReplayMode(); while (true) { if (opts.EARLY_EXIT && opts.EARLY_EXIT_TIME < Controller.controllerClock) { Controller.stop(); } Object event = Controller.controllerInputQueue.deleteMin(); ((OnStackReplacementEvent) event).process(); } } // Initialize the CompilerDNA class // This computes some internal options, must be done early in boot process CompilerDNA.init(); // Create the organizerThreads and schedule them createOrganizerThreads(); // Create the compilationThread and schedule it createCompilationThread(); if (Controller.options.sampling()) { // Create our set of standard optimization plans. Controller.recompilationStrategy.init(); } else if (Controller.options.counters()) { InvocationCounts.init(); } controllerInitDone(); // Enter main controller loop. // Pull an event to process off of // Controller.controllerInputQueue and handle it. // If no events are on the queue, then the deleteMin call will // block until an event is available. // Repeat forever. while (true) { if (opts.EARLY_EXIT && opts.EARLY_EXIT_TIME < Controller.controllerClock) { Controller.stop(); } Object event = Controller.controllerInputQueue.deleteMin(); ((ControllerInputEvent) event).process(); } } /** * Now that the controller is initialized, schedule all the organizer threads * and signal the sentinel object. */ private void controllerInitDone() { for (Enumeration<Organizer> e = Controller.organizers.elements(); e.hasMoreElements();) { Organizer o = e.nextElement(); o.start(); } try { sentinel.open(); } catch (Exception e) { e.printStackTrace(); VM.sysFail("Failed to start up controller subsystem"); } } /** * Called when the controller thread is about to wait on * Controller.controllerInputQueue */ public void aboutToWait() { } /** * Called when the controller thread is woken after waiting on * Controller.controllerInputQueue */ public void doneWaiting() { ControllerMemory.incrementNumAwoken(); } /** * If we're going to be gathering a dynamic call graph, then we don't * want to let the opt compiler compile anything above O0 until we have * some initial data in the call graph to work with. The goal of this * restriction is to avoid making early bad decisions that we don't get * a chance to revisit because methods get to maxOptLevel too quickly. * * @return {@code true} if we need to restrict the optimization levels * to ensure that we don't make bad optimization decisions, {@code false} * if no restriction is necessary */ public boolean earlyRestrictOptLevels() { return dcgOrg != null && !dcgOrg.someDataAvailable(); } /////////////////////// // Initialization. // Create AOS threads. // Initialize AOS data structures that depend on command line arguments. /////////////////////// /** * Creates and schedules the compilationThread. */ private void createCompilationThread() { CompilationThread ct = new CompilationThread(); Controller.compilationThread = ct; ct.start(); } /** * Create a dynamic call graph organizer of one doesn't already exist */ private void createDynamicCallGraphOrganizer() { if (dcgOrg == null) { dcgOrg = new DynamicCallGraphOrganizer(new EdgeListener()); Controller.organizers.add(dcgOrg); } } /** * Create profiling entities that are independent of whether or not * adaptive recompilation is actually enabled. */ private void createProfilers() { if (Controller.options.GATHER_PROFILE_DATA) { Controller.organizers.add(new AccumulatingMethodSampleOrganizer()); createDynamicCallGraphOrganizer(); } } /** * Create the organizerThreads and schedule them */ private void createOrganizerThreads() { AOSOptions opts = Controller.options; if (opts.sampling()) { // Primary backing store for method sample data Controller.methodSamples = new MethodCountData(); // Install organizer to drive method recompilation Controller.organizers.add(new MethodSampleOrganizer(opts.DERIVED_FILTER_OPT_LEVEL)); // Additional set up for feedback directed inlining if (opts.ADAPTIVE_INLINING) { Organizer decayOrganizer = new DecayOrganizer(new YieldCounterListener(opts.DECAY_FREQUENCY)); Controller.organizers.add(decayOrganizer); createDynamicCallGraphOrganizer(); } } if ((!opts.ENABLE_PRECOMPILE) && (!opts.ENABLE_BULK_COMPILE)) { Controller.osrOrganizer = new OSROrganizerThread(); Controller.osrOrganizer.start(); } } /** * Final report */ public static void report() { AOSLogging.logger.printControllerStats(); } }