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}