[llvm] 7348b95 - Add --hot-func-list to llvm-profdata show for sample profiles

Wenlei He via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 20 10:29:52 PDT 2020


Author: weihe
Date: 2020-06-20T10:13:36-07:00
New Revision: 7348b951fe74f306970f6ac567fe5dddbb1c42d4

URL: https://github.com/llvm/llvm-project/commit/7348b951fe74f306970f6ac567fe5dddbb1c42d4
DIFF: https://github.com/llvm/llvm-project/commit/7348b951fe74f306970f6ac567fe5dddbb1c42d4.diff

LOG: Add --hot-func-list to llvm-profdata show for sample profiles

Summary: Add the --hot-func-list feature to llvm-profdata show for sample profiles. This feature prints a list of hot functions whose max sample count are above the 99% threshold, with their numbers of total samples, total samples percentage, max samples, entry samples, and their function names.

Reviewers: wmi, hoyFB, wenlei

Reviewed By: wmi

Subscribers: hoyFB, wenlei, llvm-commits, weihe

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D81800

Added: 
    llvm/test/tools/llvm-profdata/Inputs/sample-hot-func-list.proftext
    llvm/test/tools/llvm-profdata/sample-hot-func-list.test

Modified: 
    llvm/include/llvm/ProfileData/SampleProf.h
    llvm/tools/llvm-profdata/llvm-profdata.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ProfileData/SampleProf.h b/llvm/include/llvm/ProfileData/SampleProf.h
index af636a95bbf8..53087df9fa15 100644
--- a/llvm/include/llvm/ProfileData/SampleProf.h
+++ b/llvm/include/llvm/ProfileData/SampleProf.h
@@ -498,6 +498,21 @@ class FunctionSamples {
     return CallsiteSamples;
   }
 
+  /// Return the maximum of sample counts in a function body including functions
+  /// inlined in it.
+  uint64_t getMaxCountInside() const {
+    uint64_t MaxCount = 0;
+    for (const auto &L : getBodySamples()) {
+      MaxCount = std::max(MaxCount, L.second.getSamples());
+    }
+    for (const auto &C : getCallsiteSamples()) {
+      for (const auto &F : C.second) {
+        MaxCount = std::max(MaxCount, F.second.getMaxCountInside());
+      }
+    }
+    return MaxCount;
+  }
+
   /// Merge the samples in \p Other into this one.
   /// Optionally scale samples by \p Weight.
   sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight = 1) {

diff  --git a/llvm/test/tools/llvm-profdata/Inputs/sample-hot-func-list.proftext b/llvm/test/tools/llvm-profdata/Inputs/sample-hot-func-list.proftext
new file mode 100644
index 000000000000..6e0060371634
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/Inputs/sample-hot-func-list.proftext
@@ -0,0 +1,41 @@
+_Z3bari:20301:1437
+ 1: 1437
+_Z3fooi:7711:610
+ 1: 610
+main:184019:0
+ 4: 534
+ 4.2: 534
+ 5: 1075
+ 5.1: 1075
+ 6: 2080
+ 7: 534
+ 9: 2300 _Z3bari:1471 _Z3fooi:631
+ 10: inline1:1000
+  1: 1000
+ 10: inline2:2000
+  1: 2000
+_Z3bazi:20305:1000
+ 1: 1000
+Func1:1523:169
+ 1: 169
+ 7: 563
+Func2:17043:1594
+ 1: 1594
+ 3: 1594
+ 6: 2009 Func1:150 Func3:1789
+ 13: 3105
+ 17: 3105
+ 19: 1594
+Func3:97401:3035
+ 1: 3035
+ 5: 7344
+ 9: 10640
+ 11: 10640
+ 15: 3035
+Func4:465:210
+ 1: 210
+Func5:6948:470
+ 1: 470
+ 3: 3507
+Func6:310:102
+ 1: 102

diff  --git a/llvm/test/tools/llvm-profdata/sample-hot-func-list.test b/llvm/test/tools/llvm-profdata/sample-hot-func-list.test
new file mode 100644
index 000000000000..352056c6694f
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/sample-hot-func-list.test
@@ -0,0 +1,12 @@
+; RUN: llvm-profdata show --sample --hot-func-list %S/Inputs/sample-hot-func-list.proftext | FileCheck %s
+; CHECK: 8 out of 10 functions with profile (80.00%) are considered hot functions (max sample >= 470).
+; CHECK-NEXT: 355251 out of 356026 profile counts (99.78%) are from hot functions.
+; CHECK-NEXT: Total sample (%)        Max sample        Entry sample    Function name
+; CHECK-NEXT: 184019 (51.69%)         2300              534             main
+; CHECK-NEXT: 97401 (27.36%)          10640             3035            Func3
+; CHECK-NEXT: 20305 (5.70%)           1000              1000            _Z3bazi
+; CHECK-NEXT: 20301 (5.70%)           1437              1437            _Z3bari
+; CHECK-NEXT: 17043 (4.79%)           3105              1594            Func2
+; CHECK-NEXT: 7711 (2.17%)            610               610             _Z3fooi
+; CHECK-NEXT: 6948 (1.95%)            3507              470             Func5
+; CHECK-NEXT: 1523 (0.43%)            563               169             Func1

diff  --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 3d0e820d2f59..0e64f274fd14 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -23,11 +23,12 @@
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/Threading.h"
 #include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
@@ -1026,11 +1027,141 @@ static void showSectionInfo(sampleprof::SampleProfileReader *Reader,
   }
 }
 
