aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-profgen/PerfReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-profgen/PerfReader.cpp')
-rw-r--r--llvm/tools/llvm-profgen/PerfReader.cpp137
1 files changed, 88 insertions, 49 deletions
diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp
index e63c6d6..e1f5cc9 100644
--- a/llvm/tools/llvm-profgen/PerfReader.cpp
+++ b/llvm/tools/llvm-profgen/PerfReader.cpp
@@ -321,7 +321,7 @@ bool VirtualUnwinder::unwind(const PerfSample *Sample, uint64_t Repeat) {
std::unique_ptr<PerfReaderBase>
PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
- std::optional<uint32_t> PIDFilter) {
+ std::optional<int32_t> PIDFilter) {
std::unique_ptr<PerfReaderBase> PerfReader;
if (PerfInput.Format == PerfFormat::UnsymbolizedProfile) {
@@ -331,9 +331,10 @@ PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
}
// For perf data input, we need to convert them into perf script first.
+ // If this is a kernel perf file, there is no need for retrieving PIDs.
if (PerfInput.Format == PerfFormat::PerfData)
- PerfInput =
- PerfScriptReader::convertPerfDataToTrace(Binary, PerfInput, PIDFilter);
+ PerfInput = PerfScriptReader::convertPerfDataToTrace(
+ Binary, Binary->isKernel(), PerfInput, PIDFilter);
assert((PerfInput.Format == PerfFormat::PerfScript) &&
"Should be a perfscript!");
@@ -353,9 +354,9 @@ PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
}
PerfInputFile
-PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary,
+PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary, bool SkipPID,
PerfInputFile &File,
- std::optional<uint32_t> PIDFilter) {
+ std::optional<int32_t> PIDFilter) {
StringRef PerfData = File.InputFile;
// Run perf script to retrieve PIDs matching binary we're interested in.
auto PerfExecutable = sys::Process::FindInEnvPath("PATH", "perf");
@@ -363,49 +364,59 @@ PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary,
exitWithError("Perf not found.");
}
std::string PerfPath = *PerfExecutable;
-
SmallString<128> PerfTraceFile;
sys::fs::createUniquePath("perf-script-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.tmp",
PerfTraceFile, /*MakeAbsolute=*/true);
std::string ErrorFile = std::string(PerfTraceFile) + ".err";
- StringRef ScriptMMapArgs[] = {PerfPath, "script", "--show-mmap-events",
- "-F", "comm,pid", "-i",
- PerfData};
std::optional<StringRef> Redirects[] = {std::nullopt, // Stdin
StringRef(PerfTraceFile), // Stdout
StringRef(ErrorFile)}; // Stderr
- sys::ExecuteAndWait(PerfPath, ScriptMMapArgs, std::nullopt, Redirects);
-
PerfScriptReader::TempFileCleanups.emplace_back(PerfTraceFile);
PerfScriptReader::TempFileCleanups.emplace_back(ErrorFile);
- // Collect the PIDs
- TraceStream TraceIt(PerfTraceFile);
std::string PIDs;
- std::unordered_set<uint32_t> PIDSet;
- while (!TraceIt.isAtEoF()) {
- MMapEvent MMap;
- if (isMMap2Event(TraceIt.getCurrentLine()) &&
- extractMMap2EventForBinary(Binary, TraceIt.getCurrentLine(), MMap)) {
- auto It = PIDSet.emplace(MMap.PID);
- if (It.second && (!PIDFilter || MMap.PID == *PIDFilter)) {
- if (!PIDs.empty()) {
- PIDs.append(",");
+ if (!SkipPID) {
+ StringRef ScriptMMapArgs[] = {PerfPath, "script", "--show-mmap-events",
+ "-F", "comm,pid", "-i",
+ PerfData};
+ sys::ExecuteAndWait(PerfPath, ScriptMMapArgs, std::nullopt, Redirects);
+
+ // Collect the PIDs
+ TraceStream TraceIt(PerfTraceFile);
+ std::unordered_set<int32_t> PIDSet;
+ while (!TraceIt.isAtEoF()) {
+ MMapEvent MMap;
+ if (isMMapEvent(TraceIt.getCurrentLine()) &&
+ extractMMapEventForBinary(Binary, TraceIt.getCurrentLine(), MMap)) {
+ auto It = PIDSet.emplace(MMap.PID);
+ if (It.second && (!PIDFilter || MMap.PID == *PIDFilter)) {
+ if (!PIDs.empty()) {
+ PIDs.append(",");
+ }
+ PIDs.append(utostr(MMap.PID));
}
- PIDs.append(utostr(MMap.PID));
}
+ TraceIt.advance();
}
- TraceIt.advance();
- }
- if (PIDs.empty()) {
- exitWithError("No relevant mmap event is found in perf data.");
+ if (PIDs.empty()) {
+ exitWithError("No relevant mmap event is found in perf data.");
+ }
}
// Run perf script again to retrieve events for PIDs collected above
- StringRef ScriptSampleArgs[] = {PerfPath, "script", "--show-mmap-events",
- "-F", "ip,brstack", "--pid",
- PIDs, "-i", PerfData};
+ SmallVector<StringRef, 8> ScriptSampleArgs;
+ ScriptSampleArgs.push_back(PerfPath);
+ ScriptSampleArgs.push_back("script");
+ ScriptSampleArgs.push_back("--show-mmap-events");
+ ScriptSampleArgs.push_back("-F");
+ ScriptSampleArgs.push_back("ip,brstack");
+ ScriptSampleArgs.push_back("-i");
+ ScriptSampleArgs.push_back(PerfData);
+ if (!PIDs.empty()) {
+ ScriptSampleArgs.push_back("--pid");
+ ScriptSampleArgs.push_back(PIDs);
+ }
sys::ExecuteAndWait(PerfPath, ScriptSampleArgs, std::nullopt, Redirects);
return {std::string(PerfTraceFile), PerfFormat::PerfScript,
@@ -428,7 +439,10 @@ static StringRef filename(StringRef Path, bool UseBackSlash) {
void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) {
// Drop the event which doesn't belong to user-provided binary
StringRef BinaryName = filename(Event.BinaryPath, Binary->isCOFF());
- if (Binary->getName() != BinaryName)
+ bool IsKernel = Binary->isKernel();
+ if (!IsKernel && Binary->getName() != BinaryName)
+ return;
+ if (IsKernel && !Binary->isKernelImageName(BinaryName))
return;
// Drop the event if process does not match pid filter
@@ -441,7 +455,7 @@ void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) {
return;
}
- if (Event.Offset == Binary->getTextSegmentOffset()) {
+ if (IsKernel || Event.Offset == Binary->getTextSegmentOffset()) {
// A binary image could be unloaded and then reloaded at different
// place, so update binary load address.
// Only update for the first executable segment and assume all other
@@ -950,16 +964,23 @@ void PerfScriptReader::parseSample(TraceStream &TraceIt) {
parseSample(TraceIt, Count);
}
-bool PerfScriptReader::extractMMap2EventForBinary(ProfiledBinary *Binary,
- StringRef Line,
- MMapEvent &MMap) {
- // Parse a line like:
+bool PerfScriptReader::extractMMapEventForBinary(ProfiledBinary *Binary,
+ StringRef Line,
+ MMapEvent &MMap) {
+ // Parse a MMap2 line like:
// PERF_RECORD_MMAP2 2113428/2113428: [0x7fd4efb57000(0x204000) @ 0
// 08:04 19532229 3585508847]: r-xp /usr/lib64/libdl-2.17.so
- constexpr static const char *const Pattern =
- "PERF_RECORD_MMAP2 ([0-9]+)/[0-9]+: "
+ constexpr static const char *const MMap2Pattern =
+ "PERF_RECORD_MMAP2 (-?[0-9]+)/[0-9]+: "
"\\[(0x[a-f0-9]+)\\((0x[a-f0-9]+)\\) @ "
"(0x[a-f0-9]+|0) .*\\]: [-a-z]+ (.*)";
+ // Parse a MMap line like
+ // PERF_RECORD_MMAP -1/0: [0xffffffff81e00000(0x3e8fa000) @ \
+ // 0xffffffff81e00000]: x [kernel.kallsyms]_text
+ constexpr static const char *const MMapPattern =
+ "PERF_RECORD_MMAP (-?[0-9]+)/[0-9]+: "
+ "\\[(0x[a-f0-9]+)\\((0x[a-f0-9]+)\\) @ "
+ "(0x[a-f0-9]+|0)\\]: [-a-z]+ (.*)";
// Field 0 - whole line
// Field 1 - PID
// Field 2 - base address
@@ -975,14 +996,25 @@ bool PerfScriptReader::extractMMap2EventForBinary(ProfiledBinary *Binary,
BINARY_PATH = 5
};
- Regex RegMmap2(Pattern);
+ bool R = false;
SmallVector<StringRef, 6> Fields;
- bool R = RegMmap2.match(Line, &Fields);
+ if (Line.contains("PERF_RECORD_MMAP2 ")) {
+ Regex RegMmap2(MMap2Pattern);
+ R = RegMmap2.match(Line, &Fields);
+ } else if (Line.contains("PERF_RECORD_MMAP ")) {
+ Regex RegMmap(MMapPattern);
+ R = RegMmap.match(Line, &Fields);
+ } else
+ llvm_unreachable("unexpected MMAP event entry");
+
if (!R) {
std::string WarningMsg = "Cannot parse mmap event: " + Line.str() + " \n";
WithColor::warning() << WarningMsg;
+ return false;
}
- Fields[PID].getAsInteger(10, MMap.PID);
+ long long MMapPID = 0;
+ getAsSignedInteger(Fields[PID], 10, MMapPID);
+ MMap.PID = MMapPID;
Fields[MMAPPED_ADDRESS].getAsInteger(0, MMap.Address);
Fields[MMAPPED_SIZE].getAsInteger(0, MMap.Size);
Fields[PAGE_OFFSET].getAsInteger(0, MMap.Offset);
@@ -993,19 +1025,22 @@ bool PerfScriptReader::extractMMap2EventForBinary(ProfiledBinary *Binary,
}
StringRef BinaryName = filename(MMap.BinaryPath, Binary->isCOFF());
+ if (Binary->isKernel()) {
+ return Binary->isKernelImageName(BinaryName);
+ }
return Binary->getName() == BinaryName;
}
-void PerfScriptReader::parseMMap2Event(TraceStream &TraceIt) {
+void PerfScriptReader::parseMMapEvent(TraceStream &TraceIt) {
MMapEvent MMap;
- if (extractMMap2EventForBinary(Binary, TraceIt.getCurrentLine(), MMap))
+ if (extractMMapEventForBinary(Binary, TraceIt.getCurrentLine(), MMap))
updateBinaryAddress(MMap);
TraceIt.advance();
}
void PerfScriptReader::parseEventOrSample(TraceStream &TraceIt) {
- if (isMMap2Event(TraceIt.getCurrentLine()))
- parseMMap2Event(TraceIt);
+ if (isMMapEvent(TraceIt.getCurrentLine()))
+ parseMMapEvent(TraceIt);
else
parseSample(TraceIt);
}
@@ -1032,7 +1067,7 @@ bool PerfScriptReader::isLBRSample(StringRef Line) {
return false;
}
-bool PerfScriptReader::isMMap2Event(StringRef Line) {
+bool PerfScriptReader::isMMapEvent(StringRef Line) {
// Short cut to avoid string find is possible.
if (Line.empty() || Line.size() < 50)
return false;
@@ -1040,9 +1075,9 @@ bool PerfScriptReader::isMMap2Event(StringRef Line) {
if (std::isdigit(Line[0]))
return false;
- // PERF_RECORD_MMAP2 does not appear at the beginning of the line
- // for ` perf script --show-mmap-events -i ...`
- return Line.contains("PERF_RECORD_MMAP2");
+ // PERF_RECORD_MMAP2 or PERF_RECORD_MMAP does not appear at the beginning of
+ // the line for ` perf script --show-mmap-events -i ...`
+ return Line.contains("PERF_RECORD_MMAP");
}
// The raw hybird sample is like
@@ -1208,6 +1243,10 @@ void PerfScriptReader::warnInvalidRange() {
void PerfScriptReader::parsePerfTraces() {
// Parse perf traces and do aggregation.
parseAndAggregateTrace();
+ if (Binary->isKernel() && !Binary->getIsLoadedByMMap()) {
+ exitWithError(
+ "Kernel is requested, but no kernel is found in mmap events.");
+ }
emitWarningSummary(NumLeafExternalFrame, NumTotalSample,
"of samples have leaf external frame in call stack.");