diff options
author | Ellis Hoag <ellis.sparky.hoag@gmail.com> | 2023-04-11 07:58:47 -0700 |
---|---|---|
committer | Ellis Hoag <ellis.sparky.hoag@gmail.com> | 2023-04-11 08:30:52 -0700 |
commit | 244be0b0de198fbe8a0861bb8f75509f610b57a4 (patch) | |
tree | 9182f8398c1bb41b9fb290fce766baeba4ea8386 /llvm/tools/llvm-profdata/llvm-profdata.cpp | |
parent | d288411c8aef1820366d477aa8f90ed6a52d70ee (diff) | |
download | llvm-244be0b0de198fbe8a0861bb8f75509f610b57a4.zip llvm-244be0b0de198fbe8a0861bb8f75509f610b57a4.tar.gz llvm-244be0b0de198fbe8a0861bb8f75509f610b57a4.tar.bz2 |
[InstrProf] Temporal Profiling
As described in [0], this extends IRPGO to support //Temporal Profiling//.
When `-pgo-temporal-instrumentation` is used we add the `llvm.instrprof.timestamp()` intrinsic to the entry of functions which in turn gets lowered to a call to the compiler-rt function `INSTR_PROF_PROFILE_SET_TIMESTAMP()`. A new field in the `llvm_prf_cnts` section stores each function's timestamp. Then in `llvm-profdata merge` we convert these function timestamps into a //trace// and add it to the indexed profile.
Since these traces could significantly increase the profile size, we've added `-max-temporal-profile-trace-length` and `-temporal-profile-trace-reservoir-size` to limit the length of a trace and the number of traces in a profile, respectively.
In a future diff we plan to use these traces to construct an optimized function order to reduce the number of page faults during startup.
Special thanks to Julian Mestre for helping with reservoir sampling.
[0] https://discourse.llvm.org/t/rfc-temporal-profiling-extension-for-irpgo/68068
Reviewed By: snehasish
Differential Revision: https://reviews.llvm.org/D147287
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 85 |
1 files changed, 60 insertions, 25 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 64cf3cf..44219e4 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -216,9 +216,10 @@ struct WriterContext { SmallSet<instrprof_error, 4> &WriterErrorCodes; WriterContext(bool IsSparse, std::mutex &ErrLock, - SmallSet<instrprof_error, 4> &WriterErrorCodes) - : Writer(IsSparse), ErrLock(ErrLock), WriterErrorCodes(WriterErrorCodes) { - } + SmallSet<instrprof_error, 4> &WriterErrorCodes, + uint64_t ReservoirSize = 0, uint64_t MaxTraceLength = 0) + : Writer(IsSparse, ReservoirSize, MaxTraceLength), ErrLock(ErrLock), + WriterErrorCodes(WriterErrorCodes) {} }; /// Computer the overlap b/w profile BaseFilename and TestFileName, @@ -304,7 +305,7 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper, auto FS = vfs::getRealFileSystem(); auto ReaderOrErr = InstrProfReader::create(Input.Filename, *FS, Correlator); if (Error E = ReaderOrErr.takeError()) { - // Skip the empty profiles by returning sliently. + // Skip the empty profiles by returning silently. instrprof_error IPE = InstrProfError::take(std::move(E)); if (IPE != instrprof_error::empty_raw_profile) WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename); @@ -342,6 +343,12 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper, }); } + if (Reader->hasTemporalProfile()) { + auto &Traces = Reader->getTemporalProfTraces(); + if (!Traces.empty()) + WC->Writer.addTemporalProfileTraces( + Traces, Reader->getTemporalProfTraceStreamSize()); + } if (Reader->hasError()) { if (Error E = Reader->getError()) WC->Errors.emplace_back(std::move(E), Filename); @@ -392,13 +399,13 @@ static void writeInstrProfile(StringRef OutputFilename, } } -static void mergeInstrProfile(const WeightedFileVector &Inputs, - StringRef DebugInfoFilename, - SymbolRemapper *Remapper, - StringRef OutputFilename, - ProfileFormat OutputFormat, bool OutputSparse, - unsigned NumThreads, FailureMode FailMode, - const StringRef ProfiledBinary) { +static void +mergeInstrProfile(const WeightedFileVector &Inputs, StringRef DebugInfoFilename, + SymbolRemapper *Remapper, StringRef OutputFilename, + ProfileFormat OutputFormat, uint64_t TraceReservoirSize, + uint64_t MaxTraceLength, bool OutputSparse, + unsigned NumThreads, FailureMode FailMode, + const StringRef ProfiledBinary) { if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary && OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text) exitWithError("unknown format is specified"); @@ -424,7 +431,8 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, SmallVector<std::unique_ptr<WriterContext>, 4> Contexts; for (unsigned I = 0; I < NumThreads; ++I) Contexts.emplace_back(std::make_unique<WriterContext>( - OutputSparse, ErrorLock, WriterErrorCodes)); + OutputSparse, ErrorLock, WriterErrorCodes, TraceReservoirSize, + MaxTraceLength)); if (NumThreads == 1) { for (const auto &Input : Inputs) @@ -1264,6 +1272,17 @@ static int merge_main(int argc, const char *argv[]) { "drop-profile-symbol-list", cl::init(false), cl::Hidden, cl::desc("Drop the profile symbol list when merging AutoFDO profiles " "(only meaningful for -sample)")); + // WARNING: This reservoir size value is propagated to any input indexed + // profiles for simplicity. Changing this value between invocations could + // result in sample bias. + cl::opt<uint64_t> TemporalProfTraceReservoirSize( + "temporal-profile-trace-reservoir-size", cl::init(100), + cl::desc("The maximum number of stored temporal profile traces (default: " + "100)")); + cl::opt<uint64_t> MaxTemporalProfTraceLength( + "max-temporal-profile-trace-length", cl::init(10000), + cl::desc("The maximum length of a single temporal profile trace " + "(default: 10000)")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); @@ -1305,7 +1324,9 @@ static int merge_main(int argc, const char *argv[]) { if (ProfileKind == instr) mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(), - OutputFilename, OutputFormat, OutputSparse, NumThreads, + OutputFilename, OutputFormat, + TemporalProfTraceReservoirSize, + MaxTemporalProfTraceLength, OutputSparse, NumThreads, FailureMode, ProfiledBinary); else mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename, @@ -2384,16 +2405,14 @@ static void showValueSitesStats(raw_fd_ostream &OS, uint32_t VK, } } -static int showInstrProfile(const std::string &Filename, bool ShowCounts, - uint32_t TopN, bool ShowIndirectCallTargets, - bool ShowMemOPSizes, bool ShowDetailedSummary, - std::vector<uint32_t> DetailedSummaryCutoffs, - bool ShowAllFunctions, bool ShowCS, - uint64_t ValueCutoff, bool OnlyListBelow, - const std::string &ShowFunction, bool TextFormat, - bool ShowBinaryIds, bool ShowCovered, - bool ShowProfileVersion, ShowFormat SFormat, - raw_fd_ostream &OS) { +static int showInstrProfile( + const std::string &Filename, bool ShowCounts, uint32_t TopN, + bool ShowIndirectCallTargets, bool ShowMemOPSizes, bool ShowDetailedSummary, + std::vector<uint32_t> DetailedSummaryCutoffs, bool ShowAllFunctions, + bool ShowCS, uint64_t ValueCutoff, bool OnlyListBelow, + const std::string &ShowFunction, bool TextFormat, bool ShowBinaryIds, + bool ShowCovered, bool ShowProfileVersion, bool ShowTemporalProfTraces, + ShowFormat SFormat, raw_fd_ostream &OS) { if (SFormat == ShowFormat::Json) exitWithError("JSON output is not supported for instr profiles"); if (SFormat == ShowFormat::Yaml) @@ -2610,6 +2629,19 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts, if (ShowProfileVersion) OS << "Profile version: " << Reader->getVersion() << "\n"; + + if (ShowTemporalProfTraces) { + auto &Traces = Reader->getTemporalProfTraces(); + OS << "Temporal Profile Traces (samples=" << Traces.size() + << " seen=" << Reader->getTemporalProfTraceStreamSize() << "):\n"; + for (unsigned i = 0; i < Traces.size(); i++) { + OS << " Temporal Profile Trace " << i << " (count=" << Traces[i].size() + << "):\n"; + for (auto &NameRef : Traces[i]) + OS << " " << Reader->getSymtab().getFuncName(NameRef) << "\n"; + } + } + return 0; } @@ -2945,6 +2977,9 @@ static int show_main(int argc, const char *argv[]) { "extbinary format")); cl::opt<bool> ShowBinaryIds("binary-ids", cl::init(false), cl::desc("Show binary ids in the profile. ")); + cl::opt<bool> ShowTemporalProfTraces( + "temporal-profile-traces", + cl::desc("Show temporal profile traces in the profile.")); cl::opt<std::string> DebugInfoFilename( "debug-info", cl::init(""), cl::desc("Read and extract profile metadata from debug info and show " @@ -2989,8 +3024,8 @@ static int show_main(int argc, const char *argv[]) { Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets, ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs, ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction, - TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion, SFormat, - OS); + TextFormat, ShowBinaryIds, ShowCovered, ShowProfileVersion, + ShowTemporalProfTraces, SFormat, OS); if (ProfileKind == sample) return showSampleProfile(Filename, ShowCounts, TopNFunctions, ShowAllFunctions, ShowDetailedSummary, |