+struct HotFuncInfo {
+  StringRef FuncName;
+  uint64_t TotalSample;
+  double TotalSamplePercent;
+  uint64_t MaxSample;
+  uint64_t EntrySample;
+
+  HotFuncInfo()
+      : FuncName(), TotalSample(0), TotalSamplePercent(0.0f), MaxSample(0),
+        EntrySample(0) {}
+
+  HotFuncInfo(StringRef FN, uint64_t TS, double TSP, uint64_t MS, uint64_t ES)
+      : FuncName(FN), TotalSample(TS), TotalSamplePercent(TSP), MaxSample(MS),
+        EntrySample(ES) {}
+};
+
+// Print out detailed information about hot functions in PrinfValues vector.
+// Users specify titles and offset of every columns through ColumnTitle and
+// ColumnOffset. Note that ColumnOffset starts from the offset of the second
+// column (because the first column always starts at offset 0). The size of
+// ColumnTitle and ColumnOffset need to be at least ColNum and ColNum-1. In
+// addition, users can optionally give a HotFuncMetric string to print out or
+// let it be an empty string.
+static void dumpHotFunctionList(
+    const uint64_t &ColNum, const std::vector<std::string> &ColumnTitle,
+    const std::vector<uint64_t> &ColumnOffset,
+    const std::vector<HotFuncInfo> &PrintValues, const uint64_t &HotFuncCount,
+    const uint64_t &TotalFuncCount, const uint64_t &HotProfCount,
+    const uint64_t &TotalProfCount, const std::string &HotFuncMetric,
+    raw_fd_ostream &OS) {
+  assert(ColumnOffset.size() >= ColNum - 1 && ColumnTitle.size() >= ColNum);
+
+  formatted_raw_ostream FOS(OS);
+  FOS << HotFuncCount << " out of " << TotalFuncCount
+      << " functions with profile ("
+      << format("%.2f%%", (((double)HotFuncCount) / TotalFuncCount * 100))
+      << ") are considered hot functions";
+  if (!HotFuncMetric.empty())
+    FOS << " (" << HotFuncMetric << ")";
+  FOS << ".\n";
+  FOS << HotProfCount << " out of " << TotalProfCount << " profile counts ("
+      << format("%.2f%%", (((double)HotProfCount) / TotalProfCount * 100))
+      << ") are from hot functions.\n";
+
+  if (ColNum == 0)
+    return;
+
+  for (size_t I = 0; I < ColNum; ++I) {
+    FOS << ColumnTitle[I];
+    FOS.PadToColumn(ColumnOffset[I]);
+  }
+  FOS << "\n";
+
+  for (const auto &R : PrintValues) {
+    FOS << R.TotalSample << " (" << format("%.2f%%", R.TotalSamplePercent)
+        << ")";
+    FOS.PadToColumn(ColumnOffset.size() > 0 ? ColumnOffset[0] : 0);
+    FOS << R.MaxSample;
+    FOS.PadToColumn(ColumnOffset.size() > 1 ? ColumnOffset[1] : 0);
+    FOS << R.EntrySample;
+    FOS.PadToColumn(ColumnOffset.size() > 2 ? ColumnOffset[2] : 0);
+    FOS << R.FuncName << "\n";
+  }
+  return;
+}
+
+static int
+showHotFunctionList(const StringMap<sampleprof::FunctionSamples> &Profiles,
+                    ProfileSummary &PS, raw_fd_ostream &OS) {
+  using namespace sampleprof;
+
+  const uint64_t HotFuncCutoff = 990000;
+  auto &SummaryVector = PS.getDetailedSummary();
+  uint64_t MinCountThreshold = 0;
+  for (const auto &SummaryEntry : SummaryVector) {
+    if (SummaryEntry.Cutoff == HotFuncCutoff) {
+      MinCountThreshold = SummaryEntry.MinCount;
+      break;
+    }
+  }
+  assert(MinCountThreshold != 0);
+
+  // Traverse all functions in the profile and keep only hot functions.
+  // The following loop also calculates the sum of total samples of all
+  // functions.
+  std::multimap<uint64_t, std::pair<const FunctionSamples *, const uint64_t>,
+                std::greater<uint64_t>>
+      HotFunc;
+  uint64_t ProfileTotalSample = 0;
+  uint64_t HotFuncSample = 0;
+  uint64_t HotFuncCount = 0;
+  uint64_t MaxCount = 0;
+  for (const auto &I : Profiles) {
+    const auto &FuncProf = I.second;
+    ProfileTotalSample += FuncProf.getTotalSamples();
+    MaxCount = FuncProf.getMaxCountInside();
+
+    // MinCountThreshold is a block/line threshold computed for a given cutoff.
+    // We intentionally compare the maximum sample count in a function with this
+    // threshold to get an approximate threshold for hot functions.
+    if (MaxCount >= MinCountThreshold) {
+      HotFunc.emplace(FuncProf.getTotalSamples(),
+                      std::make_pair(&(I.second), MaxCount));
+      HotFuncSample += FuncProf.getTotalSamples();
+      HotFuncCount++;
+    }
+  }
+
+  const uint64_t ColNum = 4;
+  std::vector<std::string> ColumnTitle{"Total sample (%)", "Max sample",
+                                       "Entry sample", "Function name"};
+  std::vector<uint64_t> ColumnOffset{24, 42, 58};
+  std::string Metric =
+      std::string("max sample >= ") + std::to_string(MinCountThreshold);
+  std::vector<HotFuncInfo> PrintValues;
+  for (const auto &FuncPair : HotFunc) {
+    const auto &FuncPtr = FuncPair.second.first;
+    PrintValues.emplace_back(
+        HotFuncInfo(FuncPtr->getFuncName(), FuncPtr->getTotalSamples(),
+                    (FuncPtr->getTotalSamples() * 100.0) / ProfileTotalSample,
+                    FuncPair.second.second, FuncPtr->getEntrySamples()));
+  }
+  dumpHotFunctionList(ColNum, ColumnTitle, ColumnOffset, PrintValues,
+                      HotFuncCount, Profiles.size(), HotFuncSample,
+                      ProfileTotalSample, Metric, OS);
+
+  return 0;
+}
+
 static int showSampleProfile(const std::string &Filename, bool ShowCounts,
                              bool ShowAllFunctions, bool ShowDetailedSummary,
                              const std::string &ShowFunction,
                              bool ShowProfileSymbolList,
-                             bool ShowSectionInfoOnly, raw_fd_ostream &OS) {
+                             bool ShowSectionInfoOnly, bool ShowHotFuncList,
+                             raw_fd_ostream &OS) {
   using namespace sampleprof;
   LLVMContext Context;
   auto ReaderOrErr = SampleProfileReader::create(Filename, Context);
@@ -1064,6 +1195,9 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts,
     PS.printDetailedSummary(OS);
   }
 
+  if (ShowHotFuncList)
+    showHotFunctionList(Reader->getProfiles(), Reader->getSummary(), OS);
+
   return 0;
 }
 
@@ -1090,6 +1224,9 @@ static int show_main(int argc, const char *argv[]) {
       cl::desc(
           "Cutoff percentages (times 10000) for generating detailed summary"),
       cl::value_desc("800000,901000,999999"));
+  cl::opt<bool> ShowHotFuncList(
+      "hot-func-list", cl::init(false),
+      cl::desc("Show profile summary of a list of hot functions"));
   cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
                                  cl::desc("Details for every function"));
   cl::opt<bool> ShowCS("showcs", cl::init(false),
@@ -1153,7 +1290,8 @@ static int show_main(int argc, const char *argv[]) {
   else
     return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
                              ShowDetailedSummary, ShowFunction,
-                             ShowProfileSymbolList, ShowSectionInfoOnly, OS);
+                             ShowProfileSymbolList, ShowSectionInfoOnly,
+                             ShowHotFuncList, OS);
 }
 
 int main(int argc, const char *argv[]) {


        


More information about the llvm-commits mailing list