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