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 org.jikesrvm.VM; 016import org.jikesrvm.adaptive.recompilation.CompilerDNA; 017import org.jikesrvm.adaptive.util.AOSLogging; 018import org.jikesrvm.classloader.RVMMethod; 019import org.jikesrvm.classloader.NormalMethod; 020import org.jikesrvm.compilers.common.CompiledMethod; 021import org.jikesrvm.compilers.opt.OptOptions; 022import org.jikesrvm.compilers.opt.driver.CompilationPlan; 023import org.jikesrvm.compilers.opt.driver.InstrumentationPlan; 024import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 025import org.jikesrvm.compilers.opt.driver.OptimizationPlanner; 026import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod; 027 028/** 029 * An abstract class providing the interface to the decision making 030 * component of the controller. 031 */ 032public abstract class RecompilationStrategy { 033 034 //------ Interface ------- 035 036 ControllerPlan considerHotMethod(CompiledMethod cmpMethod, HotMethodEvent hme) { 037 // Default behavior, do nothing. 038 return null; 039 } 040 041 void considerHotCallEdge(CompiledMethod cmpMethod, AINewHotEdgeEvent event) { 042 // Default behavior, do nothing. 043 } 044 045 // Functionality common to all recompilation strategies 046 // (at least for now) 047 048 /** 049 * Initialize the recompilation strategy.<p> 050 * 051 * Note: This uses the command line options to set up the 052 * optimization plans, so this must be run after the command line 053 * options are available. 054 */ 055 void init() { 056 createOptimizationPlans(); 057 } 058 059 /** 060 * This helper method creates a ControllerPlan, which contains a 061 * CompilationPlan, for the passed method using the passed optimization 062 * level and instrumentation plan. 063 * 064 * @param method the RVMMethod for the plan 065 * @param optLevel the optimization level to use in the plan 066 * @param instPlan the instrumentation plan to use 067 * @param prevCMID the previous compiled method ID 068 * @param expectedSpeedup expected speedup from this recompilation 069 * @param expectedCompilationTime expected time for compilation 070 * and execution of the new method 071 * @param priority a measure of the oveall benefit we expect to see 072 * by executing this plan. 073 * @return the compilation plan to be used 074 */ 075 ControllerPlan createControllerPlan(RVMMethod method, int optLevel, InstrumentationPlan instPlan, int prevCMID, 076 double expectedSpeedup, double expectedCompilationTime, double priority) { 077 078 // Construct the compilation plan (varies depending on strategy) 079 CompilationPlan compPlan = createCompilationPlan((NormalMethod) method, optLevel, instPlan); 080 081 // Create the controller plan 082 return new ControllerPlan(compPlan, 083 Controller.controllerClock, 084 prevCMID, 085 expectedSpeedup, 086 expectedCompilationTime, 087 priority); 088 } 089 090 /** 091 * Constructs a compilation plan that will compile the given method 092 * with instrumentation. 093 * 094 * @param method The method to be compiled with instrumentation 095 * @param optLevel The opt-level to recompile at 096 * @param instPlan The instrumentation plan 097 * @return a non-{@code null} compilation plan 098 */ 099 public CompilationPlan createCompilationPlan(NormalMethod method, int optLevel, 100 InstrumentationPlan instPlan) { 101 102 // Construct a plan from the basic pre-computed opt-levels 103 return new CompilationPlan(method, _optPlans[optLevel], null, _options[optLevel]); 104 } 105 106 /** 107 * Should we consider the hme for recompilation? 108 * 109 * @param hme the HotMethodEvent 110 * @param plan the ControllerPlan for the compiled method (may be {@code null}) 111 * @return {@code true/false} value 112 */ 113 boolean considerForRecompilation(HotMethodEvent hme, ControllerPlan plan) { 114 RVMMethod method = hme.getMethod(); 115 if (plan == null) { 116 // Our caller did not find a matching plan for this compiled method. 117 // Therefore the code was not generated by the AOS recompilation subsystem. 118 if (ControllerMemory.shouldConsiderForInitialRecompilation(method)) { 119 // AOS has not already taken action to address the situation 120 // (or it attempted to take action, and the attempt failed in a way 121 // that doesn't preclude trying again, 122 // for example the compilation queue could have been full). 123 return true; 124 } else { 125 // AOS has already taken action to address the situation, and thus 126 // we need to handle this as an old compiled version of a 127 // method still being live on some thread's stack. 128 transferSamplesToNewPlan(hme); 129 return false; 130 } 131 } else { 132 // A matching plan was found. 133 if (plan.getStatus() == ControllerPlan.OUTDATED || 134 ControllerMemory.planWithStatus(method, ControllerPlan.IN_PROGRESS)) { 135 // (a) The HotMethodEvent actually corresponds to an 136 // old compiled version of the method 137 // that is still live on some thread's stack or 138 // (b) AOS has already initiated a plan that hasn't 139 // completed yet to address the situation. 140 // Therefore don't initiate a new recompilation action. 141 transferSamplesToNewPlan(hme); 142 return false; 143 } 144 // if AOS failed to successfully recompile this method before. 145 // Don't try it again. 146 return !ControllerMemory.planWithStatus(method, ControllerPlan.ABORTED_COMPILATION_ERROR); 147 } 148 } 149 150 private void transferSamplesToNewPlan(HotMethodEvent hme) { 151 AOSLogging.logger.oldVersionStillHot(hme); 152 double oldNumSamples = Controller.methodSamples.getData(hme.getCMID()); 153 ControllerPlan activePlan = ControllerMemory.findLatestPlan(hme.getMethod()); 154 if (activePlan == null) return; // shouldn't happen. 155 int newCMID = activePlan.getCMID(); 156 if (newCMID > 0) { 157 // If we have a valid CMID then transfer the samples. 158 // If the CMID isn't valid, it means the compilation hasn't completed yet and 159 // the samples will be transfered by the compilation thread when it does (so we do nothing). 160 Controller.methodSamples.reset(hme.getCMID()); 161 double expectedSpeedup = activePlan.getExpectedSpeedup(); 162 double newNumSamples = oldNumSamples / expectedSpeedup; 163 Controller.methodSamples.augmentData(newCMID, newNumSamples); 164 } 165 } 166 167 /** 168 * This method returns {@code true} if we've already tried to recompile the 169 * passed method. It does not guarantee that the compilation was 170 * successful. 171 * 172 * @param method the method of interest 173 * @return whether we've tried to recompile this method 174 */ 175 boolean previousRecompilationAttempted(RVMMethod method) { 176 return ControllerMemory.findLatestPlan(method) != null; 177 } 178 179 /** 180 * @param cmpMethod the compiled method whose previous compiler we want to know 181 * @return the constant for the previous compiler 182 */ 183 int getPreviousCompiler(CompiledMethod cmpMethod) { 184 switch (cmpMethod.getCompilerType()) { 185 case CompiledMethod.TRAP: 186 case CompiledMethod.JNI: 187 return -1; // don't try to optimize these guys! 188 case CompiledMethod.BASELINE: { 189 // Prevent the adaptive system from recompiling certain classes 190 // of baseline compiled methods. 191 if (cmpMethod.getMethod().getDeclaringClass().hasDynamicBridgeAnnotation()) { 192 // The opt compiler does not implement this calling convention. 193 return -1; 194 } 195 if (cmpMethod.getMethod().getDeclaringClass().hasBridgeFromNativeAnnotation()) { 196 // The opt compiler does not implement this calling convention. 197 return -1; 198 } 199 if (cmpMethod.getMethod().hasNoOptCompileAnnotation()) { 200 // Explict declaration that the method should not be opt compiled. 201 return -1; 202 } 203 if (!cmpMethod.getMethod().isInterruptible()) { 204 // A crude filter to identify the subset of core VM methods that 205 // can't be recompiled because we require their code to be non-moving. 206 // We really need to do a better job of this to avoid missing too many opportunities. 207 // NOTE: it doesn't matter whether or not the GC is non-moving here, 208 // because recompiling effectively moves the code to a new location even if 209 // GC never moves it again!!! 210 // (C code may have a return address or other naked pointer into the old instruction array) 211 return -1; 212 } 213 return 0; 214 } 215 case CompiledMethod.OPT: 216 OptCompiledMethod optMeth = (OptCompiledMethod) cmpMethod; 217 return CompilerDNA.getCompilerConstant(optMeth.getOptLevel()); 218 default: 219 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED, "Unknown Compiler"); 220 return -1; 221 } 222 } 223 224 /** 225 * @return is the maximum opt level that is valid according to this strategy 226 */ 227 int getMaxOptLevel() { 228 return Controller.options.DERIVED_MAX_OPT_LEVEL; 229 } 230 231 private OptimizationPlanElement[][] _optPlans; 232 private OptOptions[] _options; 233 234 /** 235 * Creates the default set of <optimization plan, options> pairs. 236 * Processes optimizing compiler command line options. 237 */ 238 void createOptimizationPlans() { 239 OptOptions options = new OptOptions(); 240 241 int maxOptLevel = getMaxOptLevel(); 242 _options = new OptOptions[maxOptLevel + 1]; 243 _optPlans = new OptimizationPlanElement[maxOptLevel + 1][]; 244 String[] optCompilerOptions = Controller.getOptCompilerOptions(); 245 for (int i = 0; i <= maxOptLevel; i++) { 246 _options[i] = options.dup(); 247 _options[i].setOptLevel(i); // set optimization level specific optimizations 248 processCommandLineOptions(_options[i], i, maxOptLevel, optCompilerOptions); 249 _optPlans[i] = OptimizationPlanner.createOptimizationPlan(_options[i]); 250 } 251 } 252 253 /** 254 * Process the command line arguments and pass the appropriate ones to the 255 * Options 256 * Called by sampling and counters recompilation strategy. 257 * 258 * @param options The options being constructed 259 * @param optLevel The level of the options being constructed 260 * @param maxOptLevel The maximum valid opt level 261 * @param optCompilerOptions The list of command line options 262 */ 263 public static void processCommandLineOptions(OptOptions options, int optLevel, int maxOptLevel, 264 String[] optCompilerOptions) { 265 266 String prefix = "opt" + optLevel + ":"; 267 for (String optCompilerOption : optCompilerOptions) { 268 if (optCompilerOption.startsWith("opt:")) { 269 String option = optCompilerOption.substring(4); 270 if (!options.processAsOption("-X:recomp:", option)) { 271 VM.sysWrite("vm: Unrecognized optimizing compiler command line argument: \"" + 272 option + 273 "\" passed in as " + 274 optCompilerOption + 275 "\n"); 276 } 277 } else if (optCompilerOption.startsWith(prefix)) { 278 String option = optCompilerOption.substring(5); 279 if (!options.processAsOption("-X:recomp:" + prefix, option)) { 280 VM.sysWrite("vm: Unrecognized optimizing compiler command line argument: \"" + 281 option + 282 "\" passed in as " + 283 optCompilerOption + 284 "\n"); 285 } 286 } 287 } 288 // TODO: check for optimization levels that are invalid; that is, 289 // greater than optLevelMax. 290 // 291 for (String optCompilerOption1 : optCompilerOptions) { 292 if (!optCompilerOption1.startsWith("opt")) { 293 // This should never be the case! 294 continue; 295 } 296 if (!optCompilerOption1.startsWith("opt:")) { 297 // must specify optimization level! 298 int endPoint = optCompilerOption1.indexOf(':'); 299 if (endPoint == -1) { 300 VM.sysWrite("vm: Unrecognized optimization level in optimizing compiler command line argument: \"" + 301 optCompilerOption1 + 302 "\"\n"); 303 } 304 String optLevelS; 305 try { 306 optLevelS = optCompilerOption1.substring(3, endPoint); 307 } catch (IndexOutOfBoundsException e) { 308 VM.sysWrite("vm internal error: trying to find opt level has thrown indexOutOfBoundsException\n"); 309 e.printStackTrace(); 310 continue; 311 } 312 try { 313 Integer optLevelI = Integer.valueOf(optLevelS); 314 int cmdOptLevel = optLevelI; 315 if (cmdOptLevel > maxOptLevel) { 316 VM.sysWrite("vm: Invalid optimization level in optimizing compiler command line argument: \"" + 317 optCompilerOption1 + 318 "\"\n" + 319 " Specified optimization level " + 320 cmdOptLevel + 321 " must be less than " + 322 maxOptLevel + 323 "\n"); 324 } 325 } catch (NumberFormatException e) { 326 VM.sysWrite("vm: Unrecognized optimization level in optimizing compiler command line argument: \"" + 327 optCompilerOption1 + 328 "\"\n"); 329 } 330 } 331 } 332 } 333} 334 335 336 337