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.osr;
014
015 import org.jikesrvm.VM;
016 import org.jikesrvm.Callbacks;
017 import org.jikesrvm.adaptive.controller.Controller;
018 import org.jikesrvm.adaptive.controller.ControllerMemory;
019 import org.jikesrvm.adaptive.controller.ControllerPlan;
020 import org.jikesrvm.adaptive.recompilation.InvocationCounts;
021 import org.jikesrvm.adaptive.util.AOSLogging;
022 import org.jikesrvm.adaptive.util.CompilerAdviceAttribute;
023 import org.jikesrvm.compilers.common.CompiledMethod;
024 import org.jikesrvm.compilers.common.CompiledMethods;
025 import org.jikesrvm.compilers.common.RuntimeCompiler;
026 import org.jikesrvm.compilers.opt.driver.CompilationPlan;
027 import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
028
029 /**
030 * Maintain statistic information about on stack replacement events
031 */
032 public class OSRProfiler implements Callbacks.ExitMonitor {
033
034 private static int invalidations = 0;
035 private static boolean registered = false;
036
037 public void notifyExit(int value) {
038 VM.sysWriteln("OSR invalidations " + invalidations);
039 }
040
041 // we know which assumption is invalidated
042 // current we only reset the root caller method to be recompiled.
043 public static void notifyInvalidation(ExecutionState state) {
044
045 if (!registered && VM.MeasureCompilation) {
046 registered = true;
047 Callbacks.addExitMonitor(new OSRProfiler());
048 }
049
050 if (VM.TraceOnStackReplacement || VM.MeasureCompilation) {
051 OSRProfiler.invalidations++;
052 }
053
054 // find the root state
055 while (state.callerState != null) {
056 state = state.callerState;
057 }
058
059 // only invalidate the root state
060 invalidateState(state);
061 }
062
063 // invalidate an execution state
064 private static synchronized void invalidateState(ExecutionState state) {
065 // step 1: invalidate the compiled method with this OSR assumption
066 // how does this affect the performance?
067 CompiledMethod mostRecentlyCompiledMethod = CompiledMethods.getCompiledMethod(state.cmid);
068
069 if (VM.VerifyAssertions) {
070 VM._assert(mostRecentlyCompiledMethod.getMethod() == state.meth);
071 }
072
073 // check if the compiled method is the latest still the latest one
074 // this is necessary to check because the same compiled method may
075 // be invalidated in more than one thread at the same time
076 if (mostRecentlyCompiledMethod != state.meth.getCurrentCompiledMethod()) {
077 return;
078 }
079
080 // make sure the compiled method is an opt one
081 if (!(mostRecentlyCompiledMethod instanceof OptCompiledMethod)) {
082 return;
083 }
084
085 // reset the compiled method to null first, if other thread invokes
086 // this method before following opt recompilation, it can avoid OSR
087 state.meth.invalidateCompiledMethod(mostRecentlyCompiledMethod);
088
089 // a list of state from callee -> caller
090 if (VM.TraceOnStackReplacement) {
091 VM.sysWriteln("OSR " + OSRProfiler.invalidations + " : " + state.bcIndex + "@" + state.meth);
092 }
093
094 // simply reset the compiled method to null is not good
095 // for long run loops, because invalidate may cause
096 // the method falls back to the baseline again...
097 // NOW, we look for the previous compilation plan, and reuse
098 // the compilation plan.
099 boolean recmplsucc = false;
100 if (Controller.enabled) {
101 CompilationPlan cmplplan = null;
102 if ((Controller.options.ENABLE_REPLAY_COMPILE || Controller.options.ENABLE_PRECOMPILE) &&
103 CompilerAdviceAttribute.hasAdvice()) {
104 CompilerAdviceAttribute attr = CompilerAdviceAttribute.getCompilerAdviceInfo(state.meth);
105 if (VM.VerifyAssertions) {
106 VM._assert(attr.getCompiler() == CompiledMethod.OPT);
107 }
108 if (Controller.options.counters()) {
109 // for invocation counter, we only use one optimization level
110 cmplplan = InvocationCounts.createCompilationPlan(state.meth);
111 } else {
112 // for now there is not two options for sampling, so
113 // we don't have to use: if (Controller.options.sampling())
114 cmplplan = Controller.recompilationStrategy.createCompilationPlan(state.meth, attr.getOptLevel(), null);
115 }
116 } else {
117 ControllerPlan ctrlplan = ControllerMemory.findMatchingPlan(mostRecentlyCompiledMethod);
118 if (ctrlplan != null) {
119 cmplplan = ctrlplan.getCompPlan();
120 }
121 }
122 if (cmplplan != null) {
123 if (VM.VerifyAssertions) {VM._assert(cmplplan.getMethod() == state.meth);}
124
125 // for invalidated method, we donot perform OSR guarded inlining anymore.
126 // the Options object may be shared by several methods,
127 // we have to reset it back
128 boolean savedOsr = cmplplan.options.OSR_GUARDED_INLINING;
129 cmplplan.options.OSR_GUARDED_INLINING = false;
130 int newcmid = RuntimeCompiler.recompileWithOpt(cmplplan);
131 cmplplan.options.OSR_GUARDED_INLINING = savedOsr;
132
133 if (newcmid != -1) {
134 AOSLogging.logger.debug("recompiling state with opt succeeded " + state.cmid);
135 AOSLogging.logger.debug("new cmid " + newcmid);
136
137 // transfer hotness to the new cmid
138 double oldSamples = Controller.methodSamples.getData(state.cmid);
139 Controller.methodSamples.reset(state.cmid);
140 Controller.methodSamples.augmentData(newcmid, oldSamples);
141
142 recmplsucc = true;
143 if (VM.TraceOnStackReplacement) {
144 VM.sysWriteln(" recompile " + state.meth + " at -O" + cmplplan.options.getOptLevel());
145 }
146 }
147 }
148 }
149
150 if (!recmplsucc) {
151 int newcmid = RuntimeCompiler.recompileWithOpt(state.meth);
152 if (newcmid == -1) {
153 if (VM.TraceOnStackReplacement) {VM.sysWriteln(" opt recompilation failed!");}
154 state.meth.invalidateCompiledMethod(mostRecentlyCompiledMethod);
155 }
156 }
157
158 if (VM.TraceOnStackReplacement) {VM.sysWriteln(" opt recompilation done!");}
159 }
160 }