/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.adaptive.controller;
import org.jikesrvm.adaptive.recompilation.CompilerDNA;
import org.jikesrvm.compilers.common.CompiledMethod;
/**
* Implements the multi-level adaptive strategy using an analytic
* model, as described in the OOPSLA 2000 paper. Most behavior
* inherited from AnalyticModel. This class defines the the specific
* recompilation choices that should be considered by the analytic model.
*/
class MultiLevelAdaptiveModel extends AnalyticModel {
/**
* List of all opt-level choices that can be considered by the
* cost-benefit model
*/
protected RecompileOptChoice[] allOptLevelChoices;
/**
* Keep a map from previous compiler to a set of recompilation
* choices. After initialization, viableChoices[x][y] means that if
* x is the previous compiler, y makes sense as a possible
* recompilation choice.
*/
protected RecompilationChoice[][] viableChoices;
/**
* Normally, we will be profiling call edges to build a dynamic call graph.
* When this is enabled in the system, we want to block the adaptive system
* from choosing to compile at a level higher than O0 (only does trivial inlining)
* until the system has built up at least a little knowledge of the call graph.
* This the cached early-in-the-run viableChoices to be used until the call graph
* is ready and we can enable all the opt compiler optimization levels.
*/
protected RecompilationChoice[] earlyViableChoices = { new RecompileOptChoice(0) };
/**
* Initialize the set of "optimization choices" that the
* cost-benefit model will consider.
*
* This method is conceptually simply, but becomes more complex
* because sets of choices are precomputed and stored in a table so
* they do not need to be recomputed to answer queries.
*/
@Override
void populateRecompilationChoices() {
int maxOptLevel = Controller.options.DERIVED_MAX_OPT_LEVEL;
int maxCompiler = CompilerDNA.getCompilerConstant(maxOptLevel);
allOptLevelChoices = new RecompileOptChoice[maxOptLevel + 1];
// Create one main list of all possible recompilation choices that
// will be considered. For each opt-level, create a recompilation
// choice for that opt-level and record it indexed by opt-level
for (int optLevel = 0; optLevel <= maxOptLevel; optLevel++) {
allOptLevelChoices[optLevel] = new RecompileOptChoice(optLevel);
}
// Given the above choices, create lookup table so that the
// controller's calls to
// getViableRecompilationChoices(prevCompiler) are answered as
// efficiently as possible.
createViableOptionLookupTable(maxCompiler);
}
@Override
RecompilationChoice[] getViableRecompilationChoices(int prevCompiler, CompiledMethod cmpMethod) {
if (Controller.controllerThread.earlyRestrictOptLevels()) {
return earlyViableChoices;
} else {
return viableChoices[prevCompiler];
}
}
/**
* Setup a lookup table that maps a "previous compiler" to a set
* of viable recompilation choices. In this case, a viable choice
* is any compiler > prevCompiler.
*
* @param maxCompiler the maximum compiler that we want to consider
* (e.g. the highest optimization level).
*/
protected void createViableOptionLookupTable(int maxCompiler) {
viableChoices = new RecompilationChoice[maxCompiler][];
// A temp place to store the list of viable choices
RecompilationChoice[] temp = new RecompilationChoice[maxCompiler];
// For each potential value of the previous compiler
for (int prevCompiler = CompilerDNA.BASELINE; prevCompiler < maxCompiler; prevCompiler++) {
// Consider each choice in the list of all choices.
// If it is greater than cur compiler, add it.
int curSlot = 0;
for (RecompileOptChoice choice : allOptLevelChoices) {
if (choice.getCompiler() > prevCompiler) {
// Add the current opt-level as a choice to consider when
// the previous compiler is prevCompiler
temp[curSlot++] = choice;
}
}
// Now that you know how many choices there are, create an array
// of them and copy the choices in.
viableChoices[prevCompiler] = new RecompilationChoice[curSlot];
for (int i = 0; i < curSlot; i++) {
viableChoices[prevCompiler][i] = temp[i];
temp[i] = null;
}
}
}
}