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