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 java.io.FileReader;
016    import java.io.IOException;
017    import java.io.LineNumberReader;
018    import java.util.StringTokenizer;
019    import org.jikesrvm.VM;
020    import org.jikesrvm.Constants;
021    import org.jikesrvm.adaptive.controller.Controller;
022    import org.jikesrvm.adaptive.util.AOSLogging;
023    import org.jikesrvm.classloader.NormalMethod;
024    import org.jikesrvm.compilers.common.RuntimeCompiler;
025    
026    /**
027     * This class codifies the cost/benefit properties of the various compilers
028     * used in the adaptive optimization system.<p>
029     *
030     * The DNA tells the AOS two important kinds of averages for each optimization
031     * level: the cost of compiling at an optimization level (as measured in
032     * bytecode/milliseconds) and the expected speedup of the resulting code
033     * (relative to the first compiler).<p>
034     *
035     * There is an AOS command-line option to set the compiler DNA.  The method
036     * {@link CompilerDNA#readDNA} contains a comment on the expected format.<p>
037     *
038     * This DNA was gathered on July 9, 2008 using revision r14679 + the bugfix in r14688.
039     * The PowerPC data was gathered on piccolo.watson.ibm.com (JS21, machine type 8884; ppc64-aix).
040     * The IA32 data was gathered on lyric.watson.ibm.com (LS41, machine type 7972; x86_64-linux).
041     */
042    public class CompilerDNA implements Constants {
043    
044      private static final String[] compilerNames = {"Baseline", "Opt0", "Opt1", "Opt2"};
045      public static final int BASELINE = 0;
046      static final int OPT0 = 1;
047      static final int OPT1 = 2;
048      static final int OPT2 = 3;
049    
050      /**
051       *  The number of compilers available
052       */
053      private static int numCompilers;
054    
055      /**
056       * Average bytecodes compiled per millisecond.
057       */
058      private static final double[] compilationRates;
059    
060      static {
061        if (VM.BuildForPowerPC) {
062          compilationRates = new double[]{667.32,             // base
063                                          26.36, 13.41, 12.73}; // opt 0...2
064        } else if (VM.BuildForIA32) {
065          compilationRates = new double[]{909.46,               // base
066                                          39.53, 18.48, 17.28}; // opt 0...2
067        } else {
068          if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
069          compilationRates = null;
070        }
071      }
072    
073      /**
074       * What is the execution rate of each compiler normalized to the 1st compiler
075       */
076      private static final double[] speedupRates;
077    
078      static {
079        if (VM.BuildForPowerPC) {
080          speedupRates = new double[]{1.00,               // base
081                                      7.87, 12.23, 12.29};  // opt 0...2
082        } else if (VM.BuildForIA32) {
083          speedupRates = new double[]{1.00,               // base
084                                      4.03, 5.88, 5.93};  // opt 0...2
085        } else {
086          if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
087          speedupRates = null;
088        }
089      }
090    
091      /**
092       * Benefits of moving from one compilation level to another
093       * USAGE NOTE: The data is layed out in a upper triangular matrix
094       */
095      private static double[][] benefitRatio;
096    
097      /**
098       * Compile time ratio of one compilation level to another
099       * For example, if compiler1 (say OPT1) compiles at 50 bc/msec
100       * and compiler2 (say OPT2) compiles at 100 bc/msec,
101       *    compileTimeRatio[OPT1][OPT2] = 2
102       * USAGE NOTE: The data is layed out in a upper triangular matrix
103       */
104      private static double[][] compileTimeRatio;
105    
106      static {
107        initializeCompilerRatioArrays();
108      }
109    
110      /**
111       * This method returns the expected speedup from going from compiler1 to compiler2
112       * @param compiler1
113       * @param compiler2
114       * @return the benefit ratio (speedup) of moving from compiler1 to compiler2
115       */
116      public static double getBenefitRatio(int compiler1, int compiler2) {
117        return benefitRatio[compiler1][compiler2];
118      }
119    
120      /**
121       * What is the additional overhead (relative to compiler1 compile time)
122       * of compile2 compile time.  For example, if compiler1 compiles at
123       * 50 bc/msec and compiler2 compiles at 100 bc/msec, this method returns 2
124       * @param compiler1 the compiler whose compile time we compare to
125       * @param compiler2 the compiler's compile time we care about
126       * @return the additional overhead (relative to compiler1 compile time)
127       * of compile2 compile time
128       */
129      public static double getCompileTimeRatio(int compiler1, int compiler2) {
130        return compileTimeRatio[compiler1][compiler2];
131      }
132    
133      /**
134       * Estimate how long (in milliseconds) it will/did take the
135       * given compiler to compile the given method.
136       *
137       * @param compiler the compiler to compile meth
138       * @param meth the method to be compiled
139       * @return an estimate of compile time (in milliseconds)
140       */
141      public static double estimateCompileTime(int compiler, NormalMethod meth) {
142        double bytes = meth.getBytecodeLength();
143        double runtimeBaselineRate = RuntimeCompiler.getBaselineRate();
144        double compileTime = bytes / runtimeBaselineRate;
145        if (compiler != BASELINE) {
146          compileTime *= compileTimeRatio[BASELINE][compiler];
147        }
148        return compileTime;
149      }
150    
151      /**
152       * Returns the compilation rates of the baseline compiler in
153       *  bytecodes/millisecond.
154       * @return the compilation rates of the baseline compiler in
155       *   bytecodes/millisecond
156       */
157      public static double getBaselineCompilationRate() {
158        return compilationRates[BASELINE];
159      }
160    
161      /**
162       * initialize static fields
163       */
164      public static void init() {
165        // check to see if the raw rates are specified during boot time
166        if (Controller.options.COMPILER_DNA_FILE_NAME.length() != 0) {
167          //  Read the DNA values from disk
168          readDNA(Controller.options.COMPILER_DNA_FILE_NAME);
169          initializeCompilerRatioArrays();
170        }
171    
172        for (int i = 0; i < compilationRates.length; i++) {
173          AOSLogging.logger.reportCompilationRate(i, compilationRates[i]);
174        }
175        for (int i = 0; i < speedupRates.length; i++) {
176          AOSLogging.logger.reportSpeedupRate(i, speedupRates[i]);
177        }
178    
179        // Compute MAX_OPT_LEVEL
180        int maxProfitableCompiler = 0;
181        for (int compiler = 1; compiler < numCompilers; compiler++) {
182          if (compilationRates[compiler] > compilationRates[compiler - 1] ||
183              speedupRates[compiler] > speedupRates[compiler - 1]) {
184            maxProfitableCompiler = compiler;
185          }
186        }
187        int maxOptLevel = getOptLevel(maxProfitableCompiler);
188        Controller.options.DERIVED_MAX_OPT_LEVEL = Math.min(maxOptLevel,Controller.options.MAX_OPT_LEVEL);
189        Controller.options.DERIVED_FILTER_OPT_LEVEL = Controller.options.DERIVED_MAX_OPT_LEVEL;
190      }
191    
192      private static void initializeCompilerRatioArrays() {
193        numCompilers = compilerNames.length;
194        benefitRatio = new double[numCompilers][numCompilers];
195        compileTimeRatio = new double[numCompilers][numCompilers];
196    
197        // fill in the upper triangular matrices
198        for (int prevCompiler = 0; prevCompiler < numCompilers; prevCompiler++) {
199    
200          benefitRatio[prevCompiler][prevCompiler] = 1.0;
201          compileTimeRatio[prevCompiler][prevCompiler] = 1.0;
202    
203          for (int nextCompiler = prevCompiler + 1; nextCompiler < numCompilers; nextCompiler++) {
204            benefitRatio[prevCompiler][nextCompiler] = speedupRates[nextCompiler] / speedupRates[prevCompiler];
205    
206            // Since compilation rates are not relative to the 1st compiler
207            //  we invert the division.
208            compileTimeRatio[prevCompiler][nextCompiler] = compilationRates[prevCompiler] / compilationRates[nextCompiler];
209            AOSLogging.logger.reportBenefitRatio(prevCompiler, nextCompiler, benefitRatio[prevCompiler][nextCompiler]);
210    
211            AOSLogging.logger.reportCompileTimeRatio(prevCompiler, nextCompiler, compileTimeRatio[prevCompiler][nextCompiler]);
212          }
213        }
214      }
215    
216      /**
217       * Read a serialized representation of the DNA info
218       * @param filename DNA filename
219       */
220      private static void readDNA(String filename) {
221        try {
222    
223          LineNumberReader in = new LineNumberReader(new FileReader(filename));
224    
225          // Expected Format
226          //   CompilationRates  aaa.a  bbbb.b cccc.c dddd.d ....
227          //   SpeedupRates      aaa.a  bbbb.b cccc.c dddd.d ....
228          processOneLine(in, "CompilationRates", compilationRates);
229          processOneLine(in, "SpeedupRates", speedupRates);
230        } catch (Exception e) {
231          e.printStackTrace();
232          VM.sysFail("Failed to open controller DNA file");
233        }
234      }
235    
236      /**
237       *  Helper method to read one line of the DNA file
238       *  @param in the LineNumberReader object
239       *  @param title the title string to look for
240       *  @param valueHolder the array to hold the read values
241       */
242      private static void processOneLine(LineNumberReader in, String title, double[] valueHolder) throws IOException {
243    
244        String s = in.readLine();
245        if (VM.VerifyAssertions) VM._assert(s != null);
246    
247        // parse the string
248        StringTokenizer parser = new StringTokenizer(s);
249    
250        // make sure the title matches
251        String token = parser.nextToken();
252        if (VM.VerifyAssertions) VM._assert(token.equals(title));
253    
254        // walk through the array, making sure we still have tokens
255        for (int i = 0; parser.hasMoreTokens() && i < valueHolder.length; i++) {
256    
257          // get the available token
258          token = parser.nextToken();
259    
260          // convert token to a double
261          valueHolder[i] = Double.valueOf(token);
262        }
263      }
264    
265      /**
266       * returns the number of compilers
267       * @return the number of compilers
268       */
269      public static int getNumberOfCompilers() {
270        return numCompilers;
271      }
272    
273      /**
274       * A mapping from an Opt compiler number to the corresponding Opt level
275       * @param compiler the compiler constant of interest
276       * @return the Opt level that corresponds to the Opt compiler constant passed
277       */
278      public static int getOptLevel(int compiler) {
279        switch (compiler) {
280          case BASELINE:
281            return -1;
282          case OPT0:
283            return 0;
284          case OPT1:
285            return 1;
286          case OPT2:
287            return 2;
288          default:
289            if (VM.VerifyAssertions) VM._assert(NOT_REACHED, "Unknown compiler constant\n");
290            return -99;
291        }
292      }
293    
294      /**
295       * maps a compiler constant to a string
296       * @param compiler
297       * @return the string that represents the passed compiler constant
298       */
299      public static String getCompilerString(int compiler) {
300        return compilerNames[compiler];
301      }
302    
303      /**
304       * maps opt levels to the compiler
305       * @param optLevel opt level
306       * @return the opt level that corresponds to the passed compiler constant
307       */
308      public static int getCompilerConstant(int optLevel) {
309        switch (optLevel) {
310          case 0:
311            return OPT0;
312          case 1:
313            return OPT1;
314          case 2:
315            return OPT2;
316          default:
317            if (VM.VerifyAssertions) VM._assert(NOT_REACHED, "Unknown Opt Level\n");
318            return -99;
319        }
320      }
321    }