1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[CSSPGO][llvm-profgen] Pseudo probe based CS profile generation

This change implements profile generation infra for pseudo probe in llvm-profgen. During virtual unwinding, the raw profile is extracted into range counter and branch counter and aggregated to sample counter map indexed by the call stack context. This change introduces the last step and produces the eventual profile. Specifically, the body of function sample is recorded by going through each probe among the range and callsite target sample is recorded by extracting the callsite probe from branch's source.

Please refer https://groups.google.com/g/llvm-dev/c/1p1rdYbL93s and https://reviews.llvm.org/D89707 for more context about CSSPGO and llvm-profgen.

**Implementation**

- Extended `PseudoProbeProfileGenerator` for pseudo probe based profile generation.
- `populateBodySamplesWithProbes` reading range counter is responsible for recording function body samples and inferring caller's body samples.
- `populateBoundarySamplesWithProbes` reading branch counter is responsible for recording call site target samples.
- Each sample is recorded with its calling context(named `ContextId`). Remind that the probe based context key doesn't include the leaf frame probe info, so the `ContextId` string is created from two part: one from the probe stack strings' concatenation and other one from the leaf frame probe.
- Added regression test

Test Plan:

ninja & ninja check-llvm

Differential Revision: https://reviews.llvm.org/D92998
This commit is contained in:
wlei 2021-01-11 09:08:39 -08:00
parent fb07198b1d
commit 0adbe76ec7
8 changed files with 307 additions and 29 deletions

View File

@ -1,4 +1,21 @@
; RUN: llvm-profgen --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --show-unwinder-output | FileCheck %s --check-prefix=CHECK-UNWINDER ; RUN: llvm-profgen --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --show-unwinder-output | FileCheck %s --check-prefix=CHECK-UNWINDER
; RUN: FileCheck %s --input-file %t
; CHECK: [main:2 @ foo]:74:0
; CHECK-NEXT: 2: 15
; CHECK-NEXT: 3: 15
; CHECK-NEXT: 4: 14
; CHECK-NEXT: 5: 1
; CHECK-NEXT: 6: 15
; CHECK-NEXT: 8: 14 bar:14
; CHECK-NEXT: !CFGChecksum: 138950591924
; CHECK-NEXT:[main:2 @ foo:8 @ bar]:56:14
; CHECK-NEXT: 1: 14
; CHECK-NEXT: 2: 14
; CHECK-NEXT: 3: 14
; CHECK-NEXT: 4: 14
; CHECK-NEXT: !CFGChecksum: 72617220756
; CHECK-UNWINDER: Binary(inline-cs-pseudoprobe.perfbin)'s Range Counter: ; CHECK-UNWINDER: Binary(inline-cs-pseudoprobe.perfbin)'s Range Counter:
; CHECK-UNWINDER-EMPTY: ; CHECK-UNWINDER-EMPTY:

View File

@ -1,4 +1,20 @@
; RUN: llvm-profgen --perfscript=%S/Inputs/noinline-cs-pseudoprobe.perfscript --binary=%S/Inputs/noinline-cs-pseudoprobe.perfbin --output=%t --show-unwinder-output | FileCheck %s --check-prefix=CHECK-UNWINDER ; RUN: llvm-profgen --perfscript=%S/Inputs/noinline-cs-pseudoprobe.perfscript --binary=%S/Inputs/noinline-cs-pseudoprobe.perfbin --output=%t --show-unwinder-output | FileCheck %s --check-prefix=CHECK-UNWINDER
; RUN: FileCheck %s --input-file %t
; CHECK: [main:2 @ foo]:75:0
; CHECK-NEXT: 2: 15
; CHECK-NEXT: 3: 15
; CHECK-NEXT: 4: 15
; CHECK-NEXT: 6: 15
; CHECK-NEXT: 8: 15 bar:15
; CHECK-NEXT: !CFGChecksum: 138950591924
; CHECK-NEXT:[main:2 @ foo:8 @ bar]:60:15
; CHECK-NEXT: 1: 15
; CHECK-NEXT: 2: 15
; CHECK-NEXT: 3: 15
; CHECK-NEXT: 4: 15
; CHECK-NEXT: !CFGChecksum: 72617220756
; CHECK-UNWINDER: Binary(noinline-cs-pseudoprobe.perfbin)'s Range Counter: ; CHECK-UNWINDER: Binary(noinline-cs-pseudoprobe.perfbin)'s Range Counter:
; CHECK-UNWINDER-NEXT: main:2 ; CHECK-UNWINDER-NEXT: main:2

