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.
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 null)
114 * @return 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 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(false, "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 optimiations
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