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 java.util.LinkedList;
016import org.jikesrvm.VM;
017import org.jikesrvm.adaptive.util.AOSGenerator;
018import org.jikesrvm.adaptive.util.AOSLogging;
019import org.jikesrvm.compilers.common.CompiledMethod;
020import org.jikesrvm.compilers.common.CompiledMethods;
021import org.jikesrvm.compilers.common.RuntimeCompiler;
022import org.jikesrvm.compilers.opt.driver.CompilationPlan;
023
024/**
025 * An instance of this class describes a compilation decision made by
026 * the controller.<p>
027 *
028 * Constraints: Given the plan list of a method:
029 * <ul>
030 *   <li>Only one plan will have status COMPLETED
031 *   <li>Multiple plans may have status OUTDATED
032 *   <li>Only one plan will have status IN_PROGRESS
033 * </ul>
034 * <p>
035 * status states:
036 * <pre>
037 * UNINITIALIZED -&gt; IN_PROGRESS -&gt; COMPLETED -&gt; OUTDATED
038 *             \              \--&gt; ABORTED_COMPILATION_ERROR (never recompile method)
039 * </pre>
040 */
041public final class ControllerPlan {
042
043  /** The plan was created, but the setStatus method was never called */
044  public static final byte UNINITIALIZED = 0;
045
046  /** The plan was successfully completed, i.e., the method was recompiled */
047  public static final byte COMPLETED = 1;
048
049  /** Compilation for the method was begun, but failed in an error */
050  public static final byte ABORTED_COMPILATION_ERROR = 2;
051
052  /** The compilation is still in progress */
053  public static final byte IN_PROGRESS = 3;
054
055  /** The compilation completed, but a new plan for the same method also
056    * completed, so this is not the most recent completed plan */
057  public static final byte OUTDATED = 4;
058
059  /** The compilation plan is for a promotion from BASE to OPT */
060  public static final byte OSR_BASE_2_OPT = 5;
061
062  /** This is used by clients to initialize local variables for Java semantics */
063  public static final byte UNKNOWN = 99;
064
065  /**
066   *  The associate compilation plan
067   */
068  private final CompilationPlan compPlan;
069
070  /**
071   *  The time we created this plan
072   */
073  private final int timeCreated;
074
075  /**
076   *  The time compilation began
077   */
078  private int timeInitiated = -1;
079
080  /**
081   *  The time compilation end
082   */
083  private int timeCompleted = -1;
084
085  /**
086   *  The speedup we were expecting
087   */
088  private final double expectedSpeedup;
089
090  /**
091   *  The compilation time we were expecting
092   */
093  private final double expectedCompilationTime;
094
095  /**
096   *  The priority associated with this plan
097   */
098  private final double priority;
099
100  /**
101   *  The compiled method ID for this plan
102   */
103  private int CMID;
104
105  /**
106   *  The compiled method ID for the previous plan for this method
107   */
108  private final int prevCMID;
109
110  /**
111   *  The status of this plan
112   */
113  private byte status;
114
115  /**
116   *  The list that we are onstatus of this plan
117   */
118  private LinkedList<ControllerPlan> planList;
119
120  /**
121   * Construct a controller plan
122   *
123   * @param compPlan     The compilation plan
124   * @param timeCreated  The "time" this plan was created
125   * @param prevCMID     The previous compiled method ID
126   * @param expectedSpeedup     Expected recompilation benefit
127   * @param expectedCompilationTime     Expected recompilation cost
128   * @param priority     How important is executing this plan?
129   */
130  public ControllerPlan(CompilationPlan compPlan, int timeCreated, int prevCMID, double expectedSpeedup,
131                           double expectedCompilationTime, double priority) {
132    this.compPlan = compPlan;
133    this.timeCreated = timeCreated;
134    this.prevCMID = prevCMID;
135    this.status = ControllerPlan.UNINITIALIZED;
136    this.expectedSpeedup = expectedSpeedup;
137    this.expectedCompilationTime = expectedCompilationTime;
138    this.priority = priority;
139  }
140
141  /**
142   * Execute the plan.
143   *
144   * @return {@code true} on success, {@code false} on failure
145   */
146  public boolean execute() {
147    // mark plan as in progress and insert it into controller memory
148    setStatus(ControllerPlan.IN_PROGRESS);
149    ControllerMemory.insert(this);
150
151    if (Controller.options
152        .BACKGROUND_RECOMPILATION ||
153                                  getCompPlan().getMethod().getDeclaringClass().isInBootImage()) {
154      Controller.compilationQueue.insert(getPriority(), this);
155      AOSLogging.logger.recompilationScheduled(getCompPlan(), getPriority());
156      return true;
157    } else {
158      getCompPlan().getMethod().replaceCompiledMethod(null);
159      return true;
160    }
161  }
162
163  /**
164   * This method will recompile the method designated by the controller plan
165   * {@link #getCompPlan}.  It also
166   * <ol>
167   *   <li>credits the samples associated with the old compiled method
168   *     ID to the new method ID and clears the old value.
169   *   <li>clears inlining information
170   *   <li>updates the status of the controller plan
171   * </ol>
172   *
173   * @return {@code null} if the compilation was aborted, the new compiled
174   *  method otherwise
175   */
176  public CompiledMethod doRecompile() {
177    CompilationPlan cp = getCompPlan();
178
179    setTimeInitiated(Controller.controllerClock);
180    AOSLogging.logger.recompilationStarted(cp);
181
182    if (cp.options.PRINT_METHOD) {
183      VM.sysWrite("-oc:O" + cp.options.getOptLevel() + " \n");
184    }
185
186    // Compile the method.
187    int newCMID = RuntimeCompiler.recompileWithOpt(cp);
188    int prevCMID = getPrevCMID();
189
190    if (Controller.options.sampling()) {
191      // transfer the samples from the old CMID to the new CMID.
192      // scale the number of samples down by the expected speedup
193      // in the newly compiled method.
194      double expectedSpeedup = getExpectedSpeedup();
195      double oldNumSamples = Controller.methodSamples.getData(prevCMID);
196      double newNumSamples = oldNumSamples / expectedSpeedup;
197      Controller.methodSamples.reset(prevCMID);
198      if (newCMID > -1) {
199        Controller.methodSamples.augmentData(newCMID, newNumSamples);
200      }
201    }
202
203    // set the status of the plan accordingly
204    if (newCMID != -1) {
205      setStatus(ControllerPlan.COMPLETED);
206    } else {
207      setStatus(ControllerPlan.ABORTED_COMPILATION_ERROR);
208    }
209
210    setCMID(newCMID);
211    setTimeCompleted(Controller.controllerClock);
212    CompiledMethod cm = newCMID == -1 ? null : CompiledMethods.getCompiledMethod(newCMID);
213    if (newCMID == -1) {
214      AOSLogging.logger.recompilationAborted(cp);
215    } else {
216      AOSLogging.logger.recompilationCompleted(cp);
217      AOSLogging.logger.recordCompileTime(cm, getExpectedCompilationTime());
218    }
219    if (Controller.options.ENABLE_ADVICE_GENERATION && (newCMID != -1)) {
220      AOSGenerator.reCompilationWithOpt(cp);
221    }
222    return cm;
223  }
224
225  /**
226   * @return the compilation plan
227   */
228  public CompilationPlan getCompPlan() {
229    return compPlan;
230  }
231
232  /**
233   * @return the expected speedup <em>for this method </em> due to this recompilation
234   */
235  public double getExpectedSpeedup() {
236    return expectedSpeedup;
237  }
238
239  /**
240   * @return the expected compilation time for this method
241   */
242  public double getExpectedCompilationTime() {
243    return expectedCompilationTime;
244  }
245
246  /**
247   * @return the priority (how important is it that this plan be executed)
248   */
249  public double getPriority() {
250    return priority;
251  }
252
253  /**
254   * @return the time this plan was created
255   */
256  public int getTimeCreated() {
257    return timeCreated;
258  }
259
260  /**
261   * @return the time (according to the controller clock) compilation of this plan
262   * began.
263   */
264  public int getTimeInitiated() {
265    return timeInitiated;
266  }
267
268  public void setTimeInitiated(int t) {
269    timeInitiated = t;
270  }
271
272  /**
273   * @return the time (according to the controller clock) compilation of this plan
274   * completed.
275   */
276  public int getTimeCompleted() {
277    return timeCompleted;
278  }
279
280  public void setTimeCompleted(int t) {
281    timeCompleted = t;
282  }
283
284  /**
285   * @return CMID (compiled method id) associated with the code produced
286   * by executing this plan
287   */
288  public int getCMID() {
289    return CMID;
290  }
291
292  public void setCMID(int x) {
293    CMID = x;
294  }
295
296  /**
297   * @return CMID (compiled method id) associated with the *PREVIOUS* compiled
298   * version of this method
299   */
300  public int getPrevCMID() {
301    return prevCMID;
302  }
303
304  /**
305   * @return status of this compilation plan, chosen from the values defined
306   *  in this class
307   */
308  public byte getStatus() {
309    return status;
310  }
311
312  public void setStatus(byte newStatus) {
313    status = newStatus;
314
315    // if we are marking this plan as completed, all previous completed plans
316    // for this method should be marked as OUTDATED
317    if (newStatus == COMPLETED) {
318      // iterate over the planList until we get to this item
319      synchronized (planList) {
320        for (ControllerPlan curPlan : planList) {
321          // exit when we find ourselves
322          if (curPlan == this) break;
323
324          if (curPlan.getStatus() == COMPLETED) {
325            curPlan.status = OUTDATED;
326          }
327        } // more to process
328      }
329    }
330  }
331
332  public void setPlanList(LinkedList<ControllerPlan> list) {
333    planList = list;
334  }
335
336  public String getStatusString() {
337    switch (status) {
338      case UNINITIALIZED:
339        return "UNINITIALIZED";
340      case COMPLETED:
341        return "COMPLETED";
342      case ABORTED_COMPILATION_ERROR:
343        return "ABORTED_COMPILATION_ERROR";
344      case IN_PROGRESS:
345        return "IN_PROGRESS";
346      case OUTDATED:
347        return "OUTDATED";
348      case OSR_BASE_2_OPT:
349        return "OSR_BASE_2_OPT";
350      case UNKNOWN:
351        return "UNKNOWN (not error)";
352      default:
353        return "**** ERROR, UNKNOWN STATUS ****";
354    }
355  }
356
357  @Override
358  public String toString() {
359    StringBuilder buf = new StringBuilder();
360
361    buf.append("Method: ").append(getCompPlan().method).append("\n\tCompiled Method ID: ").append(CMID).append(
362        "\n\tPrevious Compiled Method ID: ").append(prevCMID).append("\n\tCreated at ").append(timeCreated).append(
363        "\n\tInitiated at ").append(timeInitiated).append("\n\tCompleted at ").append(timeCompleted).append(
364        "\n\tExpected Speedup: ").append(expectedSpeedup).append("\n\tExpected Compilation Time: ").append(
365        expectedCompilationTime).append("\n\tPriority: ").append(priority).append("\n\tStatus: ").append(getStatusString()).append(
366        "\n\tComp. Plan Level: ").append(compPlan.options.getOptLevel()).append("\n");
367    return buf.toString();
368  }
369
370}