hphp/runtime/vm/jit/regionize-func.cpp
/**
 * 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 T2 immediately follows
 *      T1 in R.
 *   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
 */
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 T2 immediately follows
T1 in R.
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
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 T2 immediately follows T1 in R . 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,
                   JIT::TranslatorX64* tx64,
                   RegionVec&          regions) {
  assert(RuntimeOption::EvalJitPGO);
  FuncId funcId = func->getFuncId();
  ProfData* profData = tx64->profData();
  TransCFG cfg(funcId, profData, tx64->getSrcDB(), tx64->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 (cfg.weight(tid1) != cfg.weight(tid2)) {
                return cfg.weight(tid1) > cfg.weight(tid2);
              }
              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 = selectHotTrace(newHead, profData, cfg,
                                            selectedSet, &selectedVec);
      profData->setOptimized(profData->transSrcKey(newHead));
      assert(selectedVec.size() > 0 && selectedVec[0] == newHead);
      regions.push_back(region);
      heads.insert(newHead);
      markCovered(cfg, selectedVec, heads, coveredNodes, coveredArcs);
      regionToTransIds[region] = selectedVec;
      headToRegion[newHead] = region;
      FTRACE(6, "regionizeFunc: selected trace: {}\n",
             folly::join(", ", selectedVec));
    }
  }
  assert(coveredNodes.size() == cfg.nodes().size());
  assert(coveredArcs.size() == arcs.size());
  sortRegion(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));
    }
  }
}
void regionizeFunc ( const Func * func , JIT :: TranslatorX64 * tx64 , RegionVec & regions ) { assert ( RuntimeOption :: EvalJitPGO ) ; FuncId funcId = func -> getFuncId ( ) ; ProfData * profData = tx64 -> profData ( ) ; TransCFG cfg ( funcId , profData , tx64 -> getSrcDB ( ) , tx64 -> getJmpToTransIDMap ( ) ) ; if ( Trace :: moduleEnabled ( HPHP :: Trace :: pgo , 5 ) ) { auto dotFileName = folly :: to < std :: string > ( " " , funcId , " " ) ; cfg . print ( dotFileName , funcId , profData , nullptr ) ; FTRACE ( 5 , " \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 ( cfg . weight ( tid1 ) != cfg . weight ( tid2 ) ) { return cfg . weight ( tid1 ) > cfg . weight ( tid2 ) ; } 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 , " \n " , newHead ) ; TransIDSet selectedSet ; TransIDVec selectedVec ; RegionDescPtr region = selectHotTrace ( newHead , profData , cfg , selectedSet , & selectedVec ) ; profData -> setOptimized ( profData -> transSrcKey ( newHead ) ) ; assert ( selectedVec . size ( ) > 0 && selectedVec [ 0 ] == newHead ) ; regions . push_back ( region ) ; heads . insert ( newHead ) ; markCovered ( cfg , selectedVec , heads , coveredNodes , coveredArcs ) ; regionToTransIds [ region ] = selectedVec ; headToRegion [ newHead ] = region ; FTRACE ( 6 , " \n " , folly :: join ( " " , selectedVec ) ) ; } } assert ( coveredNodes . size ( ) == cfg . nodes ( ) . size ( ) ) ; assert ( coveredArcs . size ( ) == arcs . size ( ) ) ; sortRegion ( regions , func , cfg , profData , headToRegion , regionToTransIds ) ; if ( debug && Trace :: moduleEnabled ( HPHP :: Trace :: pgo , 5 ) ) { FTRACE ( 5 , " \n \n " " \n " , funcId ) ; for ( auto region : regions ) { FTRACE ( 5 , " \n \n " , show ( * region ) ) ; } } }
Regionize a func, so that each node and each arc in its TransCFG is
 "covered".
Regionize a func so that each node and each arc in its TransCFG is " covered " .
// In case of ties, pick older translations first, in an // attempt to start loops at their headers.