RegionDescPtr selectHotRegion(TransID transId, MCGenerator* mcg) { auto const profData = jit::profData(); assertx(profData); auto const& func = *profData->transRec(transId)->func(); FuncId funcId = func.getFuncId(); TransCFG cfg(funcId, profData, mcg->srcDB()); assertx(regionMode() != RegionMode::Method); RegionDescPtr region; HotTransContext ctx; ctx.cfg = &cfg; ctx.profData = profData; ctx.tid = transId; ctx.maxBCInstrs = RuntimeOption::EvalJitMaxRegionInstrs; switch (pgoRegionMode(func)) { case PGORegionMode::Hottrace: region = selectHotTrace(ctx); break; case PGORegionMode::Hotblock: region = selectHotBlock(transId, profData, cfg); break; case PGORegionMode::WholeCFG: case PGORegionMode::HotCFG: region = selectHotCFG(ctx); break; } assertx(region); if (Trace::moduleEnabled(HPHP::Trace::pgo, 5)) { std::string dotFileName = std::string("/tmp/trans-cfg-") + folly::to<std::string>(transId) + ".dot"; std::ofstream outFile(dotFileName); if (outFile.is_open()) { cfg.print(outFile, funcId, profData); outFile.close(); } FTRACE(5, "selectHotRegion: New Translation (file: {}) {}\n", dotFileName, region ? show(*region) : std::string("empty region")); } always_assert(region->instrSize() <= RuntimeOption::EvalJitMaxRegionInstrs); if (region->empty()) return nullptr; return region; }
RegionDescPtr selectHotRegion(TransID transId, MCGenerator* mcg) { assertx(RuntimeOption::EvalJitPGO); const ProfData* profData = mcg->tx().profData(); auto const& func = *(profData->transFunc(transId)); FuncId funcId = func.getFuncId(); TransCFG cfg(funcId, profData, mcg->tx().getSrcDB(), mcg->getJmpToTransIDMap()); TransIDSet selectedTIDs; assertx(regionMode() != RegionMode::Method); RegionDescPtr region; HotTransContext ctx; ctx.cfg = &cfg; ctx.profData = profData; ctx.tid = transId; ctx.maxBCInstrs = RuntimeOption::EvalJitMaxRegionInstrs; switch (pgoRegionMode(func)) { case PGORegionMode::Hottrace: region = selectHotTrace(ctx, selectedTIDs); break; case PGORegionMode::Hotblock: region = selectHotBlock(transId, profData, cfg); break; case PGORegionMode::WholeCFG: case PGORegionMode::HotCFG: region = selectHotCFG(ctx, selectedTIDs); break; } assertx(region); if (Trace::moduleEnabled(HPHP::Trace::pgo, 5)) { std::string dotFileName = std::string("/tmp/trans-cfg-") + folly::to<std::string>(transId) + ".dot"; cfg.print(dotFileName, funcId, profData, &selectedTIDs); FTRACE(5, "selectHotRegion: New Translation {} (file: {}) {}\n", mcg->tx().profData()->curTransID(), dotFileName, region ? show(*region) : std::string("empty region")); } always_assert(region->instrSize() <= RuntimeOption::EvalJitMaxRegionInstrs); return region; }
/** * Regionize a func, so that each node and each arc in its TransCFG is * "covered". A node is covered if any region contains it. An arc T1->T2 * is covered if either: * * a) T1 and T2 are in the same region R and R contains arc T1->T2. * b) T2 is the head (first translation) of a region. * * Basic algorithm: * * 1) sort nodes in decreasing weight order * 2) for each node N: * 2.1) if N and all its incoming arcs are covered, then continue * 2.2) select a region starting at this node and mark nodes/arcs as * covered appropriately */ void regionizeFunc(const Func* func, MCGenerator* mcg, RegionVec& regions) { const Timer rf_timer(Timer::regionizeFunc); assertx(RuntimeOption::EvalJitPGO); PGORegionMode regionMode = pgoRegionMode(*func); auto const funcId = func->getFuncId(); auto const profData = mcg->tx().profData(); TransCFG cfg(funcId, profData, mcg->tx().getSrcDB(), mcg->getJmpToTransIDMap()); if (Trace::moduleEnabled(HPHP::Trace::pgo, 5)) { auto dotFileName = folly::to<std::string>( "/tmp/func-cfg-", funcId, ".dot"); cfg.print(dotFileName, funcId, profData, nullptr); FTRACE(5, "regionizeFunc: initial CFG for func {} saved to file {}\n", funcId, dotFileName); } TransCFG::ArcPtrVec arcs = cfg.arcs(); std::vector<TransID> nodes = cfg.nodes(); std::sort(nodes.begin(), nodes.end(), [&](TransID tid1, TransID tid2) -> bool { if (regionMode == PGORegionMode::WholeCFG || regionMode == PGORegionMode::HotCFG) { auto bcOff1 = profData->transStartBcOff(tid1); auto bcOff2 = profData->transStartBcOff(tid2); if (bcOff1 != bcOff2) return bcOff1 < bcOff2; } if (cfg.weight(tid1) != cfg.weight(tid2)) { return cfg.weight(tid1) > cfg.weight(tid2); } // In case of ties, pick older translations first, in an // attempt to start loops at their headers. return tid1 < tid2; }); TransCFG::ArcPtrSet coveredArcs; TransIDSet coveredNodes; TransIDSet heads; TransIDToRegionMap headToRegion; RegionToTransIDsMap regionToTransIds; regions.clear(); for (auto node : nodes) { if (!coveredNodes.count(node) || !allArcsCovered(cfg.inArcs(node), coveredArcs)) { TransID newHead = node; FTRACE(6, "regionizeFunc: selecting trace to cover node {}\n", newHead); TransIDSet selectedSet; TransIDVec selectedVec; RegionDescPtr region; switch (regionMode) { case PGORegionMode::Hottrace: region = selectHotTrace(newHead, profData, cfg, RuntimeOption::EvalJitMaxRegionInstrs, selectedSet, &selectedVec); break; case PGORegionMode::WholeCFG: case PGORegionMode::HotCFG: region = selectHotCFG(newHead, profData, cfg, RuntimeOption::EvalJitMaxRegionInstrs, selectedSet, &selectedVec); break; case PGORegionMode::Hotblock: always_assert(0 && "Invalid value for EvalJitPGORegionSelector"); } FTRACE(6, "regionizeFunc: selected region to cover node {}\n{}\n", newHead, show(*region)); profData->setOptimized(profData->transSrcKey(newHead)); assertx(selectedVec.size() > 0 && selectedVec[0] == newHead); regions.push_back(region); heads.insert(newHead); regionToTransIds[region] = selectedVec; headToRegion[newHead] = region; markCovered(cfg, region, selectedVec, heads, headToRegion, coveredNodes, coveredArcs); FTRACE(6, "regionizeFunc: selected trace: {}\n", folly::join(", ", selectedVec)); } } assertx(coveredNodes.size() == cfg.nodes().size()); assertx(coveredArcs.size() == arcs.size()); sortRegions(regions, func, cfg, profData, headToRegion, regionToTransIds); if (debug && Trace::moduleEnabled(HPHP::Trace::pgo, 5)) { FTRACE(5, "\n--------------------------------------------\n" "regionizeFunc({}): computed regions:\n", funcId); for (auto region : regions) { FTRACE(5, "{}\n\n", show(*region)); } } }