View File

@ -567,11 +567,7 @@ void PerfReader::checkAndSetPerfType(
} }
if (HasHybridPerf) { if (HasHybridPerf) {
// Set up ProfileIsCS to enable context-sensitive functionalities
// in SampleProf
FunctionSamples::ProfileIsCS = true;
PerfType = PERF_LBR_STACK; PerfType = PERF_LBR_STACK;
} else { } else {
// TODO: Support other type of perf script // TODO: Support other type of perf script
PerfType = PERF_INVILID; PerfType = PERF_INVILID;

View File

@ -67,7 +67,7 @@ void ProfileGenerator::findDisjointRanges(RangeSample &DisjointRanges,
/* /*
Regions may overlap with each other. Using the boundary info, find all Regions may overlap with each other. Using the boundary info, find all
disjoint ranges and their sample count. BoundaryPoint contains the count disjoint ranges and their sample count. BoundaryPoint contains the count
mutiple samples begin/end at this points. multiple samples begin/end at this points.
|<--100-->| Sample1 |<--100-->| Sample1
|<------200------>| Sample2 |<------200------>| Sample2
@ -264,9 +264,12 @@ static FrameLocation getCallerContext(StringRef CalleeContext,
StringRef CallerContext = CalleeContext.rsplit(" @ ").first; StringRef CallerContext = CalleeContext.rsplit(" @ ").first;
CallerNameWithContext = CallerContext.rsplit(':').first; CallerNameWithContext = CallerContext.rsplit(':').first;
auto ContextSplit = CallerContext.rsplit(" @ "); auto ContextSplit = CallerContext.rsplit(" @ ");
StringRef CallerFrameStr = ContextSplit.second.size() == 0
? ContextSplit.first
: ContextSplit.second;
FrameLocation LeafFrameLoc = {"", {0, 0}}; FrameLocation LeafFrameLoc = {"", {0, 0}};
StringRef Funcname; StringRef Funcname;
SampleContext::decodeContextString(ContextSplit.second, Funcname, SampleContext::decodeContextString(CallerFrameStr, Funcname,
LeafFrameLoc.second); LeafFrameLoc.second);
LeafFrameLoc.first = Funcname.str(); LeafFrameLoc.first = Funcname.str();
return LeafFrameLoc; return LeafFrameLoc;
@ -316,5 +319,196 @@ void CSProfileGenerator::populateInferredFunctionSamples() {
} }
} }
// Helper function to extract context prefix
// PrefixContextId is the context id string except for the leaf probe's
// context, the final ContextId will be:
// ContextId = PrefixContextId + LeafContextId;
// Remind that the string in ContextStrStack is in callee-caller order
// So process the string vector reversely
static std::string
extractPrefixContextId(const SmallVector<const PseudoProbe *, 16> &Probes,
ProfiledBinary *Binary) {
SmallVector<std::string, 16> ContextStrStack;
for (const auto *P : Probes) {
Binary->getInlineContextForProbe(P, ContextStrStack, true);
}
std::ostringstream OContextStr;
for (auto &CxtStr : ContextStrStack) {
if (OContextStr.str().size())
OContextStr << " @ ";
OContextStr << CxtStr;
}
return OContextStr.str();
}
void PseudoProbeCSProfileGenerator::generateProfile() {
// Enable CS and pseudo probe functionalities in SampleProf
FunctionSamples::ProfileIsCS = true;
FunctionSamples::ProfileIsProbeBased = true;
for (const auto &BI : BinarySampleCounters) {
ProfiledBinary *Binary = BI.first;
for (const auto &CI : BI.second) {
const ProbeBasedCtxKey *CtxKey =
dyn_cast<ProbeBasedCtxKey>(CI.first.getPtr());
std::string PrefixContextId =
extractPrefixContextId(CtxKey->Probes, Binary);
// Fill in function body samples from probes, also infer caller's samples
// from callee's probe
populateBodySamplesWithProbes(CI.second.RangeCounter, PrefixContextId,
Binary);
// Fill in boundary samples for a call probe
populateBoundarySamplesWithProbes(CI.second.BranchCounter,
PrefixContextId, Binary);
}
}
}
void PseudoProbeCSProfileGenerator::extractProbesFromRange(
const RangeSample &RangeCounter, ProbeCounterMap &ProbeCounter,
ProfiledBinary *Binary) {
RangeSample Ranges;
findDisjointRanges(Ranges, RangeCounter);
for (const auto &Range : Ranges) {
uint64_t RangeBegin = Binary->offsetToVirtualAddr(Range.first.first);
uint64_t RangeEnd = Binary->offsetToVirtualAddr(Range.first.second);
uint64_t Count = Range.second;
// Disjoint ranges have introduce zero-filled gap that
// doesn't belong to current context, filter them out.
if (Count == 0)
continue;
InstructionPointer IP(Binary, RangeBegin, true);
// Disjoint ranges may have range in the middle of two instr,
// e.g. If Instr1 at Addr1, and Instr2 at Addr2, disjoint range
// can be Addr1+1 to Addr2-1. We should ignore such range.
if (IP.Address > RangeEnd)
continue;
while (IP.Address <= RangeEnd) {
const AddressProbesMap &Address2ProbesMap =
Binary->getAddress2ProbesMap();
auto It = Address2ProbesMap.find(IP.Address);
if (It != Address2ProbesMap.end()) {
for (const auto &Probe : It->second) {
if (!Probe.isBlock())
continue;
ProbeCounter[&Probe] += Count;
}
}
IP.advance();
}
}
}
void PseudoProbeCSProfileGenerator::populateBodySamplesWithProbes(
const RangeSample &RangeCounter, StringRef PrefixContextId,
ProfiledBinary *Binary) {
ProbeCounterMap ProbeCounter;
// Extract the top frame probes by looking up each address among the range in
// the Address2ProbeMap
extractProbesFromRange(RangeCounter, ProbeCounter, Binary);
for (auto PI : ProbeCounter) {
const PseudoProbe *Probe = PI.first;
uint64_t Count = PI.second;
FunctionSamples &FunctionProfile =
getFunctionProfileForLeafProbe(PrefixContextId, Probe, Binary);
FunctionProfile.addBodySamples(Probe->Index, 0, Count);
FunctionProfile.addTotalSamples(Count);
if (Probe->isEntry()) {
FunctionProfile.addHeadSamples(Count);
// Look up for the caller's function profile
const auto *InlinerDesc = Binary->getInlinerDescForProbe(Probe);
if (InlinerDesc != nullptr) {
// Since the context id will be compressed, we have to use callee's
// context id to infer caller's context id to ensure they share the
// same context prefix.
StringRef CalleeContextId =
FunctionProfile.getContext().getNameWithContext(true);
StringRef CallerContextId;
FrameLocation &&CallerLeafFrameLoc =
getCallerContext(CalleeContextId, CallerContextId);
uint64_t CallerIndex = CallerLeafFrameLoc.second.LineOffset;
assert(CallerIndex &&
"Inferred caller's location index shouldn't be zero!");
FunctionSamples &CallerProfile =
getFunctionProfileForContext(CallerContextId);
CallerProfile.setFunctionHash(InlinerDesc->FuncHash);
CallerProfile.addBodySamples(CallerIndex, 0, Count);
CallerProfile.addTotalSamples(Count);
CallerProfile.addCalledTargetSamples(CallerIndex, 0,
FunctionProfile.getName(), Count);
}
}
}
}
void PseudoProbeCSProfileGenerator::populateBoundarySamplesWithProbes(
const BranchSample &BranchCounter, StringRef PrefixContextId,
ProfiledBinary *Binary) {
for (auto BI : BranchCounter) {
uint64_t SourceOffset = BI.first.first;
uint64_t TargetOffset = BI.first.second;
uint64_t Count = BI.second;
uint64_t SourceAddress = Binary->offsetToVirtualAddr(SourceOffset);
const PseudoProbe *CallProbe = Binary->getCallProbeForAddr(SourceAddress);
if (CallProbe == nullptr)
continue;
FunctionSamples &FunctionProfile =
getFunctionProfileForLeafProbe(PrefixContextId, CallProbe, Binary);
FunctionProfile.addBodySamples(CallProbe->Index, 0, Count);
FunctionProfile.addTotalSamples(Count);
StringRef CalleeName = FunctionSamples::getCanonicalFnName(
Binary->getFuncFromStartOffset(TargetOffset));
if (CalleeName.size() == 0)
continue;
FunctionProfile.addCalledTargetSamples(CallProbe->Index, 0, CalleeName,
Count);
}
}
FunctionSamples &PseudoProbeCSProfileGenerator::getFunctionProfileForLeafProbe(
StringRef PrefixContextId, SmallVector<std::string, 16> &LeafInlinedContext,
const PseudoProbeFuncDesc *LeafFuncDesc) {
assert(LeafInlinedContext.size() &&
"Profile context must have the leaf frame");
std::ostringstream OContextStr;
OContextStr << PrefixContextId.str();
for (uint32_t I = 0; I < LeafInlinedContext.size() - 1; I++) {
if (OContextStr.str().size())
OContextStr << " @ ";
OContextStr << LeafInlinedContext[I];
}
// For leaf inlined context with the top frame, we should strip off the top
// frame's probe id, like:
// Inlined stack: [foo:1, bar:2], the ContextId will be "foo:1 @ bar"
if (OContextStr.str().size())
OContextStr << " @ ";
StringRef LeafLoc = LeafInlinedContext.back();
OContextStr << LeafLoc.split(":").first.str();
FunctionSamples &FunctionProile =
getFunctionProfileForContext(OContextStr.str());
FunctionProile.setFunctionHash(LeafFuncDesc->FuncHash);
return FunctionProile;
}
FunctionSamples &PseudoProbeCSProfileGenerator::getFunctionProfileForLeafProbe(
StringRef PrefixContextId, const PseudoProbe *LeafProbe,
ProfiledBinary *Binary) {
SmallVector<std::string, 16> LeafInlinedContext;
Binary->getInlineContextForProbe(LeafProbe, LeafInlinedContext);
// Note that the context from probe doesn't include leaf frame,
// hence we need to retrieve and append the leaf frame.
const auto *FuncDesc = Binary->getFuncDescForGUID(LeafProbe->GUID);
LeafInlinedContext.emplace_back(FuncDesc->FuncName + ":" +
Twine(LeafProbe->Index).str());
return getFunctionProfileForLeafProbe(PrefixContextId, LeafInlinedContext,
FuncDesc);
}
} // end namespace sampleprof } // end namespace sampleprof
} // end namespace llvm } // end namespace llvm

View File

@ -25,7 +25,7 @@ public:
ProfileGenerator(){}; ProfileGenerator(){};
virtual ~ProfileGenerator() = default; virtual ~ProfileGenerator() = default;
static std::unique_ptr<ProfileGenerator> static std::unique_ptr<ProfileGenerator>
create(const BinarySampleCounterMap &SampleCounters, create(const BinarySampleCounterMap &BinarySampleCounters,
enum PerfScriptType SampleType); enum PerfScriptType SampleType);
virtual void generateProfile() = 0; virtual void generateProfile() = 0;
@ -50,7 +50,6 @@ protected:
*/ */
void findDisjointRanges(RangeSample &DisjointRanges, void findDisjointRanges(RangeSample &DisjointRanges,
const RangeSample &Ranges); const RangeSample &Ranges);
// Used by SampleProfileWriter // Used by SampleProfileWriter
StringMap<FunctionSamples> ProfileMap; StringMap<FunctionSamples> ProfileMap;
}; };
@ -65,6 +64,8 @@ public:
public: public:
void generateProfile() override { void generateProfile() override {
// Enable context-sensitive functionalities in SampleProf
FunctionSamples::ProfileIsCS = true;
for (const auto &BI : BinarySampleCounters) { for (const auto &BI : BinarySampleCounters) {
ProfiledBinary *Binary = BI.first; ProfiledBinary *Binary = BI.first;
for (const auto &CI : BI.second) { for (const auto &CI : BI.second) {
@ -90,14 +91,16 @@ public:
populateInferredFunctionSamples(); populateInferredFunctionSamples();
} }
protected:
// Lookup or create FunctionSamples for the context
FunctionSamples &getFunctionProfileForContext(StringRef ContextId);
private: private:
// Helper function for updating body sample for a leaf location in // Helper function for updating body sample for a leaf location in
// FunctionProfile // FunctionProfile
void updateBodySamplesforFunctionProfile(FunctionSamples &FunctionProfile, void updateBodySamplesforFunctionProfile(FunctionSamples &FunctionProfile,
const FrameLocation &LeafLoc, const FrameLocation &LeafLoc,
uint64_t Count); uint64_t Count);
// Lookup or create FunctionSamples for the context
FunctionSamples &getFunctionProfileForContext(StringRef ContextId);
void populateFunctionBodySamples(FunctionSamples &FunctionProfile, void populateFunctionBodySamples(FunctionSamples &FunctionProfile,
const RangeSample &RangeCounters, const RangeSample &RangeCounters,
ProfiledBinary *Binary); ProfiledBinary *Binary);
@ -108,14 +111,38 @@ private:
void populateInferredFunctionSamples(); void populateInferredFunctionSamples();
}; };
using ProbeCounterMap = std::unordered_map<const PseudoProbe *, uint64_t>;
class PseudoProbeCSProfileGenerator : public CSProfileGenerator { class PseudoProbeCSProfileGenerator : public CSProfileGenerator {
public: public:
PseudoProbeCSProfileGenerator(const BinarySampleCounterMap &Counters) PseudoProbeCSProfileGenerator(const BinarySampleCounterMap &Counters)
: CSProfileGenerator(Counters) {} : CSProfileGenerator(Counters) {}
void generateProfile() override { void generateProfile() override;
// TODO
} private:
// Go through each address from range to extract the top frame probe by
// looking up in the Address2ProbeMap
void extractProbesFromRange(const RangeSample &RangeCounter,
ProbeCounterMap &ProbeCounter,
ProfiledBinary *Binary);
// Fill in function body samples from probes
void populateBodySamplesWithProbes(const RangeSample &RangeCounter,
StringRef PrefixContextId,
ProfiledBinary *Binary);
// Fill in boundary samples for a call probe
void populateBoundarySamplesWithProbes(const BranchSample &BranchCounter,
StringRef PrefixContextId,
ProfiledBinary *Binary);
// Helper function to get FunctionSamples for the leaf inlined context
FunctionSamples &getFunctionProfileForLeafProbe(
StringRef PrefixContextId,
SmallVector<std::string, 16> &LeafInlinedContext,
const PseudoProbeFuncDesc *LeafFuncDesc);
// Helper function to get FunctionSamples for the leaf probe
FunctionSamples &getFunctionProfileForLeafProbe(StringRef PrefixContextId,
const PseudoProbe *LeafProbe,
ProfiledBinary *Binary);
}; };
} // end namespace sampleprof } // end namespace sampleprof

View File

@ -244,10 +244,19 @@ public:
void void
getInlineContextForProbe(const PseudoProbe *Probe, getInlineContextForProbe(const PseudoProbe *Probe,
SmallVector<std::string, 16> &InlineContextStack, SmallVector<std::string, 16> &InlineContextStack,
bool IncludeLeaf) const { bool IncludeLeaf = false) const {
return ProbeDecoder.getInlineContextForProbe(Probe, InlineContextStack, return ProbeDecoder.getInlineContextForProbe(Probe, InlineContextStack,
IncludeLeaf); IncludeLeaf);
} }
const AddressProbesMap &getAddress2ProbesMap() const {
return ProbeDecoder.getAddress2ProbesMap();
}
const PseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) {
return ProbeDecoder.getFuncDescForGUID(GUID);
}
const PseudoProbeFuncDesc *getInlinerDescForProbe(const PseudoProbe *Probe) {
return ProbeDecoder.getInlinerDescForProbe(Probe);
}
}; };
} // end namespace sampleprof } // end namespace sampleprof

