std::string show(const RegionDesc& region) { std::string ret{folly::sformat("Region ({} blocks):\n", region.blocks().size())}; auto profData = mcg->tx().profData(); auto weight = [&] (RegionDesc::BlockPtr b) -> int64_t { if (!profData) return 0; auto tid = b->profTransID(); if (tid == kInvalidTransID) return 0; return profData->transCounter(tid); }; uint64_t maxBlockWgt = 1; // avoid div by 0 // Print contents of all blocks in pure text format. for (auto& b : region.blocks()) { folly::toAppend(show(*b), &ret); auto w = weight(b); if (w > maxBlockWgt) maxBlockWgt = w; } // Print CFG in dot format, coloring the blocks based on hotness. // Print all the blocks first. folly::toAppend("\ndigraph RegionCFG {\n node[shape=box,style=filled]\n", &ret); for (auto& b : region.blocks()) { auto const id = b->id(); auto const& mergedSet = region.merged(id); std::string mergedStr = mergedSet.empty() ? "" : (" (" + folly::join(",", mergedSet) + ")"); uint32_t coldness = 255 - (255 * weight(b) / maxBlockWgt); folly::format(&ret, " \"B{}\" [label=\"B {}{}\\np: {}\"," "fillcolor=\"#ff{:02x}{:02x}\"]\n", id, id, mergedStr, weight(b), coldness, coldness); } // Print arcs in dot format. for (auto& b : region.blocks()) { if (auto r = region.nextRetrans(b->id())) { folly::toAppend(folly::format(" \"B{}\" -> \"B{}\" [label=R,color=red]\n", b->id(), r.value()), &ret); } for (auto s : region.succs(b->id())) { folly::toAppend(folly::format(" \"B{}\" -> \"B{}\"\n", b->id(), s), &ret); } } ret += "}\n"; return ret; }
/* * Computes the approximate number of times that `loop' was invoked * (i.e. entered) using profiling data. This value is computed by * adding up the profiling weights of all the Profile translations * that may execute immediately before the Profile translation * containing the loop header. */ uint64_t countInvocations(const LoopInfo& loop, const IRUnit& unit) { always_assert(mcg->tx().profData()); // Find the predecessor TransIDs along each non-back-edge // predecessor of the loop header. boost::dynamic_bitset<> visited(unit.numBlocks()); TransIDSet predTIDs; auto headerTID = loop.header->front().marker().profTransID(); for (auto& predEdge : loop.header->preds()) { if (loop.backEdges.count(&predEdge) == 0) { findPredTransIDs(headerTID, predEdge.from(), visited, predTIDs); } } auto const profData = mcg->tx().profData(); uint64_t count = 0; for (auto tid : predTIDs) { count += profData->transCounter(tid); } return count; }
/** * Chain the retranslation blocks. This method enforces that, for * each region block, all its successor have distinct SrcKeys. */ void RegionDesc::chainRetransBlocks() { jit::vector<Chain> chains; BlockToChainMap block2chain; // 1. Initially assign each region block to its own chain. for (auto b : blocks()) { auto bid = b->id(); auto cid = chains.size(); chains.push_back({cid, {bid}}); block2chain[bid] = cid; } // 2. For each block, if it has 2 successors with the same SrcKey, // then merge the successors' chains into one. for (auto b : blocks()) { auto bid = b->id(); const auto& succSet = succs(bid); for (auto it1 = succSet.begin(); it1 != succSet.end(); it1++) { auto bid1 = *it1; auto cid1 = block2chain[bid1]; for (auto it2 = it1 + 1; it2 != succSet.end(); it2++) { auto bid2 = *it2; auto cid2 = block2chain[bid2]; if (data(bid1).block->start() == data(bid2).block->start()) { mergeChains(chains[cid1], chains[cid2], block2chain); } } } } // 3. Sort each chain. In general, we want to sort each chain in // decreasing order of profile weights. However, note that this // transformation can turn acyclic graphs into cyclic ones (see // example below). Therefore, if JitLoops are disabled, we // instead sort each chain following the original block order, // which prevents loops from being generated if the region was // originally acyclic. // // Here's an example showing how an acyclic CFG can become cyclic // by chaining its retranslation blocks: // // - Region before chaining retranslation blocks, where B2' and B2" // are retranslations starting at the same SrcKey: // B1 -> B2' // B1 -> B2" // B2' -> B3 // B3 -> B2" // // - Region after sorting the chain as B2" -R-> B2': // B1 -> B2" // B2" -R-> B2' // B2' -> B3 // B3 -> B2" // Note the cycle: B2" -R-> B2' -> B3 -> B2". // auto profData = mcg->tx().profData(); auto weight = [&](RegionDesc::BlockId bid) { return hasTransID(bid) ? profData->transCounter(getTransID(bid)) : 0; }; auto sortGeneral = [&](RegionDesc::BlockId bid1, RegionDesc::BlockId bid2) { return weight(bid1) > weight(bid2); }; using SortFun = std::function<bool(RegionDesc::BlockId, RegionDesc::BlockId)>; SortFun sortFunc = sortGeneral; hphp_hash_map<RegionDesc::BlockId, uint32_t> origBlockOrder; if (!RuntimeOption::EvalJitLoops) { for (uint32_t i = 0; i < m_blocks.size(); i++) { origBlockOrder[m_blocks[i]->id()] = i; } auto sortAcyclic = [&](RegionDesc::BlockId bid1, RegionDesc::BlockId bid2) { return origBlockOrder[bid1] < origBlockOrder[bid2]; }; sortFunc = sortAcyclic; } TRACE(1, "chainRetransBlocks: computed chains:\n"); for (auto& c : chains) { std::sort(c.blocks.begin(), c.blocks.end(), sortFunc); if (Trace::moduleEnabled(Trace::region, 1) && c.blocks.size() > 0) { FTRACE(1, " -> {} (w={})", c.blocks[0], weight(c.blocks[0])); for (size_t i = 1; i < c.blocks.size(); i++) { FTRACE(1, ", {} (w={})", c.blocks[i], weight(c.blocks[i])); } FTRACE(1, "\n"); } } // 4. Set the nextRetrans blocks according to the computed chains. for (auto& c : chains) { if (c.blocks.size() == 0) continue; for (size_t i = 0; i < c.blocks.size() - 1; i++) { setNextRetrans(c.blocks[i], c.blocks[i + 1]); } } // 5. For each block with multiple successors in the same chain, // only keep the successor that first appears in the chain. for (auto b : blocks()) { auto& succSet = data(b->id()).succs; for (auto s : succSet) { auto& c = chains[block2chain[s]]; auto selectedSucc = findFirstInSet(c, succSet); for (auto other : c.blocks) { if (other == selectedSucc) continue; succSet.erase(other); data(other).preds.erase(b->id()); } } } // 6. Reorder the blocks in the region in topological order (if // region is acyclic), since the previous steps may break it. sortBlocks(); }