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