diff options
Diffstat (limited to 'llvm/tools/llvm-profgen/PerfReader.cpp')
-rw-r--r-- | llvm/tools/llvm-profgen/PerfReader.cpp | 137 |
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."); |