View File

@ -41,7 +41,7 @@ void PseudoProbe::getInlineContext(SmallVector<std::string, 16> &ContextStack,
PseudoProbeInlineTree *Cur = InlineTree; PseudoProbeInlineTree *Cur = InlineTree;
// It will add the string of each node's inline site during iteration. // It will add the string of each node's inline site during iteration.
// Note that it won't include the probe's belonging function(leaf location) // Note that it won't include the probe's belonging function(leaf location)
while (!Cur->hasInlineSite()) { while (Cur->hasInlineSite()) {
std::string ContextStr; std::string ContextStr;
if (ShowName) { if (ShowName) {
StringRef FuncName = StringRef FuncName =
@ -312,22 +312,32 @@ PseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
return CallProbe; return CallProbe;
} }
const PseudoProbeFuncDesc *
PseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
auto It = GUID2FuncDescMap.find(GUID);
assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
return &It->second;
}
void PseudoProbeDecoder::getInlineContextForProbe( void PseudoProbeDecoder::getInlineContextForProbe(
const PseudoProbe *Probe, SmallVector<std::string, 16> &InlineContextStack, const PseudoProbe *Probe, SmallVector<std::string, 16> &InlineContextStack,
bool IncludeLeaf) const { bool IncludeLeaf) const {
if (IncludeLeaf) {
// Note that the context from probe doesn't include leaf frame,
// hence we need to retrieve and prepend leaf if requested.
auto It = GUID2FuncDescMap.find(Probe->GUID);
assert(It != GUID2FuncDescMap.end() &&
"Should have function descriptor for a valid GUID");
StringRef FuncName = It->second.FuncName;
// InlineContextStack is in callee-caller order, so push leaf in the front
InlineContextStack.emplace_back(FuncName.str() + ":" +
Twine(Probe->Index).str());
}
Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap, true); Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap, true);
if (!IncludeLeaf)
return;
// Note that the context from probe doesn't include leaf frame,
// hence we need to retrieve and prepend leaf if requested.
const auto *FuncDesc = getFuncDescForGUID(Probe->GUID);
InlineContextStack.emplace_back(FuncDesc->FuncName + ":" +
Twine(Probe->Index).str());
}
const PseudoProbeFuncDesc *
PseudoProbeDecoder::getInlinerDescForProbe(const PseudoProbe *Probe) const {
PseudoProbeInlineTree *InlinerNode = Probe->InlineTree;
if (!InlinerNode->hasInlineSite())
return nullptr;
return getFuncDescForGUID(std::get<0>(InlinerNode->ISite));
} }
} // end namespace sampleprof } // end namespace sampleprof

