/* * 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.compilers.common; import static org.jikesrvm.VM.NOT_REACHED; import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG; import org.jikesrvm.VM; import org.jikesrvm.adaptive.controller.Controller; import org.jikesrvm.adaptive.controller.ControllerMemory; import org.jikesrvm.adaptive.controller.ControllerPlan; import org.jikesrvm.adaptive.recompilation.InvocationCounts; import org.jikesrvm.adaptive.recompilation.BulkCompile; import org.jikesrvm.adaptive.recompilation.instrumentation.AOSInstrumentationPlan; import org.jikesrvm.adaptive.util.AOSGenerator; import org.jikesrvm.adaptive.util.AOSLogging; import org.jikesrvm.adaptive.util.CompilerAdviceAttribute; import org.jikesrvm.architecture.ArchConstants; import org.jikesrvm.classloader.NativeMethod; import org.jikesrvm.classloader.NormalMethod; import org.jikesrvm.classloader.RVMType; import org.jikesrvm.classloader.TypeReference; import org.jikesrvm.compilers.baseline.BaselineCompiler; import org.jikesrvm.compilers.opt.MagicNotImplementedException; import org.jikesrvm.compilers.opt.OptimizingCompilerException; import org.jikesrvm.compilers.opt.OptOptions; import org.jikesrvm.compilers.opt.driver.CompilationPlan; import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; import org.jikesrvm.compilers.opt.driver.OptimizationPlanner; import org.jikesrvm.compilers.opt.driver.OptimizingCompiler; import org.jikesrvm.runtime.Callbacks; import org.jikesrvm.runtime.Time; import org.jikesrvm.scheduler.RVMThread; /** * Harness to select which compiler to dynamically * compile a method in first invocation. * <p> * A place to put code common to all runtime compilers. * This includes instrumentation code to get equivalent data for * each of the runtime compilers. * <p> * We collect the following data for each compiler * <ol> * <li> * total number of methods complied by the compiler * <li> * total compilation time in milliseconds. * <li> * total number of bytes of bytecodes compiled by the compiler * (under the assumption that there is no padding in the bytecode * array and thus RVMMethod.getBytecodes().length is the number bytes * of bytecode for a method) * <li> * total number of machine code instructions generated by the compiler * (under the assumption that there is no (excessive) padding in the * machine code array and thus CompiledMethod.numberOfInsturctions() * is a close enough approximation of the number of machinecodes generated) * </ol> * Note that even if 3. & 4. are inflated due to padding, the numbers will * still be an accurate measure of the space costs of the compile-only * approach. */ public class RuntimeCompiler implements Callbacks.ExitMonitor { // Use these to encode the compiler for record() public static final byte JNI_COMPILER = 0; public static final byte BASELINE_COMPILER = 1; public static final byte OPT_COMPILER = 2; // Data accumulators private static final String[] name = {"JNI\t", "Base\t", "Opt\t"}; // Output names private static int[] totalMethods = {0, 0, 0}; private static double[] totalCompTime = {0, 0, 0}; private static int[] totalBCLength = {0, 0, 0}; private static int[] totalMCLength = {0, 0, 0}; // running sum of the natural logs of the rates, // used for geometric mean, the product of rates is too big for doubles // so we use the principle of logs to help us // We compute e ** ((log a + log b + ... + log n) / n ) private static double[] totalLogOfRates = {0, 0, 0}; // We can't record values until Math.log is loaded, so we miss the first few private static int[] totalLogValueMethods = {0, 0, 0}; private static String[] earlyOptArgs = new String[0]; /** is the opt compiler usable? This will be the case after booting. */ protected static boolean compilerEnabled; // FIXME Make opt compiler reentrant and update documentation accordingly. /** * is opt compiler currently in use? This flag is used to detect/avoid * recursive opt compilation (ie when opt compilation causes a method to be * compiled). We also make all public entrypoints static synchronized methods * because the opt compiler is not reentrant. There are two cases here: * <ol> * <li>recursive opt compilation by the same thread (always bad) * <li>parallel opt compilation (currently bad because opt compiler * is not reentrant, future ok) * </ol> * <p> * NOTE: The associated code can be quite subtle, so please be absolutely sure * you know what you're doing before modifying it!!! */ protected static boolean compilationInProgress; // Cache objects needed to cons up compilation plans // TODO: cutting link to opt compiler by declaring type as object. public static final Object /* Options */ options = VM.BuildForAdaptiveSystem ? new OptOptions() : null; public static Object /* OptimizationPlanElement[] */ optimizationPlan; /** * To be called when the VM is about to exit. * @param value the exit value */ @Override public void notifyExit(int value) { report(false); } /** * This method records the time and sizes (bytecode and machine code) for * a compilation. * @param compiler the compiler used * @param method the resulting RVMMethod * @param compiledMethod the resulting compiled method */ public static void record(byte compiler, NormalMethod method, CompiledMethod compiledMethod) { recordCompilation(compiler, method.getBytecodeLength(), compiledMethod.numberOfInstructions(), compiledMethod.getCompilationTime()); if (VM.BuildForAdaptiveSystem) { if (AOSLogging.logger.booted()) { AOSLogging.logger.recordUpdatedCompilationRates(compiler, method, method.getBytecodeLength(), totalBCLength[compiler], compiledMethod.numberOfInstructions(), totalMCLength[compiler], compiledMethod.getCompilationTime(), totalCompTime[compiler], totalLogOfRates[compiler], totalLogValueMethods[compiler], totalMethods[compiler]); } } } /** * This method records the time and sizes (bytecode and machine code) for * a compilation * @param compiler the compiler used * @param method the resulting RVMMethod * @param compiledMethod the resulting compiled method */ public static void record(byte compiler, NativeMethod method, CompiledMethod compiledMethod) { recordCompilation(compiler, 0, // don't have any bytecode info, its native compiledMethod.numberOfInstructions(), compiledMethod.getCompilationTime()); } /** * This method does the actual recording * @param compiler the compiler used * @param BCLength the number of bytecodes in method source * @param MCLength the length of the generated machine code * @param compTime the compilation time in ms */ private static void recordCompilation(byte compiler, int BCLength, int MCLength, double compTime) { totalMethods[compiler]++; totalMCLength[compiler] += MCLength; totalCompTime[compiler] += compTime; // Comp rate not useful for JNI compiler because there is no bytecode! if (compiler != JNI_COMPILER) { totalBCLength[compiler] += BCLength; double rate = BCLength / compTime; // need to be fully booted before calling log if (VM.fullyBooted) { // we want the geometric mean, but the product of rates is too big // for doubles, so we use the principle of logs to help us // We compute e ** ((log a + log b + ... + log n) / n ) totalLogOfRates[compiler] += Math.log(rate); totalLogValueMethods[compiler]++; } } } /** * This method produces a summary report of compilation activities * @param explain Explains the metrics used in the report */ public static void report(boolean explain) { VM.sysWriteln(); VM.sysWriteln("\t\tCompilation Subsystem Report"); VM.sysWriteln("Comp\t#Meths\tTime\tbcb/ms\tmcb/bcb\tMCKB\tBCKB"); for (int i = 0; i <= name.length - 1; i++) { if (totalMethods[i] > 0) { VM.sysWrite(name[i]); // Number of methods VM.sysWrite(totalMethods[i]); VM.sysWrite("\t"); // Compilation time VM.sysWrite(totalCompTime[i]); VM.sysWrite("\t"); if (i == JNI_COMPILER) { VM.sysWrite("NA"); } else { // Bytecode bytes per millisecond, // use unweighted geomean VM.sysWrite(Math.exp(totalLogOfRates[i] / totalLogValueMethods[i]), 2); } VM.sysWrite("\t"); // Ratio of machine code bytes to bytecode bytes if (i != JNI_COMPILER) { VM.sysWrite((double) (totalMCLength[i] << ArchConstants.getLogInstructionWidth()) / totalBCLength[i], 2); } else { VM.sysWrite("NA"); } VM.sysWrite("\t"); // Generated machine code Kbytes VM.sysWrite((double) (totalMCLength[i] << ArchConstants.getLogInstructionWidth()) / 1024, 1); VM.sysWrite("\t"); // Compiled bytecode Kbytes if (i != JNI_COMPILER) { VM.sysWrite((double) totalBCLength[i] / 1024, 1); } else { VM.sysWrite("NA"); } VM.sysWriteln(); } } if (explain) { // Generate an explanation of the metrics reported VM.sysWriteln("\t\t\tExplanation of Metrics"); VM.sysWriteln("#Meths:\t\tTotal number of methods compiled by the compiler"); VM.sysWriteln("Time:\t\tTotal compilation time in milliseconds"); VM.sysWriteln("bcb/ms:\t\tNumber of bytecode bytes complied per millisecond"); VM.sysWriteln("mcb/bcb:\tRatio of machine code bytes to bytecode bytes"); VM.sysWriteln("MCKB:\t\tTotal number of machine code bytes generated in kilobytes"); VM.sysWriteln("BCKB:\t\tTotal number of bytecode bytes compiled in kilobytes"); } BaselineCompiler.generateBaselineCompilerSubsystemReport(explain); if (VM.BuildForAdaptiveSystem) { // Get the opt's report RVMType theType = TypeReference.OptimizationPlanner.peekType(); if (theType != null && theType.asClass().isInitialized()) { OptimizationPlanner.generateOptimizingCompilerSubsystemReport(explain); } else { VM.sysWriteln(); VM.sysWriteln("\tNot generating Optimizing Compiler SubSystem Report because "); VM.sysWriteln("\tthe opt compiler was never invoked."); VM.sysWriteln(); } } } /** * @return the current estimate of basline-compiler rate, in bcb/msec */ public static double getBaselineRate() { return Math.exp(totalLogOfRates[BASELINE_COMPILER] / totalLogValueMethods[BASELINE_COMPILER]); } /** * This method will compile the passed method using the baseline compiler. * @param method the method to compile * @return the compiled method */ public static CompiledMethod baselineCompile(NormalMethod method) { Callbacks.notifyMethodCompile(method, CompiledMethod.BASELINE); long start = 0; CompiledMethod cm = null; try { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { start = Time.nanoTime(); } cm = BaselineCompiler.compile(method); } finally { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { long end = Time.nanoTime(); if (cm != null) { double compileTime = Time.nanosToMillis(end - start); cm.setCompilationTime(compileTime); record(BASELINE_COMPILER, method, cm); } } } return cm; } /** * Processes a command line argument destined for the opt compiler. * * @param prefix the prefix, e.g. "-X:opt:" * @param arg everything after the last ':' */ public static void processOptCommandLineArg(String prefix, String arg) { if (VM.BuildForAdaptiveSystem) { if (compilerEnabled) { if (((OptOptions) options).processAsOption(prefix, arg)) { // update the optimization plan to reflect the new command line argument optimizationPlan = OptimizationPlanner.createOptimizationPlan((OptOptions) options); } else { VM.sysWrite("Unrecognized opt compiler argument \"" + arg + "\""); VM.sysExit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); } } else { String[] tmp = new String[earlyOptArgs.length + 2]; for (int i = 0; i < earlyOptArgs.length; i++) { tmp[i] = earlyOptArgs[i]; } earlyOptArgs = tmp; earlyOptArgs[earlyOptArgs.length - 2] = prefix; earlyOptArgs[earlyOptArgs.length - 1] = arg; } } else { if (VM.VerifyAssertions) VM._assert(NOT_REACHED); } } /** * Attempt to compile the passed method with the Compiler. * Don't handle OptimizingCompilerExceptions * (leave it up to caller to decide what to do)<p> * Precondition: compilationInProgress "lock" has been acquired * @param method the method to compile * @param plan the plan to use for compiling the method * @return a compiled method */ private static CompiledMethod optCompile(NormalMethod method, CompilationPlan plan) throws OptimizingCompilerException { if (VM.BuildForOptCompiler) { if (VM.VerifyAssertions) { VM._assert(compilationInProgress, "Failed to acquire compilationInProgress \"lock\""); } Callbacks.notifyMethodCompile(method, CompiledMethod.OPT); long start = 0; CompiledMethod cm = null; try { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { start = Time.nanoTime(); } cm = OptimizingCompiler.compile(plan); } finally { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { long end = Time.nanoTime(); if (cm != null) { double compileTime = Time.nanosToMillis(end - start); cm.setCompilationTime(compileTime); record(OPT_COMPILER, method, cm); } } } return cm; } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return null; } } // These methods are safe to invoke from RuntimeCompiler.compile /** * This method tries to compile the passed method with the Compiler, * using the default compilation plan. If * this fails we will use the quicker compiler (baseline for now) * The following is carefully crafted to avoid (infinte) recursive opt * compilation for all combinations of bootimages & lazy/eager compilation. * Be absolutely sure you know what you're doing before changing it !!! * @param method the method to compile * @return a compiled method (opt when possible, baseline when the opt compiler * busy) */ public static synchronized CompiledMethod optCompileWithFallBack(NormalMethod method) { if (VM.BuildForOptCompiler) { if (compilationInProgress) { return fallback(method); } else { try { compilationInProgress = true; CompilationPlan plan = new CompilationPlan(method, (OptimizationPlanElement[]) optimizationPlan, null, (OptOptions) options); return optCompileWithFallBackInternal(method, plan); } finally { compilationInProgress = false; } } } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return null; } } /** * This method tries to compile the passed method with the Compiler * with the passed compilation plan. If * this fails we will use the quicker compiler (baseline for now) * The following is carefully crafted to avoid (infinite) recursive opt * compilation for all combinations of bootimages & lazy/eager compilation. * Be absolutely sure you know what you're doing before changing it !!! * @param method the method to compile * @param plan the compilation plan to use for the compile * @return a compiled method (opt when possible, baseline when the opt compiler * busy) */ public static synchronized CompiledMethod optCompileWithFallBack(NormalMethod method, CompilationPlan plan) { if (VM.BuildForOptCompiler) { if (compilationInProgress) { return fallback(method); } else { try { compilationInProgress = true; return optCompileWithFallBackInternal(method, plan); } finally { compilationInProgress = false; } } } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return null; } } /** * This real method that performs the opt compilation. * @param method the method to compile * @param plan the compilation plan to use * @return a compiled method (opt when possible, baseline when the opt compiler * busy) */ private static CompiledMethod optCompileWithFallBackInternal(NormalMethod method, CompilationPlan plan) { if (VM.BuildForOptCompiler) { if (method.hasNoOptCompileAnnotation()) return fallback(method); try { return optCompile(method, plan); } catch (OptimizingCompilerException e) { String msg = "RuntimeCompiler: can't optimize \"" + method + "\" (error was: " + e + "): reverting to baseline compiler\n"; if (e.isFatal && VM.ErrorsFatal) { e.printStackTrace(); VM.sysFail(msg); } else { boolean printMsg = true; if (e instanceof MagicNotImplementedException) { printMsg = !((MagicNotImplementedException) e).isExpected; } if (printMsg) VM.sysWrite(msg); } return fallback(method); } } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return null; } } /* recompile the specialized method with Compiler. */ public static CompiledMethod recompileWithOptOnStackSpecialization(CompilationPlan plan) { if (VM.BuildForOptCompiler) { if (VM.VerifyAssertions) { VM._assert(plan.method.isForOsrSpecialization()); } if (compilationInProgress) { return null; } try { compilationInProgress = true; // the compiler will check if isForOsrSpecialization of the method CompiledMethod cm = optCompile(plan.method, plan); // we do not replace the compiledMethod of original method, // because it is temporary method return cm; } catch (OptimizingCompilerException e) { e.printStackTrace(); String msg = "Optimizing compiler " + "(via recompileWithOptOnStackSpecialization): " + "can't optimize \"" + plan .method + "\" (error was: " + e + ")\n"; if (e.isFatal && VM.ErrorsFatal) { VM.sysFail(msg); } else { VM.sysWrite(msg); } return null; } finally { compilationInProgress = false; } } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return null; } } /** * This method tries to compile the passed method with the Compiler. * It will install the new compiled method in the VM, if successful. * <p> * NOTE: the recompile method should never be invoked via * RuntimeCompiler.compile; * it does not have sufficient guards against recursive recompilation. * @param plan the compilation plan to use * @return the CMID of the new method if successful, -1 if the * recompilation failed. * **/ public static synchronized int recompileWithOpt(CompilationPlan plan) { if (VM.BuildForOptCompiler) { if (compilationInProgress) { return -1; } else { try { compilationInProgress = true; CompiledMethod cm = optCompile(plan.method, plan); try { plan.method.replaceCompiledMethod(cm); } catch (Throwable e) { String msg = "Failure in RVMMethod.replaceCompiledMethod (via recompileWithOpt): while replacing \"" + plan .method + "\" (error was: " + e + ")\n"; if (VM.ErrorsFatal) { e.printStackTrace(); VM.sysFail(msg); } else { VM.sysWrite(msg); } return -1; } return cm.getId(); } catch (OptimizingCompilerException e) { String msg = "Optimizing compiler (via recompileWithOpt): can't optimize \"" + plan .method + "\" (error was: " + e + ")\n"; if (e.isFatal && VM.ErrorsFatal) { e.printStackTrace(); VM.sysFail(msg); } else { // VM.sysWrite(msg); } return -1; } finally { compilationInProgress = false; } } } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return -1; } } /** * A wrapper method for those callers who don't want to make * optimization plans * @param method the method to recompile * @return a compiled method id or -1 when the compilation failed */ public static int recompileWithOpt(NormalMethod method) { if (VM.BuildForOptCompiler) { CompilationPlan plan = new CompilationPlan(method, (OptimizationPlanElement[]) optimizationPlan, null, (OptOptions) options); return recompileWithOpt(plan); } else { if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED); return -1; } } /** * This method uses the default compiler (baseline) to compile a method * It is typically called when a more aggressive compilation fails. * This method is safe to invoke from RuntimeCompiler.compile. * * @param method method to compile * @return a baseline compiled method */ protected static CompiledMethod fallback(NormalMethod method) { // call the inherited method "baselineCompile" return baselineCompile(method); } public static void boot() { if (VM.MeasureCompilation) { Callbacks.addExitMonitor(new RuntimeCompiler()); } if (VM.BuildForAdaptiveSystem) { optimizationPlan = OptimizationPlanner.createOptimizationPlan((OptOptions) options); if (VM.MeasureCompilationPhases) { OptimizationPlanner.initializeMeasureCompilation(); } OptimizingCompiler.init((OptOptions) options); BulkCompile.init(); // when we reach here the OPT compiler is enabled. compilerEnabled = true; for (int i = 0; i < earlyOptArgs.length; i += 2) { processOptCommandLineArg(earlyOptArgs[i], earlyOptArgs[i + 1]); } } } public static void processCommandLineArg(String prefix, String arg) { if (VM.BuildForAdaptiveSystem) { if (Controller.options != null && Controller.options.optIRC()) { processOptCommandLineArg(prefix, arg); } else { BaselineCompiler.processCommandLineArg(prefix, arg); } } else { BaselineCompiler.processCommandLineArg(prefix, arg); } } /** * Compile a Java method when it is first invoked. * @param method the method to compile * @return its compiled method. */ public static CompiledMethod compile(NormalMethod method) { if (VM.BuildForAdaptiveSystem) { CompiledMethod cm; if (!Controller.enabled) { // System still early in boot process; compile with baseline compiler cm = baselineCompile(method); ControllerMemory.incrementNumBase(); } else { if (Controller.options.optIRC()) { if (// will only run once: don't bother optimizing method.isClassInitializer() || // exception in progress. can't use opt compiler: // it uses exceptions and runtime doesn't support // multiple pending (undelivered) exceptions [--DL] RVMThread.getCurrentThread().getExceptionRegisters().getInUse()) { // compile with baseline compiler cm = baselineCompile(method); ControllerMemory.incrementNumBase(); } else { // compile with opt compiler AOSInstrumentationPlan instrumentationPlan = new AOSInstrumentationPlan(Controller.options, method); CompilationPlan compPlan = new CompilationPlan(method, (OptimizationPlanElement[]) optimizationPlan, instrumentationPlan, (OptOptions) options); cm = optCompileWithFallBack(method, compPlan); } } else { if ((Controller.options.BACKGROUND_RECOMPILATION && !Controller.options.ENABLE_PRECOMPILE)) { // must be an initial compilation: compile with baseline compiler // or if recompilation with OSR. cm = baselineCompile(method); ControllerMemory.incrementNumBase(); } else { if (CompilerAdviceAttribute.hasAdvice()) { CompilerAdviceAttribute attr = CompilerAdviceAttribute.getCompilerAdviceInfo(method); if (attr.getCompiler() != CompiledMethod.OPT) { cm = fallback(method); AOSLogging.logger.recordCompileTime(cm, 0.0); return cm; } int newCMID = -2; CompilationPlan compPlan; if (Controller.options.counters()) { // for invocation counter, we only use one optimization level compPlan = InvocationCounts.createCompilationPlan(method); } else { // for now there is not two options for sampling, so // we don't have to use: if (Controller.options.sampling()) compPlan = Controller.recompilationStrategy.createCompilationPlan(method, attr.getOptLevel(), null); } AOSLogging.logger.recompilationStarted(compPlan); newCMID = recompileWithOpt(compPlan); cm = newCMID == -1 ? null : CompiledMethods.getCompiledMethod(newCMID); if (newCMID == -1) { AOSLogging.logger.recompilationAborted(compPlan); } else if (newCMID > 0) { AOSLogging.logger.recompilationCompleted(compPlan); } if (cm == null) { // if recompilation is aborted cm = baselineCompile(method); ControllerMemory.incrementNumBase(); } } else { // check to see if there is a compilation plan for this method. ControllerPlan plan = ControllerMemory.findLatestPlan(method); if (plan == null || plan.getStatus() != ControllerPlan.IN_PROGRESS) { // initial compilation or some other funny state: compile with baseline compiler cm = baselineCompile(method); ControllerMemory.incrementNumBase(); } else { cm = plan.doRecompile(); if (cm == null) { // opt compilation aborted for some reason. cm = baselineCompile(method); } } } } } } if ((Controller.options.ENABLE_ADVICE_GENERATION) && (cm.getCompilerType() == CompiledMethod.BASELINE) && Controller .enabled) { AOSGenerator.baseCompilationCompleted(cm); } AOSLogging.logger.recordCompileTime(cm, 0.0); return cm; } else { return baselineCompile(method); } } /** * Compile the stub for a native method when it is first invoked. * @param method the method to compile * @return its compiled method. */ public static CompiledMethod compile(NativeMethod method) { Callbacks.notifyMethodCompile(method, CompiledMethod.JNI); long start = 0; CompiledMethod cm = null; try { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { start = Time.nanoTime(); } if (VM.BuildForIA32) { cm = org.jikesrvm.jni.ia32.JNICompiler.compile(method); } else { if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC); cm = org.jikesrvm.jni.ppc.JNICompiler.compile(method); } if (VM.verboseJNI) { VM.sysWriteln("[Dynamic-linking native method " + method.getDeclaringClass() + "." + method.getName() + " " + method.getDescriptor()); } } finally { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { long end = Time.nanoTime(); if (cm != null) { double compileTime = Time.nanosToMillis(end - start); cm.setCompilationTime(compileTime); record(JNI_COMPILER, method, cm); } } } return cm; } /** * returns the string version of compiler number, using the naming scheme * in this file * @param compiler the compiler of interest * @return the string version of compiler number */ public static String getCompilerName(byte compiler) { return name[compiler]; } /** * @return total compilation time in milliseconds */ public static long getTotalCompilationTime() { double baseTime = getTotalCompilationTime(BASELINE_COMPILER); double optTime = getTotalCompilationTime(OPT_COMPILER); double jniTime = getTotalCompilationTime(JNI_COMPILER); return Math.round(baseTime + optTime + jniTime); } /** * Returns the total compilation time of compiler number, using the naming scheme * from this class * @param compilerType the compiler of interest * @return the total compilation time for the given compiler in milliseconds */ public static double getTotalCompilationTime(byte compilerType) { return totalCompTime[compilerType]; } }