[llvm] [BasicBlockSections] Propose a staleness detection by checking the func cfg node num (PR #133244)

Jinjie Huang via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 27 05:51:44 PDT 2025


https://github.com/Jinjie-Huang created https://github.com/llvm/llvm-project/pull/133244

This patch introduces ‘light-weight’ method to detect the propeller profile staleness. 
To achieve this, the CFG node count of a function can be emitted into the profile (create_llvm_prof tool can obtain this information from the .llvm_bb_addr_map). This allows for  the detection of changes in the CFG during optimization.

If 'node_count' is not provided in the profile, the check will not be enabled.


>From d574f68d14f7f7ef9335e270b40afa9955987b24 Mon Sep 17 00:00:00 2001
From: huangjinjie <huangjinjie at bytedance.com>
Date: Thu, 27 Mar 2025 20:22:53 +0800
Subject: [PATCH] propose a check for func cfg node num

---
 .../CodeGen/BasicBlockSectionsProfileReader.h |  7 ++++++
 llvm/lib/CodeGen/BasicBlockSections.cpp       | 12 ++++++++++
 .../BasicBlockSectionsProfileReader.cpp       | 22 +++++++++++++++++++
 3 files changed, 41 insertions(+)

diff --git a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
index 08e6a0e3ef629..51000efd7f219 100644
--- a/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
+++ b/llvm/include/llvm/CodeGen/BasicBlockSectionsProfileReader.h
@@ -50,6 +50,8 @@ struct FunctionPathAndClusterInfo {
   // the edge a -> b (a is not cloned). The index of the path in this vector
   // determines the `UniqueBBID::CloneID` of the cloned blocks in that path.
   SmallVector<SmallVector<unsigned>> ClonePaths;
+  // Node count of the func CFG, record for staleness check
+  unsigned NodeCount;
 };
 
 // Provides DenseMapInfo for UniqueBBID.
@@ -94,6 +96,9 @@ class BasicBlockSectionsProfileReader {
   std::pair<bool, SmallVector<BBClusterInfo>>
   getClusterInfoForFunction(StringRef FuncName) const;
 
+  // Returns the cfg node count of the CFG for the given function.
+  unsigned getCfgNodeNumForFunction(StringRef FuncName) const;
+
   // Returns the path clonings for the given function.
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
@@ -201,6 +206,8 @@ class BasicBlockSectionsProfileReaderWrapperPass : public ImmutablePass {
   std::pair<bool, SmallVector<BBClusterInfo>>
   getClusterInfoForFunction(StringRef FuncName) const;
 
+  unsigned getCfgNodeNumForFunction(StringRef FuncName) const;
+
   SmallVector<SmallVector<unsigned>>
   getClonePathsForFunction(StringRef FuncName) const;
 
diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp
index 1eedfc4b25912..ad2e86ea16c58 100644
--- a/llvm/lib/CodeGen/BasicBlockSections.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSections.cpp
@@ -80,6 +80,7 @@
 #include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Target/TargetMachine.h"
+#include "llvm/Support/WithColor.h"
 #include <optional>
 
 using namespace llvm;
@@ -311,6 +312,7 @@ bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
   // original layout positions and finding the original fallthroughs.
   MF.RenumberBlocks();
 
+  unsigned NodeCount = 0;
   DenseMap<UniqueBBID, BBClusterInfo> FuncClusterInfo;
   if (BBSectionsType == BasicBlockSection::List) {
     auto [HasProfile, ClusterInfo] =
@@ -318,6 +320,16 @@ bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
             .getClusterInfoForFunction(MF.getName());
     if (!HasProfile)
       return false;
+    
+    NodeCount = getAnalysis<BasicBlockSectionsProfileReaderWrapperPass>()
+                    .getCfgNodeNumForFunction(MF.getName());
+    if ((NodeCount != 0) && (NodeCount != MF.size())) {
+      WithColor::warning() << "MF " << MF.getName() << ": node count mismatch "
+                        << "(profile=" << NodeCount
+                        << " actual=" << MF.size() << ")\n";
+      return false;
+    }
+
     for (auto &BBClusterInfo : ClusterInfo) {
       FuncClusterInfo.try_emplace(BBClusterInfo.BBID, BBClusterInfo);
     }
diff --git a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
index fa54640265162..06e5034522bd4 100644
--- a/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSectionsProfileReader.cpp
@@ -69,6 +69,13 @@ BasicBlockSectionsProfileReader::getClusterInfoForFunction(
              : std::pair(false, SmallVector<BBClusterInfo>());
 }
 
+unsigned BasicBlockSectionsProfileReader::getCfgNodeNumForFunction(
+    StringRef FuncName) const {
+  auto R = ProgramPathAndClusterInfo.find(getAliasName(FuncName));
+  return R != ProgramPathAndClusterInfo.end()
+             ? R->second.NodeCount : 0;
+}
+
 SmallVector<SmallVector<unsigned>>
 BasicBlockSectionsProfileReader::getClonePathsForFunction(
     StringRef FuncName) const {
@@ -263,6 +270,16 @@ Error BasicBlockSectionsProfileReader::ReadV0Profile() {
     StringRef S(*LineIt);
     if (S[0] == '@')
       continue;
+
+    // Record the function cfg node num for staleness check
+    if (S.consume_front("$node_count")) {
+      unsigned long long NodeCount;
+      if (getAsUnsignedInteger(S.trim(), 10, NodeCount))
+        return invalidProfileError("Invalid node count value.");
+      if (FI != ProgramBBClusterInfo.end())
+        FI->second.NodeCount = (unsigned)NodeCount;
+      continue;
+    }
     // Check for the leading "!"
     if (!S.consume_front("!") || S.empty())
       break;
@@ -433,6 +450,11 @@ BasicBlockSectionsProfileReaderWrapperPass::getClusterInfoForFunction(
   return BBSPR.getClusterInfoForFunction(FuncName);
 }
 
+unsigned BasicBlockSectionsProfileReaderWrapperPass::getCfgNodeNumForFunction(
+    StringRef FuncName) const {
+  return BBSPR.getCfgNodeNumForFunction(FuncName);
+}
+
 SmallVector<SmallVector<unsigned>>
 BasicBlockSectionsProfileReaderWrapperPass::getClonePathsForFunction(
     StringRef FuncName) const {



More information about the llvm-commits mailing list