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.adaptive.recompilation.CompilerDNA;
016    import org.jikesrvm.compilers.common.CompiledMethod;
017    
018    /**
019     * Implements the multi-level adaptive strategy using an analytic
020     * model, as described in the OOPSLA 2000 paper.  Most behavior
021     * inherited from AnalyticModel.  This class defines the the specific
022     * recompilation choices that should be considered by the analytic model.
023     */
024    class MultiLevelAdaptiveModel extends AnalyticModel {
025    
026      /**
027       * List of all opt-level choices that can be considered by the
028       * cost-benefit model
029       */
030      protected RecompileOptChoice[] allOptLevelChoices;
031    
032      /**
033       * Keep a map from previous compiler to a set of recompilation
034       * choices.  After initialization, viableChoices[x][y] means that if
035       * x is the previous compiler, y makes sense as a possible
036       * recompilation choice.
037       */
038      protected RecompilationChoice[][] viableChoices;
039    
040      /**
041       * Normally, we will be profiling call edges to build a dynamic call graph.
042       * When this is enabled in the system, we want to block the adaptive system
043       * from choosing to compile at a level higher than O0 (only does trivial inlining)
044       * until the system has built up at least a little knowledge of the call graph.
045       * This the cached early-in-the-run viableChoices to be used until the call graph
046       * is ready and we can enable all the opt compiler optimization levels.
047       */
048      protected RecompilationChoice[] earlyViableChoices = { new RecompileOptChoice(0) };
049    
050      /**
051       * Initialize the set of "optimization choices" that the
052       * cost-benefit model will consider.
053       *
054       * This method is conceptually simply, but becomes more complex
055       * because sets of choices are precomputed and stored in a table so
056       * they do not need to be recomputed to answer queries.
057       */
058      void populateRecompilationChoices() {
059        int maxOptLevel = Controller.options.DERIVED_MAX_OPT_LEVEL;
060        int maxCompiler = CompilerDNA.getCompilerConstant(maxOptLevel);
061        allOptLevelChoices = new RecompileOptChoice[maxOptLevel + 1];
062    
063        // Create one main list of all possible recompilation choices that
064        // will be considered.  For each opt-level, create a recompilation
065        // choice for that opt-level and record it indexed by opt-level
066        for (int optLevel = 0; optLevel <= maxOptLevel; optLevel++) {
067          allOptLevelChoices[optLevel] = new RecompileOptChoice(optLevel);
068        }
069    
070        // Given the above choices, create lookup table so that the
071        // controller's calls to
072        // getViableRecompilationChoices(prevCompiler) are answered as
073        // efficiently as possible.
074        createViableOptionLookupTable(maxCompiler);
075      }
076    
077      /**
078       * Compute the set of optimization choices that should be
079       * considered by the cost-benefit model.
080       *
081       * @param prevCompiler The compiler compiler that was used to
082       *                     compile cmpMethod
083       * @param cmpMethod The compiled method being considered
084       */
085      RecompilationChoice[] getViableRecompilationChoices(int prevCompiler, CompiledMethod cmpMethod) {
086        if (Controller.controllerThread.earlyRestrictOptLevels()) {
087          return earlyViableChoices;
088        } else {
089          return viableChoices[prevCompiler];
090        }
091      }
092    
093      /**
094       * Setup a lookup table that maps a "previous compiler" to a set
095       * of viable recompilation choices.  In this case, a viable choice
096       * is any compiler > prevCompiler.
097       */
098      protected void createViableOptionLookupTable(int maxCompiler) {
099        viableChoices = new RecompilationChoice[maxCompiler][];
100    
101        // A temp place to store the list of viable choices
102        RecompilationChoice[] temp = new RecompilationChoice[maxCompiler];
103    
104        // For each potential value of the previous compiler
105        for (int prevCompiler = CompilerDNA.BASELINE; prevCompiler < maxCompiler; prevCompiler++) {
106    
107          // Consider each choice in the list of all choices.
108          // If it is greater than cur compiler, add it.
109          int curSlot = 0;
110          for (RecompileOptChoice choice : allOptLevelChoices) {
111            if (choice.getCompiler() > prevCompiler) {
112              // Add the current opt-level as a choice to consider when
113              // the previous compiler is prevCompiler
114              temp[curSlot++] = choice;
115            }
116          }
117    
118          // Now that you know how many choices there are, create an array
119          // of them and copy the choices in.
120          viableChoices[prevCompiler] = new RecompilationChoice[curSlot];
121          for (int i = 0; i < curSlot; i++) {
122            viableChoices[prevCompiler][i] = temp[i];
123            temp[i] = null;
124          }
125        }
126      }
127    }