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