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.recompilation;
014
015import org.jikesrvm.VM;
016import org.jikesrvm.adaptive.controller.Controller;
017import org.jikesrvm.adaptive.util.AOSLogging;
018import org.jikesrvm.adaptive.util.CompilerAdvice;
019import org.jikesrvm.adaptive.util.CompilerAdviceAttribute;
020import org.jikesrvm.classloader.RVMClass;
021import org.jikesrvm.classloader.RVMClassLoader;
022import org.jikesrvm.classloader.RVMMethod;
023import org.jikesrvm.classloader.NormalMethod;
024import org.jikesrvm.classloader.TypeReference;
025import org.jikesrvm.compilers.baseline.EdgeCounts;
026import org.jikesrvm.compilers.common.RuntimeCompiler;
027import org.jikesrvm.compilers.opt.driver.CompilationPlan;
028import org.jikesrvm.runtime.Callbacks;
029
030/**
031 * Utilities for providing compiler advice.  Advice files provided
032 * at run time allow compilers to be specified for particular methods
033 * <p>
034 * <i>Run time</i> advice is given by identifying an advice file
035 * through a command line option:
036 * <code>-X:aos:cafi=path-to-advice-file</code>.
037 * This file specifies which methods should be optimized, and at
038 * what level.<p>
039 *
040 * Optionally, a dynamic call graph and edge counts may also
041 * be provided in advice files, at the command line.
042 * <code>-X:aos:dcfi=path-to-dynamic-call-graph-file</code>.
043 * <code>-X:vm:edgeCounterFile=path-to-edge-count-file</code>.
044 * These provide synthetic profile data to the compiler that would
045 * otherwise be gathered by the AOS at run time.  These are therefore
046 * strictly an optimization, so they are options.
047 *
048 * @see org.jikesrvm.adaptive.util.CompilerAdviceAttribute
049 * @see org.jikesrvm.compilers.common.RuntimeCompiler
050 */
051public class BulkCompile implements Callbacks.StartupMonitor {
052
053  public static void init() {
054    Callbacks.addStartupMonitor(new BulkCompile());
055  }
056
057  @Override
058  public void notifyStartup() {
059    if (Controller.options.ENABLE_PRECOMPILE) {
060      compileAllMethods();
061    }
062  }
063
064  /**
065   * Compile all methods nominated in the compiler advice,
066   * which should have been provided in a .ca advice file.<p>
067   *
068   * This method will be called at boot time (via notifyStartup())
069   * if ENABLE_PRECOMPILE is true.  For replay compilation, this
070   * method needs to be called explicitly from within the application
071   * or benchmark harness. Typical usage in a benchmarking context
072   * would be to call this method at the end of the first iteration
073   * of the benchmark so that all/most classes were loaded, and
074   * compilation could occur prior to the second iteration.
075   */
076  public static void compileAllMethods() {
077    if (!(Controller.options.ENABLE_BULK_COMPILE || Controller.options.ENABLE_PRECOMPILE)) {
078      /* should not be here */
079      VM.sysFail("Attempt to perform bulk compilation without setting either -X:aos:enable_bulk_compile=true or -X:aos:enable_precompile=true");
080    }
081
082    EdgeCounts.loadCountsFromFileIfAvailable(VM.EdgeCounterFile);
083    CompilerAdvice.readCompilerAdvice();
084    if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1)
085      VM.sysWriteln(Controller.options.ENABLE_PRECOMPILE ? "Start precompile" : "Start bulk compile");
086
087    for (CompilerAdviceAttribute value : CompilerAdviceAttribute.values()) {
088      if (value.getOptLevel() == -1) {
089        if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
090          VM.sysWrite("Skipping base method: "); VM.sysWriteln(value.toString());
091        } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
092          VM.sysWrite(".");
093        }
094        continue;
095      }
096
097      ClassLoader cl = RVMClassLoader.findWorkableClassloader(value.getClassName());
098      if (cl == null)
099        continue;
100
101      TypeReference tRef = TypeReference.findOrCreate(cl, value.getClassName());
102      RVMClass cls = (RVMClass) tRef.peekType();
103
104      if (cls != null) {
105        // Ensure the class is properly loaded
106        if (!cls.isInstantiated()) {
107          if (!cls.isResolved()) {
108            if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
109              VM.sysWriteln("Resolving class: ", cls.toString());
110            } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
111              VM.sysWrite("R");
112            }
113            cls.resolve();
114          }
115          if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
116            VM.sysWriteln("Instantiating class: ", cls.toString());
117          } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
118            VM.sysWrite("I");
119          }
120          cls.instantiate();
121        }
122
123        // Find the method
124        RVMMethod method = cls.findDeclaredMethod(value.getMethodName(), value.getMethodSig());
125
126
127        // If found, compile it
128        if ((method != null) &&
129            !method.hasNoOptCompileAnnotation() &&
130            (method instanceof org.jikesrvm.classloader.NormalMethod)) {
131          // if user's requirement is higher than advice
132          if (value.getOptLevel() > Controller.options.DERIVED_MAX_OPT_LEVEL) {
133            if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
134              VM.sysWrite("Replay advice overriden by default opt levels.  Wanted "); VM.sysWrite(value.getOptLevel()); VM.sysWrite(", but Controller.options.DERIVED_MAX_OPT_LEVEL: ");
135              VM.sysWrite(Controller.options.DERIVED_MAX_OPT_LEVEL); VM.sysWrite(" "); VM.sysWriteln(value.toString());
136            } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
137              VM.sysWrite(value.getOptLevel(), "!");
138            }
139            method.compile();
140          } else {
141            CompilationPlan compPlan;
142            if (Controller.options.counters()) {
143              // for invocation counter, we only use one optimization level
144              compPlan = InvocationCounts.createCompilationPlan((NormalMethod) method);
145              AOSLogging.logger.recompilationStarted(compPlan);
146              if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
147                VM.sysWrite("Bulk compiling for counters ");
148                VM.sysWriteln(value.toString());
149              }
150              RuntimeCompiler.recompileWithOpt(compPlan);
151              AOSLogging.logger.recompilationCompleted(compPlan);
152            } else if (Controller.options.sampling()) {
153              // Create our set of standard optimization plans.
154              compPlan = Controller.recompilationStrategy.createCompilationPlan((NormalMethod) method, value.getOptLevel(), null);
155              if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
156                VM.sysWrite("Bulk compiling for sampling ");
157                VM.sysWriteln(value.toString());
158              }
159              if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
160                VM.sysWrite(value.getOptLevel());
161              }
162              AOSLogging.logger.recompilationStarted(compPlan);
163              RuntimeCompiler.recompileWithOpt(compPlan);
164              AOSLogging.logger.recompilationCompleted(compPlan);
165            } else {
166              if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
167                VM.sysWrite("Compiler advice file overridden ");
168                VM.sysWriteln(value.toString());
169              }
170              method.compile();
171            }
172          }
173        } else {
174          if (Controller.options.BULK_COMPILATION_VERBOSITY > 1) {
175            VM.sysWrite("Replay failed for "); VM.sysWrite(value.toString()); VM.sysWrite(" "); VM.sysWriteln(cl.toString());
176          } else if (Controller.options.BULK_COMPILATION_VERBOSITY == 1) {
177            VM.sysWrite("*");
178          }
179        }
180      }
181    }
182    AOSLogging.logger.compileAllMethodsCompleted();
183    if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1) VM.sysWriteln();
184    if (Controller.options.BULK_COMPILATION_VERBOSITY >= 1) VM.sysWriteln("Recompilation complete");
185  }
186}