diff options
author | weihe <weihe@dev103.prn2.facebook.com> | 2020-06-24 12:43:27 -0700 |
---|---|---|
committer | Wenlei He <aktoon@gmail.com> | 2020-06-24 12:49:46 -0700 |
commit | 53cf53023cbeb47d03fb9937ab3d06181eec8843 (patch) | |
tree | 988b4c088e38bb0e84bee7f8050d369a3ef0bc70 /llvm/tools/llvm-profdata/llvm-profdata.cpp | |
parent | dc3f8913d2ad33b1129ea488393e12cc88061aff (diff) | |
download | llvm-53cf53023cbeb47d03fb9937ab3d06181eec8843.zip llvm-53cf53023cbeb47d03fb9937ab3d06181eec8843.tar.gz llvm-53cf53023cbeb47d03fb9937ab3d06181eec8843.tar.bz2 |
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.
Test Plan:
Reviewers: wenlei, hoyFB
Reviewed By: wenlei, hoyFB
Subscribers: hoyFB, wenlei, weihe, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D82355
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 145 |
1 files changed, 142 insertions, 3 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 3d0e820..5fdb0ce 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,142 @@ static void showSectionInfo(sampleprof::SampleProfileReader *Reader, } } +struct HotFuncInfo { + StringRef FuncName; + uint64_t TotalCount; + double TotalCountPercent; + uint64_t MaxCount; + uint64_t EntryCount; + + HotFuncInfo() + : FuncName(), TotalCount(0), TotalCountPercent(0.0f), MaxCount(0), + EntryCount(0) {} + + HotFuncInfo(StringRef FN, uint64_t TS, double TSP, uint64_t MS, uint64_t ES) + : FuncName(FN), TotalCount(TS), TotalCountPercent(TSP), MaxCount(MS), + EntryCount(ES) {} +}; + +// Print out detailed information about hot functions in PrintValues vector. +// Users specify titles and offset of every columns through ColumnTitle and +// ColumnOffset. The size of ColumnTitle and ColumnOffset need to be the same +// and at least 4. Besides, users can optionally give a HotFuncMetric string to +// print out or let it be an empty string. +static void dumpHotFunctionList(const std::vector<std::string> &ColumnTitle, + const std::vector<int> &ColumnOffset, + const std::vector<HotFuncInfo> &PrintValues, + uint64_t HotFuncCount, uint64_t TotalFuncCount, + uint64_t HotProfCount, uint64_t TotalProfCount, + const std::string &HotFuncMetric, + raw_fd_ostream &OS) { + assert(ColumnOffset.size() == ColumnTitle.size()); + assert(ColumnTitle.size() >= 4); + assert(TotalFuncCount > 0); + double TotalProfPercent = 0; + if (TotalProfCount > 0) + TotalProfPercent = ((double)HotProfCount) / TotalProfCount * 100; + + 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%%", TotalProfPercent) << ") are from hot functions.\n"; + + for (size_t I = 0; I < ColumnTitle.size(); ++I) { + FOS.PadToColumn(ColumnOffset[I]); + FOS << ColumnTitle[I]; + } + FOS << "\n"; + + for (const auto &R : PrintValues) { + FOS.PadToColumn(ColumnOffset[0]); + FOS << R.TotalCount << " (" << format("%.2f%%", R.TotalCountPercent) << ")"; + FOS.PadToColumn(ColumnOffset[1]); + FOS << R.MaxCount; + FOS.PadToColumn(ColumnOffset[2]); + FOS << R.EntryCount; + FOS.PadToColumn(ColumnOffset[3]); + FOS << R.FuncName << "\n"; + } + return; +} + +static int +showHotFunctionList(const StringMap<sampleprof::FunctionSamples> &Profiles, + ProfileSummary &PS, raw_fd_ostream &OS) { + using namespace sampleprof; + + const uint32_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; + } + } + + std::vector<std::string> ColumnTitle{"Total sample (%)", "Max sample", + "Entry sample", "Function name"}; + std::vector<int> ColumnOffset{0, 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; + double TotalSamplePercent = + (ProfileTotalSample > 0) + ? (FuncPtr->getTotalSamples() * 100.0) / ProfileTotalSample + : 0; + PrintValues.emplace_back(HotFuncInfo( + FuncPtr->getFuncName(), FuncPtr->getTotalSamples(), TotalSamplePercent, + FuncPair.second.second, FuncPtr->getEntrySamples())); + } + dumpHotFunctionList(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 +1196,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 +1225,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 +1291,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[]) { |