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.controller; 014 015 import java.io.PrintStream; 016 import java.util.LinkedList; 017 import org.jikesrvm.VM; 018 import org.jikesrvm.Constants; 019 import org.jikesrvm.classloader.RVMMethod; 020 import org.jikesrvm.compilers.common.CompiledMethod; 021 import org.jikesrvm.compilers.common.CompiledMethods; 022 import org.jikesrvm.util.ImmutableEntryHashMapRVM; 023 024 /** 025 * This class records decisions taken by the controller. It will remember 026 * controller plans, which contain compilation plans and other goodies, 027 * and allows searching for previous decisions 028 */ 029 public final class ControllerMemory implements Constants { 030 031 /** 032 * This is a hashtable of controller plans indexed by RVMMethod. 033 * Each method can have a list of such plans associated with. 034 */ 035 private static final ImmutableEntryHashMapRVM<RVMMethod, LinkedList<ControllerPlan>> table = 036 new ImmutableEntryHashMapRVM<RVMMethod, LinkedList<ControllerPlan>>(); 037 038 /** 039 * Number of times controller is awoken and did nothing. 040 */ 041 private static int didNothing = 0; 042 043 /** 044 * Number of times controller is awoken 045 */ 046 private static int awoken = 0; 047 048 // counters for chosen opt levels 049 private static int numMethodsConsidered = 0; 050 private static int numMethodsScheduledForRecomp = 0; 051 private static int numBase = 0; 052 private static int numOpt0 = 0; 053 private static int numOpt1 = 0; 054 private static int numOpt2 = 0; 055 private static int numOpt3 = 0; 056 private static int numOpt4 = 0; 057 058 public static int getNumAwoken() { return awoken; } 059 060 public static int getNumDidNothing() { return didNothing; } 061 062 public static int getNumMethodsConsidered() { return numMethodsConsidered; } 063 064 public static int getNumMethodsScheduledForRecomp() { return numMethodsScheduledForRecomp; } 065 066 public static int getNumBase() { return numBase; } 067 068 public static int getNumOpt0() { return numOpt0; } 069 070 public static int getNumOpt1() { return numOpt1; } 071 072 public static int getNumOpt2() { return numOpt2; } 073 074 public static int getNumOpt3() { return numOpt3; } 075 076 static int getNumOpt4() { return numOpt4; } 077 078 static void incrementNumAwoken() { awoken++; } 079 080 static void incrementNumDidNothing() { didNothing++; } 081 082 static void incrementNumMethodsConsidered() { numMethodsConsidered++; } 083 084 static void incrementNumMethodsScheduledForRecomp() { numMethodsScheduledForRecomp++; } 085 086 public static void incrementNumBase() { numBase++; } 087 088 static void incrementNumOpt0() { numOpt0++; } 089 090 static void incrementNumOpt1() { numOpt1++; } 091 092 static void incrementNumOpt2() { numOpt2++; } 093 094 static void incrementNumOpt3() { numOpt3++; } 095 096 static void incrementNumOpt4() { numOpt4++; } 097 098 /** 099 * Inserts a controller plan keyed on the underlying method 100 * 101 * @param plan the controller plan to insert 102 */ 103 static synchronized void insert(ControllerPlan plan) { 104 105 numMethodsScheduledForRecomp++; 106 int optLevel = plan.getCompPlan().options.getOptLevel(); 107 switch (optLevel) { 108 case 0: 109 numOpt0++; 110 break; 111 case 1: 112 numOpt1++; 113 break; 114 case 2: 115 numOpt2++; 116 break; 117 case 3: 118 numOpt3++; 119 break; 120 case 4: 121 numOpt4++; 122 break; 123 default: 124 if (VM.VerifyAssertions) VM._assert(NOT_REACHED, "Unknown Opt Level"); 125 } 126 127 // first check to see if there is a plan list for this method 128 LinkedList<ControllerPlan> planList = findPlan(plan.getCompPlan().method); 129 130 if (planList == null) { 131 // create a plan list, with the single element being this plan 132 planList = new LinkedList<ControllerPlan>(); 133 134 // no synch needed here because the planList is not in the table yet 135 planList.addLast(plan); 136 137 // insert in the hashtable using the method as the hash value 138 table.put(plan.getCompPlan().method, planList); 139 } else { 140 // add the current plan to the end of the list 141 synchronized (planList) { 142 planList.addLast(plan); 143 } 144 } 145 146 // tell the plan what list it is on 147 plan.setPlanList(planList); 148 } 149 150 /** 151 * Looks for a controller plan for the passed method 152 * 153 * @param method The method to look for 154 * @return the list of controller plans for this method if one exists, 155 * otherwise, {@code null} 156 */ 157 private static synchronized LinkedList<ControllerPlan> findPlan(RVMMethod method) { 158 return table.get(method); 159 } 160 161 /** 162 * Find the plan for the compiled method that is passed 163 * @param cmpMethod the compiled method of interest 164 * @return the matching plan or {@code null} if none exists. 165 */ 166 public static synchronized ControllerPlan findMatchingPlan(CompiledMethod cmpMethod) { 167 RVMMethod method = cmpMethod.getMethod(); 168 169 LinkedList<ControllerPlan> planList = findPlan(method); 170 if (planList == null) { 171 return null; 172 } else { 173 // iterate over the planList until we get to this item 174 synchronized (planList) { 175 for (ControllerPlan plan : planList) { 176 // exit when we find ourselves 177 if (plan.getCMID() == cmpMethod.getId()) { 178 return plan; 179 } 180 } // more to process 181 } 182 return null; 183 } 184 } 185 186 /** 187 * Determine if the passed method should be considered as a candidate 188 * for _initial_ AOS recompilation. 189 * A method should not be reconsider for initial AOS recompilation if 190 * a plan already exists for the method whose status is {@link ControllerPlan#IN_PROGRESS}, 191 * {@link ControllerPlan#COMPLETED}, {@link ControllerPlan#OUTDATED}, 192 * or {@link ControllerPlan#ABORTED_COMPILATION_ERROR} because of compilation error. 193 * 194 * @param method the method of interest 195 * @return whether the method should be considered or not 196 */ 197 static synchronized boolean shouldConsiderForInitialRecompilation(RVMMethod method) { 198 LinkedList<ControllerPlan> planList = findPlan(method); 199 if (planList == null) { 200 return true; 201 } else { 202 // iterate over the planList until we find a plan whose status is 203 // inprogress, completed, 204 synchronized (planList) { 205 for (ControllerPlan curPlan : planList) { 206 // exit when we find ourselves 207 byte status = curPlan.getStatus(); 208 if (status == ControllerPlan.COMPLETED || 209 status == ControllerPlan.IN_PROGRESS || 210 status == ControllerPlan.ABORTED_COMPILATION_ERROR || 211 status == ControllerPlan.OUTDATED) { 212 return false; 213 } 214 } 215 } 216 return true; // we didn't find any, so return true 217 } 218 } 219 220 /** 221 * Return {@code true} if there is a plan with the given status for the given method 222 * 223 * @param method the method of interest 224 * @param status the status of interest 225 * @return whether or not there is plan with that status for the method 226 */ 227 static synchronized boolean planWithStatus(RVMMethod method, byte status) { 228 LinkedList<ControllerPlan> planList = findPlan(method); 229 if (planList != null) { 230 // iterate over the planList until we find a plan with status 'status' 231 synchronized (planList) { 232 for (ControllerPlan curPlan : planList) { 233 if (curPlan.getStatus() == status) { 234 return true; 235 } 236 } 237 } 238 } 239 return false; 240 } 241 242 /** 243 * Return {@code true} iff there is a plan to transition from Base to Opt for a 244 * given CMID. 245 */ 246 public static synchronized boolean requestedOSR(int cmid) { 247 CompiledMethod cm = CompiledMethods.getCompiledMethod(cmid); 248 249 // make sure that the cm in question is baseline-compiled 250 if (cm.getCompilerType() != CompiledMethod.BASELINE) return false; 251 252 // OK; now check for an OSR plan 253 RVMMethod m = cm.getMethod(); 254 if (m == null) return false; 255 return planWithStatus(m, ControllerPlan.OSR_BASE_2_OPT); 256 } 257 258 /** 259 * Return {@code true} if there is a completed plan with the given opt level for 260 * the given method 261 * 262 * @param method the method of interest 263 * @param optLevel the opt level of interest 264 * @return whether or not there is completed plan with that level 265 * for the method 266 */ 267 static synchronized boolean completedPlanWithOptLevel(RVMMethod method, int optLevel) { 268 LinkedList<ControllerPlan> planList = findPlan(method); 269 if (planList != null) { 270 // iterate over the planList until we find a completed plan with the 271 // opt level passed 272 synchronized (planList) { 273 for (ControllerPlan curPlan : planList) { 274 if (curPlan.getStatus() == ControllerPlan.COMPLETED && 275 curPlan.getCompPlan().options.getOptLevel() == optLevel) { 276 return true; 277 } 278 } 279 } 280 } 281 return false; 282 } 283 284 /** 285 * Looks for the last controller plan for the passed method 286 * 287 * @param method The method to look for 288 * @return The last controller plan for this method if it exists, 289 * otherwise, {@code null} 290 */ 291 public static synchronized ControllerPlan findLatestPlan(RVMMethod method) { 292 LinkedList<ControllerPlan> planList = findPlan(method); 293 if (planList == null) { 294 return null; 295 } else { 296 return planList.getLast(); 297 } 298 } 299 300 /** 301 * This method summarizes the recompilation actions taken for all methods 302 * in this object and produces a report to the passed PrintStream. 303 * @param log the stream to print to 304 */ 305 public static synchronized void printFinalMethodStats(PrintStream log) { 306 // We will traverse the hash table and for each method record its status as 307 // one of the following 308 // B -> 0 -> 1 -> 2 309 // B -> 0 -> 1 310 // B -> 0 311 // B -> 1 -> 2 312 // B -> 0 -> 2 313 // B -> 2 314 // B -> 1 315 // 316 // We encode these possibilities by turning on 1 of three bits for 0, 1, 2 317 // Also, for all methods that eventually get to level 2, they can be 318 // recompiled an arbitrary amount of times. We record this in in a counter. 319 320 final int MAX_BIT_PATTERN = 7; 321 int[] summaryArray = new int[MAX_BIT_PATTERN + 1]; 322 int[] recompsAtLevel2Array = new int[MAX_BIT_PATTERN + 1]; 323 int totalRecompsAtLevel2 = 0; 324 325 // traverse table and give a summary of all actions that have occurred 326 for (RVMMethod meth : table.keys()) { 327 LinkedList<ControllerPlan> planList = table.get(meth); 328 329 int bitPattern = 0; 330 int recompsAtLevel2 = 0; 331 332 for (ControllerPlan plan : planList) { 333 334 // only process plans that were completed or completed and outdated 335 // by subsequent plans for this method 336 byte status = plan.getStatus(); 337 if (status == ControllerPlan.COMPLETED || status == ControllerPlan.OUTDATED) { 338 int optLevel = plan.getCompPlan().options.getOptLevel(); 339 340 // check for recomps at level 2 341 if (optLevel == 2 && bitIsSet(bitPattern, 2)) { 342 recompsAtLevel2++; 343 } 344 345 bitPattern = setBitPattern(bitPattern, optLevel); 346 } // if 347 } // while 348 349 if (Controller.options.LOGGING_LEVEL >= 2) { 350 log.println("Method: " + meth + ", bitPattern: " + bitPattern + ", recompsAtLevel2: " + recompsAtLevel2); 351 } 352 353 summaryArray[bitPattern]++; 354 // track level 2 recomps per pattern 355 recompsAtLevel2Array[bitPattern] += recompsAtLevel2; 356 } 357 358 // Print the summary 359 int totalUniqueMethods = 0; 360 for (int i = 1; i <= MAX_BIT_PATTERN; i++) { 361 log.print(" Base"); 362 for (int optLevel = 0; optLevel <= 2; optLevel++) { 363 if (bitIsSet(i, optLevel)) { 364 log.print(" -> " + optLevel); 365 } 366 } 367 log.print(": " + summaryArray[i]); 368 // print any level 2 recomps for this pattern 369 if (recompsAtLevel2Array[i] > 0) { 370 totalRecompsAtLevel2 += recompsAtLevel2Array[i]; 371 log.println(" (" + recompsAtLevel2Array[i] + " opt level 2 recomps)"); 372 } else { 373 log.println(); 374 } 375 totalUniqueMethods = totalUniqueMethods + summaryArray[i]; 376 } 377 log.println(" Num recompilations At level 2: " + totalRecompsAtLevel2); 378 log.println(" Num unique methods recompiled: " + totalUniqueMethods + "\n"); 379 } 380 381 /** 382 * set the optLevel bit in the passed bitPattern and return the result 383 * @param bitPattern 384 * @param optLevel 385 */ 386 static int setBitPattern(int bitPattern, int optLevel) { 387 int newPattern = 1; 388 newPattern = newPattern << optLevel; 389 return newPattern | bitPattern; 390 } 391 392 /** 393 * check if the bit position defined by the 2nd parm is set in the first parm 394 * @param bitPattern 395 * @param optLevel 396 * @return whether the passed bit is set 397 */ 398 static boolean bitIsSet(int bitPattern, int optLevel) { 399 int newPattern = 1; 400 newPattern = newPattern << optLevel; 401 return (newPattern & bitPattern) > 0; 402 } 403 404 static synchronized String asString() { 405 return table.toString(); 406 } 407 } 408