Skip to content

[profdata] Use --hot-func-list to show all hot functions #149428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ellishg
Copy link
Contributor

@ellishg ellishg commented Jul 18, 2025

The --hot-func-list flag is used for sample profiles to dump the list of hot functions. Add support to dump hot functions for IRPGO profiles as well.

This also removes a priority_queue used for --topn. We can instead store all functions and sort at the end before dumping. Since we are storing hashed names instead of strings, I believe this won't consume too much memory.

@llvmbot llvmbot added the PGO Profile Guided Optimizations label Jul 18, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2025

@llvm/pr-subscribers-pgo

Author: Ellis Hoag (ellishg)

Changes

The --hot-func-list flag is used for sample profiles to dump the list of hot functions. Add support to dump hot functions for IRPGO profiles as well.

This also removes a priority_queue used for --topn. We can instead store all functions and sort at the end before dumping. Since we are storing hashed names instead of strings, I believe this won't consume too much memory.


Full diff: https://github.com/llvm/llvm-project/pull/149428.diff

3 Files Affected:

  • (modified) llvm/test/tools/llvm-profdata/c-general.test (+3-3)
  • (added) llvm/test/tools/llvm-profdata/show-hot.proftext (+35)
  • (modified) llvm/tools/llvm-profdata/llvm-profdata.cpp (+24-28)
diff --git a/llvm/test/tools/llvm-profdata/c-general.test b/llvm/test/tools/llvm-profdata/c-general.test
index 7c48f7b04a05c..ab4849fac034f 100644
--- a/llvm/test/tools/llvm-profdata/c-general.test
+++ b/llvm/test/tools/llvm-profdata/c-general.test
@@ -22,6 +22,6 @@ SWITCHES-LABEL: Functions shown: 1
 CHECK-LABEL: Total functions: 12
 CHECK-NEXT: Maximum function count: 1
 CHECK-NEXT: Maximum internal block count: 100
-TOPN: boolean_operators, max count = 100
-TOPN-NEXT: simple_loops, max count = 100
-TOPN-NEXT:  conditionals, max count = 100
+TOPN:         simple_loops, max count = 100
+TOPN-NEXT:    conditionals, max count = 100
+TOPN-NEXT:    boolean_operators, max count = 100
diff --git a/llvm/test/tools/llvm-profdata/show-hot.proftext b/llvm/test/tools/llvm-profdata/show-hot.proftext
new file mode 100644
index 0000000000000..5c9bd61c20d28
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/show-hot.proftext
@@ -0,0 +1,35 @@
+# RUN: llvm-profdata show %s --hot-func-list | FileCheck %s
+
+# CHECK: # Hot count threshold: 101
+# CHECK: hot_b
+# CHECK: hot_a
+# CHECK: hot_c
+
+:ir
+hot_a
+# Func Hash:
+0x1234
+# Num Counters:
+1
+# Counter Values:
+101
+
+hot_b
+0x5678
+1
+202
+
+hot_c
+0x5678
+1
+101
+
+cold_d
+0xabcd
+1
+1
+
+cold_e
+0xefff
+1
+0
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 45eac90aef935..f6d5c0cf14914 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -2849,9 +2849,9 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
   auto FS = vfs::getRealFileSystem();
   auto ReaderOrErr = InstrProfReader::create(Filename, *FS);
   std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
-  if (ShowDetailedSummary && Cutoffs.empty()) {
-    Cutoffs = ProfileSummaryBuilder::DefaultCutoffs;
-  }
+  if (Cutoffs.empty())
+    if (ShowDetailedSummary || ShowHotFuncList)
+      Cutoffs = ProfileSummaryBuilder::DefaultCutoffs;
   InstrProfSummaryBuilder Builder(std::move(Cutoffs));
   if (Error E = ReaderOrErr.takeError())
     exitWithError(std::move(E), Filename);
@@ -2863,15 +2863,7 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
   int NumVPKind = IPVK_Last - IPVK_First + 1;
   std::vector<ValueSitesStats> VPStats(NumVPKind);
 
-  auto MinCmp = [](const std::pair<std::string, uint64_t> &v1,
-                   const std::pair<std::string, uint64_t> &v2) {
-    return v1.second > v2.second;
-  };
-
-  std::priority_queue<std::pair<std::string, uint64_t>,
-                      std::vector<std::pair<std::string, uint64_t>>,
-                      decltype(MinCmp)>
-      HottestFuncs(MinCmp);
+  std::vector<std::pair<uint64_t, uint64_t>> NameRefAndMaxCount;
 
   if (!TextFormat && OnlyListBelow) {
     OS << "The list of functions with the maximum counter less than "
@@ -2946,15 +2938,9 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
     } else if (OnlyListBelow)
       continue;
 
-    if (TopNFunctions) {
-      if (HottestFuncs.size() == TopNFunctions) {
-        if (HottestFuncs.top().second < FuncMax) {
-          HottestFuncs.pop();
-          HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
-        }
-      } else
-        HottestFuncs.emplace(std::make_pair(std::string(Func.Name), FuncMax));
-    }
+    if (TopNFunctions || ShowHotFuncList)
+      NameRefAndMaxCount.emplace_back(IndexedInstrProf::ComputeHash(Func.Name),
+                                      FuncMax);
 
     if (Show) {
       if (!ShownFunctions)
@@ -3034,16 +3020,26 @@ static int showInstrProfile(ShowFormat SFormat, raw_fd_ostream &OS) {
        << "): " << PS->getNumFunctions() - BelowCutoffFunctions << "\n";
   }
 
+  // Sort by MaxCount in decreasing order
+  llvm::stable_sort(NameRefAndMaxCount, [](const auto &L, const auto &R) {
+    return L.second > R.second;
+  });
   if (TopNFunctions) {
-    std::vector<std::pair<std::string, uint64_t>> SortedHottestFuncs;
-    while (!HottestFuncs.empty()) {
-      SortedHottestFuncs.emplace_back(HottestFuncs.top());
-      HottestFuncs.pop();
-    }
     OS << "Top " << TopNFunctions
        << " functions with the largest internal block counts: \n";
-    for (auto &hotfunc : llvm::reverse(SortedHottestFuncs))
-      OS << "  " << hotfunc.first << ", max count = " << hotfunc.second << "\n";
+    auto TopFuncs = ArrayRef(NameRefAndMaxCount).take_front(TopNFunctions);
+    for (auto [NameRef, MaxCount] : TopFuncs)
+      OS << "  " << Reader->getSymtab().getFuncOrVarName(NameRef)
+         << ", max count = " << MaxCount << "\n";
+  }
+
+  if (ShowHotFuncList) {
+    auto HotCountThreshold =
+        ProfileSummaryBuilder::getHotCountThreshold(PS->getDetailedSummary());
+    OS << "# Hot count threshold: " << HotCountThreshold << "\n";
+    for (auto [NameRef, MaxCount] : NameRefAndMaxCount)
+      if (MaxCount >= HotCountThreshold)
+        OS << Reader->getSymtab().getFuncOrVarName(NameRef) << "\n";
   }
 
   if (ShownFunctions && ShowIndirectCallTargets) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PGO Profile Guided Optimizations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants