[llvm] 6da9241 - [llvm-profgen] Refactor PerfReader to allow different types of perf scripts
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 2 17:20:07 PDT 2021
Author: wlei
Date: 2021-08-02T17:18:47-07:00
New Revision: 6da9241aabe12c07fb905e5b3d2e4e16ef7d4296
URL: https://github.com/llvm/llvm-project/commit/6da9241aabe12c07fb905e5b3d2e4e16ef7d4296
DIFF: https://github.com/llvm/llvm-project/commit/6da9241aabe12c07fb905e5b3d2e4e16ef7d4296.diff
LOG: [llvm-profgen] Refactor PerfReader to allow different types of perf scripts
In order to support different types of perf scripts, this change tried to refactor `PerfReader` by adding the base class `PerfReaderBase` and current HybridPerfReader is derived from it for CS profile generation. Common functions like, passMM2PEvents, extract_lbrs, extract_callstack, etc. can be reused.
Next step is to add LBR only reader(for non-CS profile) and aggregated perf scripts reader(do a pre-aggregation of scripts).
Reviewed By: hoy, wenlei
Differential Revision: https://reviews.llvm.org/D107014
Added:
Modified:
llvm/tools/llvm-profgen/PerfReader.cpp
llvm/tools/llvm-profgen/PerfReader.h
llvm/tools/llvm-profgen/ProfiledBinary.h
llvm/tools/llvm-profgen/llvm-profgen.cpp
Removed:
################################################################################
diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index f6b394e7966fd..d95ce49d0ab98 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -241,7 +241,7 @@ bool VirtualUnwinder::unwind(const HybridSample *Sample, uint64_t Repeat) {
return true;
}
-void PerfReader::validateCommandLine(
+void PerfReaderBase::validateCommandLine(
cl::list<std::string> &BinaryFilenames,
cl::list<std::string> &PerfTraceFilenames) {
// Allow the invalid perfscript if we only use to show binary disassembly
@@ -276,16 +276,33 @@ void PerfReader::validateCommandLine(
}
}
-PerfReader::PerfReader(cl::list<std::string> &BinaryFilenames,
+std::unique_ptr<PerfReaderBase>
+PerfReaderBase::create(cl::list<std::string> &BinaryFilenames,
cl::list<std::string> &PerfTraceFilenames) {
validateCommandLine(BinaryFilenames, PerfTraceFilenames);
+
+ PerfScriptType PerfType = extractPerfType(PerfTraceFilenames);
+ std::unique_ptr<PerfReaderBase> PerfReader;
+ if (PerfType == PERF_LBR_STACK) {
+ PerfReader.reset(new HybridPerfReader(BinaryFilenames));
+ } else if (PerfType == PERF_LBR) {
+ // TODO:
+ exitWithError("Unsupported perfscript!");
+ } else {
+ exitWithError("Unsupported perfscript!");
+ }
+
+ return PerfReader;
+}
+
+PerfReaderBase::PerfReaderBase(cl::list<std::string> &BinaryFilenames) {
// Load the binaries.
for (auto Filename : BinaryFilenames)
loadBinary(Filename, /*AllowNameConflict*/ false);
}
-ProfiledBinary &PerfReader::loadBinary(const StringRef BinaryPath,
- bool AllowNameConflict) {
+ProfiledBinary &PerfReaderBase::loadBinary(const StringRef BinaryPath,
+ bool AllowNameConflict) {
// The binary table is currently indexed by the binary name not the full
// binary path. This is because the user-given path may not match the one
// that was actually executed.
@@ -303,7 +320,7 @@ ProfiledBinary &PerfReader::loadBinary(const StringRef BinaryPath,
return Ret.first->second;
}
-void PerfReader::updateBinaryAddress(const MMapEvent &Event) {
+void PerfReaderBase::updateBinaryAddress(const MMapEvent &Event) {
// Load the binary.
StringRef BinaryPath = Event.BinaryPath;
StringRef BinaryName = llvm::sys::path::filename(BinaryPath);
@@ -353,7 +370,7 @@ void PerfReader::updateBinaryAddress(const MMapEvent &Event) {
}
}
-ProfiledBinary *PerfReader::getBinary(uint64_t Address) {
+ProfiledBinary *PerfReaderBase::getBinary(uint64_t Address) {
auto Iter = AddrToBinaryMap.lower_bound(Address);
if (Iter == AddrToBinaryMap.end() || Iter->first != Address) {
if (Iter == AddrToBinaryMap.begin())
@@ -415,7 +432,7 @@ static void printBranchCounter(ContextSampleCounterMap &Counter,
printSampleCounter(OrderedCounter);
}
-void PerfReader::printUnwinderOutput() {
+void HybridPerfReader::printUnwinderOutput() {
for (auto I : BinarySampleCounters) {
const ProfiledBinary *Binary = I.first;
outs() << "Binary(" << Binary->getName().str() << ")'s Range Counter:\n";
@@ -425,7 +442,7 @@ void PerfReader::printUnwinderOutput() {
}
}
-void PerfReader::unwindSamples() {
+void HybridPerfReader::unwindSamples() {
for (const auto &Item : AggregatedSamples) {
const HybridSample *Sample = dyn_cast<HybridSample>(Item.first.getPtr());
VirtualUnwinder Unwinder(&BinarySampleCounters[Sample->Binary],
@@ -437,9 +454,9 @@ void PerfReader::unwindSamples() {
printUnwinderOutput();
}
-bool PerfReader::extractLBRStack(TraceStream &TraceIt,
- SmallVectorImpl<LBREntry> &LBRStack,
- ProfiledBinary *Binary) {
+bool PerfReaderBase::extractLBRStack(TraceStream &TraceIt,
+ SmallVectorImpl<LBREntry> &LBRStack,
+ ProfiledBinary *Binary) {
// The raw format of LBR stack is like:
// 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 ...
// ... 0x4005c8/0x4005dc/P/-/-/0
@@ -531,8 +548,8 @@ bool PerfReader::extractLBRStack(TraceStream &TraceIt,
return !LBRStack.empty();
}
-bool PerfReader::extractCallstack(TraceStream &TraceIt,
- SmallVectorImpl<uint64_t> &CallStack) {
+bool PerfReaderBase::extractCallstack(TraceStream &TraceIt,
+ SmallVectorImpl<uint64_t> &CallStack) {
// The raw format of call stack is like:
// 4005dc # leaf frame
// 400634
@@ -593,7 +610,7 @@ bool PerfReader::extractCallstack(TraceStream &TraceIt,
!Binary->addressInPrologEpilog(CallStack.front());
}
-void PerfReader::parseHybridSample(TraceStream &TraceIt) {
+void HybridPerfReader::parseSample(TraceStream &TraceIt) {
// The raw hybird sample started with call stack in FILO order and followed
// intermediately by LBR sample
// e.g.
@@ -631,7 +648,7 @@ void PerfReader::parseHybridSample(TraceStream &TraceIt) {
}
}
-void PerfReader::parseMMap2Event(TraceStream &TraceIt) {
+void PerfReaderBase::parseMMap2Event(TraceStream &TraceIt) {
// Parse a line like:
// PERF_RECORD_MMAP2 2113428/2113428: [0x7fd4efb57000(0x204000) @ 0
// 08:04 19532229 3585508847]: r-xp /usr/lib64/libdl-2.17.so
@@ -677,26 +694,23 @@ void PerfReader::parseMMap2Event(TraceStream &TraceIt) {
TraceIt.advance();
}
-void PerfReader::parseEventOrSample(TraceStream &TraceIt) {
+void PerfReaderBase::parseEventOrSample(TraceStream &TraceIt) {
if (TraceIt.getCurrentLine().startswith("PERF_RECORD_MMAP2"))
parseMMap2Event(TraceIt);
- else if (getPerfScriptType() == PERF_LBR_STACK)
- parseHybridSample(TraceIt);
- else {
- // TODO: parse other type sample
- TraceIt.advance();
- }
+ else
+ parseSample(TraceIt);
}
-void PerfReader::parseAndAggregateTrace(StringRef Filename) {
+void PerfReaderBase::parseAndAggregateTrace(StringRef Filename) {
// Trace line iterator
TraceStream TraceIt(Filename);
while (!TraceIt.isAtEoF())
parseEventOrSample(TraceIt);
}
-void PerfReader::checkAndSetPerfType(
- cl::list<std::string> &PerfTraceFilenames) {
+PerfScriptType
+PerfReaderBase::extractPerfType(cl::list<std::string> &PerfTraceFilenames) {
+ PerfScriptType PerfType = PERF_UNKNOWN;
for (auto FileName : PerfTraceFilenames) {
PerfScriptType Type = checkPerfScriptType(FileName);
if (Type == PERF_INVALID)
@@ -705,20 +719,13 @@ void PerfReader::checkAndSetPerfType(
exitWithError("Inconsistent sample among
diff erent perf scripts");
PerfType = Type;
}
+ return PerfType;
}
-void PerfReader::generateRawProfile() {
- if (getPerfScriptType() == PERF_LBR_STACK) {
- // Unwind samples if it's hybird sample
- unwindSamples();
- } else if (getPerfScriptType() == PERF_LBR) {
- // TODO: range overlap computation for regular AutoFDO
- }
-}
+void HybridPerfReader::generateRawProfile() { unwindSamples(); }
-void PerfReader::parsePerfTraces(cl::list<std::string> &PerfTraceFilenames) {
- // Check and set current perfscript type
- checkAndSetPerfType(PerfTraceFilenames);
+void PerfReaderBase::parsePerfTraces(
+ cl::list<std::string> &PerfTraceFilenames) {
// Parse perf traces and do aggregation.
for (auto Filename : PerfTraceFilenames)
parseAndAggregateTrace(Filename);
diff --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h
index 05bf2d698c528..630d14a0c44c2 100644
--- a/llvm/tools/llvm-profgen/PerfReader.h
+++ b/llvm/tools/llvm-profgen/PerfReader.h
@@ -541,11 +541,13 @@ using BinarySampleCounterMap =
std::unordered_map<ProfiledBinary *, ContextSampleCounterMap>;
// Load binaries and read perf trace to parse the events and samples
-class PerfReader {
-
+class PerfReaderBase {
public:
- PerfReader(cl::list<std::string> &BinaryFilenames,
- cl::list<std::string> &PerfTraceFilenames);
+ PerfReaderBase(cl::list<std::string> &BinaryFilenames);
+ virtual ~PerfReaderBase() = default;
+ static std::unique_ptr<PerfReaderBase>
+ create(cl::list<std::string> &BinaryFilenames,
+ cl::list<std::string> &PerfTraceFilenames);
// A LBR sample is like:
// 0x5c6313f/0x5c63170/P/-/-/0 0x5c630e7/0x5c63130/P/-/-/0 ...
@@ -614,10 +616,12 @@ class PerfReader {
return BinarySampleCounters;
}
-private:
+protected:
/// Validate the command line input
- void validateCommandLine(cl::list<std::string> &BinaryFilenames,
- cl::list<std::string> &PerfTraceFilenames);
+ static void validateCommandLine(cl::list<std::string> &BinaryFilenames,
+ cl::list<std::string> &PerfTraceFilenames);
+ static PerfScriptType
+ extractPerfType(cl::list<std::string> &PerfTraceFilenames);
/// Parse a single line of a PERF_RECORD_MMAP2 event looking for a
/// mapping between the binary name and its memory layout.
///
@@ -626,8 +630,6 @@ class PerfReader {
void parseAndAggregateTrace(StringRef Filename);
// Parse either an MMAP event or a perf sample
void parseEventOrSample(TraceStream &TraceIt);
- // Parse the hybrid sample including the call and LBR line
- void parseHybridSample(TraceStream &TraceIt);
// Extract call stack from the perf trace lines
bool extractCallstack(TraceStream &TraceIt,
SmallVectorImpl<uint64_t> &CallStack);
@@ -635,13 +637,12 @@ class PerfReader {
bool extractLBRStack(TraceStream &TraceIt,
SmallVectorImpl<LBREntry> &LBRStack,
ProfiledBinary *Binary);
- void checkAndSetPerfType(cl::list<std::string> &PerfTraceFilenames);
+ // Parse one sample from multiple perf lines, override this for
diff erent
+ // sample type
+ virtual void parseSample(TraceStream &TraceIt) = 0;
// Post process the profile after trace aggregation, we will do simple range
// overlap computation for AutoFDO, or unwind for CSSPGO(hybrid sample).
- void generateRawProfile();
- // Unwind the hybrid samples after aggregration
- void unwindSamples();
- void printUnwinderOutput();
+ virtual void generateRawProfile() = 0;
// Helper function for looking up binary in AddressBinaryMap
ProfiledBinary *getBinary(uint64_t Address);
@@ -654,6 +655,31 @@ class PerfReader {
PerfScriptType PerfType = PERF_UNKNOWN;
};
+/*
+ Hybrid perf script includes a group of hybrid samples(LBRs + call stack),
+ which is used to generate CS profile. An example of hybrid sample:
+ 4005dc # call stack leaf
+ 400634
+ 400684 # call stack root
+ 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 ...
+ ... 0x4005c8/0x4005dc/P/-/-/0 # LBR Entries
+*/
+class HybridPerfReader : public PerfReaderBase {
+public:
+ HybridPerfReader(cl::list<std::string> &BinaryFilenames)
+ : PerfReaderBase(BinaryFilenames) {
+ PerfType = PERF_LBR_STACK;
+ };
+ // Parse the hybrid sample including the call and LBR line
+ void parseSample(TraceStream &TraceIt) override;
+ void generateRawProfile() override;
+
+private:
+ // Unwind the hybrid samples after aggregration
+ void unwindSamples();
+ void printUnwinderOutput();
+};
+
} // end namespace sampleprof
} // end namespace llvm
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index be1169e41f7e3..5c628470bdabe 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -27,6 +27,7 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/ProfileData/SampleProf.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include <list>
#include <set>
@@ -190,7 +191,7 @@ class ProfiledBinary {
StringRef getName() const { return llvm::sys::path::filename(Path); }
uint64_t getBaseAddress() const { return BaseAddress; }
void setBaseAddress(uint64_t Address) { BaseAddress = Address; }
-
+
// Return the preferred load address for the first executable segment.
uint64_t getPreferredBaseAddress() const { return PreferredTextSegmentAddresses[0]; }
// Return the file offset for the first executable segment.
diff --git a/llvm/tools/llvm-profgen/llvm-profgen.cpp b/llvm/tools/llvm-profgen/llvm-profgen.cpp
index 8ea0156aee09e..4045a26209daa 100644
--- a/llvm/tools/llvm-profgen/llvm-profgen.cpp
+++ b/llvm/tools/llvm-profgen/llvm-profgen.cpp
@@ -49,14 +49,20 @@ int main(int argc, const char *argv[]) {
cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()});
cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n");
- // Load binaries and parse perf events and samples
- PerfReader Reader(BinaryFilenames, PerfTraceFilenames);
- if (ShowDisassemblyOnly)
+ if (ShowDisassemblyOnly) {
+ for (auto BinaryPath : BinaryFilenames) {
+ (void)ProfiledBinary(BinaryPath);
+ }
return EXIT_SUCCESS;
- Reader.parsePerfTraces(PerfTraceFilenames);
+ }
+
+ // Load binaries and parse perf events and samples
+ std::unique_ptr<PerfReaderBase> Reader =
+ PerfReaderBase::create(BinaryFilenames, PerfTraceFilenames);
+ Reader->parsePerfTraces(PerfTraceFilenames);
std::unique_ptr<ProfileGenerator> Generator = ProfileGenerator::create(
- Reader.getBinarySampleCounters(), Reader.getPerfScriptType());
+ Reader->getBinarySampleCounters(), Reader->getPerfScriptType());
Generator->generateProfile();
Generator->write();
More information about the llvm-commits
mailing list