/*
* 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.recompilation;
import org.jikesrvm.VM;
import org.jikesrvm.adaptive.controller.Controller;
import org.jikesrvm.adaptive.util.AOSLogging;
import org.jikesrvm.adaptive.util.CompilerAdvice;
import org.jikesrvm.adaptive.util.CompilerAdviceAttribute;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.RVMClassLoader;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.classloader.NormalMethod;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.compilers.baseline.EdgeCounts;
import org.jikesrvm.compilers.common.RuntimeCompiler;
import org.jikesrvm.compilers.opt.driver.CompilationPlan;
import org.jikesrvm.runtime.Callbacks;
/**
* Utilities for providing compiler advice. Advice files provided
* at run time allow compilers to be specified for particular methods
* <p>
* <i>Run time</i> advice is given by identifying an advice file
* through a command line option:
* <code>-X:aos:cafi=path-to-advice-file</code>.
* This file specifies which methods should be optimized, and at
* what level.<p>
*
* Optionally, a dynamic call graph and edge counts may also
* be provided in advice files, at the command line.
* <code>-X:aos:dcfi=path-to-dynamic-call-graph-file</code>.
* <code>-X:vm:edgeCounterFile=path-to-edge-count-file</code>.
* These provide synthetic profile data to the compiler that would
* otherwise be gathered by the AOS at run time. These are therefore
* strictly an optimization, so they are options.
*
* @see org.jikesrvm.adaptive.util.CompilerAdviceAttribute
* @see org.jikesrvm.compilers.common.RuntimeCompiler
*/
public class BulkCompile implements Callbacks.StartupMonitor {
public static void init() {
Callbacks.addStartupMonitor(new BulkCompile());
}
@Override
public void notifyStartup() {
if (Controller.options.ENABLE_PRECOMPILE) {
compileAllMethods();
}
}
/**
* Compile all methods nominated in the compiler advice,
* which should have been provided in a .ca advice file.<p>
*
* This method will be called at boot time (via notifyStartup())
* if ENABLE_PRECOMPILE is true. For replay compilation, this
* method needs to be called explicitly from within the application
* or benchmark harness. Typical usage in a benchmarking context
* would be to call this method at the end of the first iteration
* of the benchmark so that all/most classes were loaded, and
* compilation could occur prior to the second iteration.
*/
public static void compileAllMethods() {
if (!(Controller.options.ENABLE_BULK_COMPILE || Controller.options.ENABLE_PRECOMPILE)) {
/* should not be here */
VM.sysFail("Attempt to perform bulk compilation without setting either -X:aos:enable_bulk_compile=true or -X:aos:enable_precompile=true");
}
EdgeCounts.loadCountsFromFileIfAvailable(VM.EdgeCounterFile);
CompilerAdvice.readCompilerAdvice();
if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1)
VM.sysWriteln(Controller.options.ENABLE_PRECOMPILE ? "Start precompile" : "Start bulk compile");
for (CompilerAdviceAttribute value : CompilerAdviceAttribute.values()) {
if (value.getOptLevel() == -1) {
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWriteln("Skipping base method: ", value.toString());
} else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
VM.sysWrite(".");
}
continue;
}
ClassLoader cl = RVMClassLoader.findWorkableClassloader(value.getClassName());
if (cl == null)
continue;
TypeReference tRef = TypeReference.findOrCreate(cl, value.getClassName());
RVMClass cls = (RVMClass) tRef.peekType();
if (cls != null) {
// Ensure the class is properly loaded
if (!cls.isInstantiated()) {
if (!cls.isResolved()) {
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWriteln("Resolving class: ", cls.toString());
} else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
VM.sysWrite("R");
}
cls.resolve();
}
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWriteln("Instantiating class: ", cls.toString());
} else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
VM.sysWrite("I");
}
cls.instantiate();
}
// Find the method
RVMMethod method = cls.findDeclaredMethod(value.getMethodName(), value.getMethodSig());
// If found, compile it
if ((method != null) &&
!method.hasNoOptCompileAnnotation() &&
(method instanceof org.jikesrvm.classloader.NormalMethod)) {
// if user's requirement is higher than advice
if (value.getOptLevel() > Controller.options.DERIVED_MAX_OPT_LEVEL) {
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWrite("Replay advice overriden by default opt levels. Wanted ");
VM.sysWrite(value.getOptLevel());
VM.sysWrite(", but Controller.options.DERIVED_MAX_OPT_LEVEL: ");
VM.sysWrite(Controller.options.DERIVED_MAX_OPT_LEVEL);
VM.sysWrite(" ");
VM.sysWriteln(value.toString());
} else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
VM.sysWrite(value.getOptLevel(), "!");
}
method.compile();
} else {
CompilationPlan compPlan;
if (Controller.options.counters()) {
// for invocation counter, we only use one optimization level
compPlan = InvocationCounts.createCompilationPlan((NormalMethod) method);
AOSLogging.logger.recompilationStarted(compPlan);
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWrite("Bulk compiling for counters ");
VM.sysWriteln(value.toString());
}
RuntimeCompiler.recompileWithOpt(compPlan);
AOSLogging.logger.recompilationCompleted(compPlan);
} else if (Controller.options.sampling()) {
// Create our set of standard optimization plans.
compPlan = Controller.recompilationStrategy.createCompilationPlan((NormalMethod) method, value.getOptLevel(), null);
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWrite("Bulk compiling for sampling ");
VM.sysWriteln(value.toString());
}
if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
VM.sysWrite(value.getOptLevel());
}
AOSLogging.logger.recompilationStarted(compPlan);
RuntimeCompiler.recompileWithOpt(compPlan);
AOSLogging.logger.recompilationCompleted(compPlan);
} else {
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWrite("Compiler advice file overridden ");
VM.sysWriteln(value.toString());
}
method.compile();
}
}
} else {
if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
VM.sysWrite("Replay failed for ");
VM.sysWrite(value.toString());
VM.sysWrite(" ");
VM.sysWriteln(cl.toString());
} else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
VM.sysWrite("*");
}
}
}
}
AOSLogging.logger.compileAllMethodsCompleted();
if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1) VM.sysWriteln();
if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1) VM.sysWriteln("Recompilation complete");
}
}