From 03e94f66087ea48a6321738130bdf85e714ad281 Mon Sep 17 00:00:00 2001 From: Maksim Panchenko Date: Fri, 24 Feb 2023 15:45:21 -0800 Subject: [PATCH] [BOLT] Change call count output for ICF ICF optimization runs multiple passes and the order in which functions are folded could be dependent on the order they are being processed. This order is indeterministic as functions are intermediately stored in std::unordered_map<>. Note that this order is mostly stable, but is not guaranteed to be and can change e.g. after switching to a different C++ library implementation. Because the processing (and folding) order is indeterministic, the previous way of calculating merged function call count could produce different results. Change the way we calculate the ICF call count to make it independent of the function folding/processing order. Mostly NFC as the output binary should remain the same, the change affects only the console output. Reviewed By: yota9 Differential Revision: https://reviews.llvm.org/D144807 --- bolt/include/bolt/Core/BinaryFunction.h | 9 +++++++++ bolt/lib/Core/BinaryContext.cpp | 2 ++ bolt/lib/Passes/IdenticalCodeFolding.cpp | 12 +++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index fd243a4f9fa8..ddff1315aee3 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -349,6 +349,9 @@ private: /// This attribute is only valid when hasCFG() == true. bool HasCanonicalCFG{true}; + /// True if another function body was merged into this one. + bool HasFunctionsFoldedInto{false}; + /// Name for the section this function code should reside in. std::string CodeSectionName; @@ -1407,6 +1410,9 @@ public: /// Return true if the body of the function was merged into another function. bool isFolded() const { return FoldedIntoFunction != nullptr; } + /// Return true if other functions were folded into this one. + bool hasFunctionsFoldedInto() const { return HasFunctionsFoldedInto; } + /// If this function was folded, return the function it was folded into. BinaryFunction *getFoldedIntoFunction() const { return FoldedIntoFunction; } @@ -1770,6 +1776,9 @@ public: void setFolded(BinaryFunction *BF) { FoldedIntoFunction = BF; } + /// Indicate that another function body was merged with this function. + void setHasFunctionsFoldedInto() { HasFunctionsFoldedInto = true; } + BinaryFunction &setPersonalityFunction(uint64_t Addr) { assert(!PersonalityFunction && "can't set personality function twice"); PersonalityFunction = BC.getOrCreateGlobalSymbol(Addr, "FUNCat"); diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 9942b5ddede7..9403b1b80aa9 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -1345,6 +1345,8 @@ void BinaryContext::foldFunction(BinaryFunction &ChildBF, ChildBF.setFolded(&ParentBF); } + + ParentBF.setHasFunctionsFoldedInto(); } void BinaryContext::fixBinaryDataHoles() { diff --git a/bolt/lib/Passes/IdenticalCodeFolding.cpp b/bolt/lib/Passes/IdenticalCodeFolding.cpp index 9695eb6fa3e2..ccf1749c47bf 100644 --- a/bolt/lib/Passes/IdenticalCodeFolding.cpp +++ b/bolt/lib/Passes/IdenticalCodeFolding.cpp @@ -413,7 +413,7 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { uint64_t NumFunctionsFolded = 0; std::atomic NumJTFunctionsFolded{0}; std::atomic BytesSavedEstimate{0}; - std::atomic CallsSavedEstimate{0}; + std::atomic NumCalled{0}; std::atomic NumFoldedLastIteration{0}; CongruentBucketsMap CongruentBuckets; @@ -493,6 +493,8 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { }); BinaryFunction *ParentBF = Twins[0]; + if (!ParentBF->hasFunctionsFoldedInto()) + NumCalled += ParentBF->getKnownExecutionCount(); for (unsigned I = 1; I < Twins.size(); ++I) { BinaryFunction *ChildBF = Twins[I]; LLVM_DEBUG(dbgs() << "BOLT-DEBUG: folding " << *ChildBF << " into " @@ -506,8 +508,8 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { // Fold the function and remove from the list of processed functions. BytesSavedEstimate += ChildBF->getSize(); - CallsSavedEstimate += std::min(ChildBF->getKnownExecutionCount(), - ParentBF->getKnownExecutionCount()); + if (!ChildBF->hasFunctionsFoldedInto()) + NumCalled += ChildBF->getKnownExecutionCount(); BC.foldFunction(*ChildBF, *ParentBF); ++NumFoldedLastIteration; @@ -579,8 +581,8 @@ void IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) { << " functions had jump tables.\n" << "BOLT-INFO: Removing all identical functions will save " << format("%.2lf", (double)BytesSavedEstimate / 1024) - << " KB of code space. Folded functions were called " - << CallsSavedEstimate << " times based on profile.\n"; + << " KB of code space. Folded functions were called " << NumCalled + << " times based on profile.\n"; } } // namespace bolt