View File

@ -73,7 +73,7 @@ public:
void addProbes(PseudoProbe *Probe) { ProbeVector.push_back(Probe); } void addProbes(PseudoProbe *Probe) { ProbeVector.push_back(Probe); }
// Return false if it's a dummy inline site // Return false if it's a dummy inline site
bool hasInlineSite() const { return !std::get<0>(ISite); } bool hasInlineSite() const { return std::get<0>(ISite) != 0; }
}; };
// Function descriptor decoded from .pseudo_probe_desc section // Function descriptor decoded from .pseudo_probe_desc section
@ -203,17 +203,26 @@ public:
// Look up the probe of a call for the input address // Look up the probe of a call for the input address
const PseudoProbe *getCallProbeForAddr(uint64_t Address) const; const PseudoProbe *getCallProbeForAddr(uint64_t Address) const;
const PseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const;
// Helper function to populate one probe's inline stack into // Helper function to populate one probe's inline stack into
// \p InlineContextStack. // \p InlineContextStack.
// Current leaf location info will be added if IncludeLeaf is true // Current leaf location info will be added if IncludeLeaf is true
// Example: // Example:
// Current probe(bar:3) inlined at foo:2 then inlined at main:1 // Current probe(bar:3) inlined at foo:2 then inlined at main:1
// IncludeLeaf = true, Output: [main:1, foo:2, bar:3] // IncludeLeaf = true, Output: [main:1, foo:2, bar:3]
// IncludeLeaf = false, OUtput: [main:1, foo:2] // IncludeLeaf = false, Output: [main:1, foo:2]
void void
getInlineContextForProbe(const PseudoProbe *Probe, getInlineContextForProbe(const PseudoProbe *Probe,
SmallVector<std::string, 16> &InlineContextStack, SmallVector<std::string, 16> &InlineContextStack,
bool IncludeLeaf) const; bool IncludeLeaf) const;
const AddressProbesMap &getAddress2ProbesMap() const {
return Address2ProbesMap;
}
const PseudoProbeFuncDesc *
getInlinerDescForProbe(const PseudoProbe *Probe) const;
}; };
} // end namespace sampleprof } // end namespace sampleprof