Skip to content

Commit cc84154

Browse files
laithsakkamaksfb
authored andcommitted
Rewrite frame analysis using parallel utilities
Summary: Rewrite frame analysis using parallel utilities (cherry picked from FBD16499130)
1 parent 5084534 commit cc84154

File tree

1 file changed

+32
-129
lines changed

1 file changed

+32
-129
lines changed

bolt/src/Passes/FrameAnalysis.cpp

Lines changed: 32 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -496,42 +496,19 @@ bool FrameAnalysis::restoreFrameIndex(BinaryFunction &BF) {
496496
void FrameAnalysis::cleanAnnotations() {
497497
NamedRegionTimer T("cleanannotations", "clean annotations", "FA",
498498
"FA breakdown", opts::TimeFA);
499-
auto cleanBlock = [&](std::map<uint64_t, BinaryFunction>::iterator BlockBegin,
500-
std::map<uint64_t, BinaryFunction>::iterator BlockEnd) {
501-
for (auto It = BlockBegin; It != BlockEnd; ++It) {
502-
auto &BF = It->second;
503-
504-
for (auto &BB : BF) {
505-
for (auto &Inst : BB) {
506-
BC.MIB->removeAnnotation(Inst, "ArgAccessEntry");
507-
BC.MIB->removeAnnotation(Inst, "FrameAccessEntry");
508-
}
499+
500+
ParallelUtilities::WorkFuncTy CleanFunction = [&](BinaryFunction &BF) {
501+
for (auto &BB : BF) {
502+
for (auto &Inst : BB) {
503+
BC.MIB->removeAnnotation(Inst, "ArgAccessEntry");
504+
BC.MIB->removeAnnotation(Inst, "FrameAccessEntry");
509505
}
510506
}
511507
};
512508

513-
if (opts::NoThreads) {
514-
cleanBlock(BC.getBinaryFunctions().begin(), BC.getBinaryFunctions().end());
515-
return;
516-
}
517-
518-
ThreadPool ThPool(opts::ThreadCount);
519-
const unsigned TasksCount = 20 * opts::ThreadCount;
520-
const unsigned SingleTaskSize = BC.getBinaryFunctions().size() / TasksCount;
521-
522-
auto BlockBegin = BC.getBinaryFunctions().begin();
523-
unsigned CurSize = 0;
524-
for (auto It = BC.getBinaryFunctions().begin();
525-
It != BC.getBinaryFunctions().end(); ++It) {
526-
CurSize++;
527-
if (CurSize >= SingleTaskSize) {
528-
ThPool.async(cleanBlock, BlockBegin, std::next(It));
529-
BlockBegin = std::next(It);
530-
CurSize = 0;
531-
}
532-
}
533-
ThPool.async(cleanBlock, BlockBegin, BC.getBinaryFunctions().end());
534-
ThPool.wait();
509+
ParallelUtilities::runOnEachFunction(
510+
BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, CleanFunction,
511+
ParallelUtilities::PredicateTy(nullptr), "cleanAnnotations");
535512
}
536513

537514
FrameAnalysis::FrameAnalysis(BinaryContext &BC, BinaryFunctionCallGraph &CG)
@@ -613,127 +590,53 @@ void FrameAnalysis::clearSPTMap() {
613590
return;
614591
}
615592

616-
auto clearBlock = [&](std::map<uint64_t, BinaryFunction>::iterator BlockBegin,
617-
std::map<uint64_t, BinaryFunction>::iterator BlockEnd) {
618-
for (auto It = BlockBegin; It != BlockEnd; ++It) {
619-
auto &BF = It->second;
620-
621-
if (!BF.isSimple() || !BF.hasCFG())
622-
continue;
623-
624-
auto &SPTPtr = SPTMap.find(&BF)->second;
625-
SPTPtr.reset();
626-
}
593+
ParallelUtilities::WorkFuncTy ClearFunctionSPT = [&](BinaryFunction &BF) {
594+
auto &SPTPtr = SPTMap.find(&BF)->second;
595+
SPTPtr.reset();
627596
};
628597

629-
ThreadPool ThPool(opts::ThreadCount);
630-
unsigned CurId = 0;
631-
auto BlockBegin = BC.getBinaryFunctions().begin();
632-
633-
// Functions that use the same allocator id are on the same task
634-
for (auto It = BC.getBinaryFunctions().begin();
635-
It != BC.getBinaryFunctions().end(); ++It) {
636-
auto &BF = It->second;
637-
638-
if (BF.isSimple() && BF.hasCFG()) {
639-
auto &SPT = getSPT(BF);
640-
641-
// First valid allocator id is seen
642-
if (CurId == 0) {
643-
BlockBegin = It;
644-
CurId = SPT.getAllocatorId();
645-
continue;
646-
}
598+
ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
599+
return !BF.isSimple() || !BF.hasCFG();
600+
};
647601

648-
if (CurId != SPT.getAllocatorId()) {
649-
CurId = SPT.getAllocatorId();
650-
ThPool.async(clearBlock, BlockBegin, It);
651-
BlockBegin = It;
652-
}
653-
}
654-
}
602+
ParallelUtilities::runOnEachFunction(
603+
BC, ParallelUtilities::SchedulingPolicy::SP_INST_LINEAR, ClearFunctionSPT,
604+
SkipFunc, "clearSPTMap");
655605

656-
ThPool.async(clearBlock, BlockBegin, BC.getBinaryFunctions().end());
657-
ThPool.wait();
658606
SPTMap.clear();
659607
}
660608

661609
void FrameAnalysis::preComputeSPT() {
662-
// Create a lock that postpone execution of tasks until all allocators are
663-
// initialized
664-
std::shared_timed_mutex Mutex;
665-
std::unique_lock<std::shared_timed_mutex> MainLock(Mutex);
666-
667-
auto runBlock = [&](std::map<uint64_t, BinaryFunction>::iterator BlockBegin,
668-
std::map<uint64_t, BinaryFunction>::iterator BlockEnd,
669-
MCPlusBuilder::AllocatorIdTy AllocId) {
670-
// Wait until all tasks are created
671-
std::shared_lock<std::shared_timed_mutex> Lock(Mutex);
672-
673-
Timer T("preComputeSPT runBlock", "preComputeSPT runBlock");
674-
DEBUG(T.startTimer());
675-
for (auto It = BlockBegin; It != BlockEnd; ++It) {
676-
auto &BF = It->second;
677-
678-
if (!BF.isSimple() || !BF.hasCFG())
679-
continue;
680-
681-
auto &SPTPtr = SPTMap.find(&BF)->second;
682-
SPTPtr = std::make_unique<StackPointerTracking>(BC, BF, AllocId);
683-
SPTPtr->run();
684-
}
685-
DEBUG(T.stopTimer());
686-
};
687-
688610
// Make sure that the SPTMap is empty
689611
assert(SPTMap.size() == 0);
690612

691613
// Create map entries to allow lock-free parallel execution
692-
unsigned TotalCost = 0;
693614
for (auto &BFI : BC.getBinaryFunctions()) {
694615
auto &BF = BFI.second;
695616
if (!BF.isSimple() || !BF.hasCFG())
696617
continue;
697-
TotalCost += BF.size() * BF.size();
698618
SPTMap.emplace(&BF, std::unique_ptr<StackPointerTracking>());
699619
}
700620

701621
// Create an index for the SPT annotation to allow lock-free parallel
702622
// execution
703623
BC.MIB->getOrCreateAnnotationIndex("StackPointerTracking");
704624

705-
// The runtime cost of a single function is estimated by the square of its
706-
// size, the load distribution tries to create blocks of equal runtime.
707-
ThreadPool ThPool(opts::ThreadCount);
708-
const unsigned BlocksCount = 20 * opts::ThreadCount;
709-
const unsigned SingleBlockCost = TotalCost / BlocksCount;
710-
711-
// Split functions into tasks and run them in parallel each using its own
712-
// allocator
713-
auto BlockBegin = BC.getBinaryFunctions().begin();
714-
unsigned CurBlockCost = 0;
715-
for (auto It = BC.getBinaryFunctions().begin();
716-
It != BC.getBinaryFunctions().end(); ++It) {
717-
auto &BF = It->second;
718-
719-
if (BF.isSimple() && BF.hasCFG())
720-
CurBlockCost += BF.size() * BF.size();
721-
722-
if (CurBlockCost >= SingleBlockCost) {
723-
auto AllocId = BC.MIB->initializeNewAnnotationAllocator();
724-
SPTAllocatorsId.push_back(AllocId);
725-
ThPool.async(runBlock, BlockBegin, std::next(It), AllocId);
726-
BlockBegin = std::next(It);
727-
CurBlockCost = 0;
728-
}
729-
}
730-
auto AllocId = BC.MIB->initializeNewAnnotationAllocator();
731-
SPTAllocatorsId.push_back(AllocId);
732-
ThPool.async(runBlock, BlockBegin, BC.getBinaryFunctions().end(), AllocId);
625+
// Run SPT in parallel
626+
ParallelUtilities::WorkFuncWithAllocTy ProcessFunction =
627+
[&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocId) {
628+
auto &SPTPtr = SPTMap.find(&BF)->second;
629+
SPTPtr = std::make_unique<StackPointerTracking>(BC, BF, AllocId);
630+
SPTPtr->run();
631+
};
632+
633+
ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
634+
return !BF.isSimple() || !BF.hasCFG();
635+
};
733636

734-
// Start executing tasks
735-
MainLock.unlock();
736-
ThPool.wait();
637+
ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
638+
BC, ParallelUtilities::SchedulingPolicy::SP_BB_QUADRATIC, ProcessFunction,
639+
SkipPredicate, "preComputeSPT");
737640
}
738641

739642
} // namespace bolt

0 commit comments

Comments
 (0)