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.
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).
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.
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 = (double) 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 }