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