forked from OSchip/llvm-project
[CSSPGO][llvm-profgen] Truncate stack samples with invalid return address.
Invalid frame addresses exist in call stack samples due to bad unwinding. This could happen to frame-pointer-based unwinding and the callee functions that do not have the frame pointer chain set up. It isn't common when the program is built with the frame pointer omission disabled, but can still happen with third-party static libs built with frame pointer omitted. Reviewed By: wenlei Differential Revision: https://reviews.llvm.org/D109638
This commit is contained in:
parent
0dc461441e
commit
0057c7185d
|
@ -0,0 +1,12 @@
|
|||
PERF_RECORD_MMAP2 2854748/2854748: [0x400000(0x1000) @ 0 00:1d 123291722 526021]: r-xp /home/noinline-cs-noprobe.perfbin
|
||||
// test for invalid return address
|
||||
|
||||
4005b0
|
||||
400686
|
||||
7f68c5788793
|
||||
0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0
|
||||
|
||||
4005b2
|
||||
400686
|
||||
7f68c5788793
|
||||
0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 0x400645/0x4005ff/P/-/-/0 0x400637/0x400645/P/-/-/0 0x4005e9/0x400634/P/-/-/0 0x4005d7/0x4005e5/P/-/-/0 0x40062f/0x4005b0/P/-/-/0
|
|
@ -0,0 +1,4 @@
|
|||
; REQUIRES: x86_64-linux
|
||||
; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/cs-invalid-ret-addr.perfscript --binary=%S/Inputs/noinline-cs-noprobe.perfbin --output=%t 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: warning: Truncated stack sample due to invalid return address at 0x400686, likely caused by frame pointer omission
|
|
@ -9,13 +9,15 @@
|
|||
#include "ProfileGenerator.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
|
||||
#define DEBUG_TYPE "perf-reader"
|
||||
|
||||
static cl::opt<bool> ShowMmapEvents("show-mmap-events", cl::ReallyHidden,
|
||||
cl::init(false), cl::ZeroOrMore,
|
||||
cl::desc("Print binary load events."));
|
||||
|
||||
cl::opt<bool> SkipSymbolization("skip-symbolization", cl::ReallyHidden,
|
||||
cl::init(false), cl::ZeroOrMore,
|
||||
cl::desc("Dump the unsumbolized profile to the "
|
||||
cl::desc("Dump the unsymbolized profile to the "
|
||||
"output file. It will show unwinder "
|
||||
"output for CS profile generation."));
|
||||
|
||||
|
@ -517,10 +519,17 @@ bool PerfReaderBase::extractCallstack(TraceStream &TraceIt,
|
|||
if (!Binary->addressIsCode(FrameAddr))
|
||||
break;
|
||||
|
||||
// We need to translate return address to call address
|
||||
// for non-leaf frames
|
||||
// We need to translate return address to call address for non-leaf frames.
|
||||
if (!CallStack.empty()) {
|
||||
FrameAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
|
||||
auto CallAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
|
||||
if (!CallAddr) {
|
||||
// Stop at an invalid return address caused by bad unwinding. This could
|
||||
// happen to frame-pointer-based unwinding and the callee functions that
|
||||
// do not have the frame pointer chain set up.
|
||||
InvalidReturnAddresses.insert(FrameAddr);
|
||||
break;
|
||||
}
|
||||
FrameAddr = CallAddr;
|
||||
}
|
||||
|
||||
CallStack.emplace_back(FrameAddr);
|
||||
|
@ -760,12 +769,22 @@ PerfReaderBase::extractPerfType(cl::list<std::string> &PerfTraceFilenames) {
|
|||
|
||||
void HybridPerfReader::generateRawProfile() { unwindSamples(); }
|
||||
|
||||
void PerfReaderBase::warnTruncatedStack() {
|
||||
for (auto Address : InvalidReturnAddresses) {
|
||||
WithColor::warning()
|
||||
<< "Truncated stack sample due to invalid return address at "
|
||||
<< format("0x%" PRIx64, Address)
|
||||
<< ", likely caused by frame pointer omission\n";
|
||||
}
|
||||
}
|
||||
|
||||
void PerfReaderBase::parsePerfTraces(
|
||||
cl::list<std::string> &PerfTraceFilenames) {
|
||||
// Parse perf traces and do aggregation.
|
||||
for (auto Filename : PerfTraceFilenames)
|
||||
parseAndAggregateTrace(Filename);
|
||||
|
||||
warnTruncatedStack();
|
||||
generateRawProfile();
|
||||
}
|
||||
|
||||
|
|
|
@ -594,6 +594,8 @@ protected:
|
|||
void parseEventOrSample(TraceStream &TraceIt);
|
||||
// Warn if the relevant mmap event is missing.
|
||||
void warnIfMissingMMap();
|
||||
// Emit accumulate warnings.
|
||||
void warnTruncatedStack();
|
||||
// Extract call stack from the perf trace lines
|
||||
bool extractCallstack(TraceStream &TraceIt,
|
||||
SmallVectorImpl<uint64_t> &CallStack);
|
||||
|
@ -619,6 +621,8 @@ protected:
|
|||
// Samples with the repeating time generated by the perf reader
|
||||
AggregatedCounter AggregatedSamples;
|
||||
PerfScriptType PerfType = PERF_UNKNOWN;
|
||||
// Keep track of all invalid return addresses
|
||||
std::set<uint64_t> InvalidReturnAddresses;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -299,7 +299,11 @@ public:
|
|||
}
|
||||
|
||||
uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const {
|
||||
return getAddressforIndex(getIndexForAddr(FrameAddr) - 1);
|
||||
auto I = getIndexForAddr(FrameAddr);
|
||||
FrameAddr = I ? getAddressforIndex(I - 1) : 0;
|
||||
if (FrameAddr && addressIsCall(FrameAddr))
|
||||
return FrameAddr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
StringRef getFuncFromStartOffset(uint64_t Offset) {
|
||||
|
|
Loading…
Reference in New Issue