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 }