private static void updateCallSite(Instr instr, IRScope scope, Integer scopeVersion) { if (instr instanceof CallBase) { callerSite.s = scope; callerSite.v = scopeVersion; callerSite.call = (CallBase) instr; } }
private static void analyzeProfile() { versionCount++; // if (inlineCount == 2) return; if (codeModificationsCount == 0) numCyclesWithNoModifications++; else numCyclesWithNoModifications = 0; codeModificationsCount = 0; if (numCyclesWithNoModifications < 3) return; // We are now good to go -- start analyzing the profile // System.out.println("-------------------start analysis-----------------------"); final HashMap<IRScope, Long> scopeCounts = new HashMap<IRScope, Long>(); final ArrayList<IRCallSite> callSites = new ArrayList<IRCallSite>(); HashMap<IRCallSite, Long> callSiteCounts = new HashMap<IRCallSite, Long>(); // System.out.println("# call sites: " + callProfile.keySet().size()); long total = 0; for (Long id : callProfile.keySet()) { Long c; CallSiteProfile csp = callProfile.get(id); IRCallSite cs = csp.cs; if (cs.v != scopeVersionMap.get(cs.s).intValue()) { // System.out.println("Skipping callsite: <" + cs.s + "," + cs.v + "> with compiled version: // " + scopeVersionMap.get(cs.s)); continue; } Set<IRScope> calledScopes = csp.counters.keySet(); cs.count = 0; for (IRScope s : calledScopes) { c = scopeCounts.get(s); if (c == null) { c = new Long(0); scopeCounts.put(s, c); } long x = csp.counters.get(s).count; c += x; cs.count += x; } CallBase call = cs.call; if (calledScopes.size() == 1 && !call.inliningBlocked()) { CallSite runtimeCS = call.getCallSite(); if (runtimeCS != null && (runtimeCS instanceof CachingCallSite)) { CachingCallSite ccs = (CachingCallSite) runtimeCS; CacheEntry ce = ccs.getCache(); if (!(ce.method instanceof InterpretedIRMethod)) { // System.out.println("NOT IR-M!"); continue; } else { callSites.add(cs); cs.tgtM = (InterpretedIRMethod) ce.method; } } } total += cs.count; } Collections.sort( callSites, new java.util.Comparator<IRCallSite>() { @Override public int compare(IRCallSite a, IRCallSite b) { if (a.count == b.count) return 0; return (a.count < b.count) ? 1 : -1; } }); // Find top N call sites double freq = 0.0; int i = 0; boolean noInlining = true; Set<IRScope> inlinedScopes = new HashSet<IRScope>(); for (IRCallSite ircs : callSites) { double contrib = (ircs.count * 100.0) / total; // 1% is arbitrary if (contrib < 1.0) break; i++; freq += contrib; // This check is arbitrary if (i == 100 || freq > 99.0) break; // System.out.println("Considering: " + ircs.call + " with id: " + ircs.call.callSiteId + // " in scope " + ircs.s + " with count " + ircs.count + "; contrib " + contrib + "; freq: " + // freq); // Now inline here! CallBase call = ircs.call; IRScope hs = ircs.s; boolean isHotClosure = hs instanceof IRClosure; IRScope hc = isHotClosure ? hs : null; hs = isHotClosure ? hs.getLexicalParent() : hs; IRScope tgtMethod = ircs.tgtM.getIRMethod(); Instr[] instrs = tgtMethod.getInstrsForInterpretation(); // Dont inline large methods -- 500 is arbitrary // Can be null if a previously inlined method hasn't been rebuilt if ((instrs == null) || instrs.length > 500) { // if (instrs == null) System.out.println("no instrs!"); // else System.out.println("large method with " + instrs.length + " instrs. skipping!"); continue; } RubyModule implClass = ircs.tgtM.getImplementationClass(); int classToken = implClass.getGeneration(); String n = tgtMethod.getName(); boolean inlineCall = true; if (isHotClosure) { Operand clArg = call.getClosureArg(null); inlineCall = (clArg instanceof WrappedIRClosure) && (((WrappedIRClosure) clArg).getClosure() == hc); } if (inlineCall) { noInlining = false; long start = new java.util.Date().getTime(); hs.inlineMethod(tgtMethod, implClass, classToken, null, call); inlinedScopes.add(hs); long end = new java.util.Date().getTime(); // System.out.println("Inlined " + tgtMethod + " in " + hs + // " @ instr " + call + " in time (ms): " // + (end-start) + " # instrs: " + instrs.length); inlineCount++; } else { // System.out.println("--no inlining--"); } } for (IRScope x : inlinedScopes) { // update version count for 'hs' scopeVersionMap.put(x, versionCount); // System.out.println("Updating version of " + x + " to " + versionCount); // System.out.println("--- pre-inline-instrs ---"); // System.out.println(x.getCFG().toStringInstrs()); // System.out.println("--- post-inline-instrs ---"); // System.out.println(x.getCFG().toStringInstrs()); } // reset codeModificationsCount = 0; callProfile = new HashMap<Long, CallSiteProfile>(); // Every 1M thread polls, discard stats by reallocating the thread-poll count map if (globalThreadPollCount % 1000000 == 0) { globalThreadPollCount = 0; } }