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 }