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 org.jikesrvm.adaptive.recompilation.CompilerDNA;
016import 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 */
024class 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  @Override
059  void populateRecompilationChoices() {
060    int maxOptLevel = Controller.options.DERIVED_MAX_OPT_LEVEL;
061    int maxCompiler = CompilerDNA.getCompilerConstant(maxOptLevel);
062    allOptLevelChoices = new RecompileOptChoice[maxOptLevel + 1];
063
064    // Create one main list of all possible recompilation choices that
065    // will be considered.  For each opt-level, create a recompilation
066    // choice for that opt-level and record it indexed by opt-level
067    for (int optLevel = 0; optLevel <= maxOptLevel; optLevel++) {
068      allOptLevelChoices[optLevel] = new RecompileOptChoice(optLevel);
069    }
070
071    // Given the above choices, create lookup table so that the
072    // controller's calls to
073    // getViableRecompilationChoices(prevCompiler) are answered as
074    // efficiently as possible.
075    createViableOptionLookupTable(maxCompiler);
076  }
077
078  @Override
079  RecompilationChoice[] getViableRecompilationChoices(int prevCompiler, CompiledMethod cmpMethod) {
080    if (Controller.controllerThread.earlyRestrictOptLevels()) {
081      return earlyViableChoices;
082    } else {
083      return viableChoices[prevCompiler];
084    }
085  }
086
087  /**
088   * Setup a lookup table that maps a "previous compiler" to a set
089   * of viable recompilation choices.  In this case, a viable choice
090   * is any compiler &gt; prevCompiler.
091   *
092   * @param maxCompiler the maximum compiler that we want to consider
093   * (e.g. the highest optimization level).
094   */
095  protected void createViableOptionLookupTable(int maxCompiler) {
096    viableChoices = new RecompilationChoice[maxCompiler][];
097
098    // A temp place to store the list of viable choices
099    RecompilationChoice[] temp = new RecompilationChoice[maxCompiler];
100
101    // For each potential value of the previous compiler
102    for (int prevCompiler = CompilerDNA.BASELINE; prevCompiler < maxCompiler; prevCompiler++) {
103
104      // Consider each choice in the list of all choices.
105      // If it is greater than cur compiler, add it.
106      int curSlot = 0;
107      for (RecompileOptChoice choice : allOptLevelChoices) {
108        if (choice.getCompiler() > prevCompiler) {
109          // Add the current opt-level as a choice to consider when
110          // the previous compiler is prevCompiler
111          temp[curSlot++] = choice;
112        }
113      }
114
115      // Now that you know how many choices there are, create an array
116      // of them and copy the choices in.
117      viableChoices[prevCompiler] = new RecompilationChoice[curSlot];
118      for (int i = 0; i < curSlot; i++) {
119        viableChoices[prevCompiler][i] = temp[i];
120        temp[i] = null;
121      }
122    }
123  }
124}