123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- //===-- ProfileGenerator.cpp - Profile Generator ---------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "ProfileGenerator.h"
- static cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::Required,
- cl::desc("Output profile file"));
- static cl::alias OutputA("o", cl::desc("Alias for --output"),
- cl::aliasopt(OutputFilename));
- static cl::opt<SampleProfileFormat> OutputFormat(
- "format", cl::desc("Format of output profile"), cl::init(SPF_Text),
- cl::values(
- clEnumValN(SPF_Binary, "binary", "Binary encoding (default)"),
- clEnumValN(SPF_Compact_Binary, "compbinary", "Compact binary encoding"),
- clEnumValN(SPF_Ext_Binary, "extbinary", "Extensible binary encoding"),
- clEnumValN(SPF_Text, "text", "Text encoding"),
- clEnumValN(SPF_GCC, "gcc",
- "GCC encoding (only meaningful for -sample)")));
- static cl::opt<int32_t, true> RecursionCompression(
- "compress-recursion",
- cl::desc("Compressing recursion by deduplicating adjacent frame "
- "sequences up to the specified size. -1 means no size limit."),
- cl::Hidden,
- cl::location(llvm::sampleprof::CSProfileGenerator::MaxCompressionSize));
- static cl::opt<uint64_t> CSProfColdThres(
- "csprof-cold-thres", cl::init(100), cl::ZeroOrMore,
- cl::desc("Specify the total samples threshold for a context profile to "
- "be considered cold, any cold profiles will be merged into "
- "context-less base profiles"));
- static cl::opt<bool> CSProfKeepCold(
- "csprof-keep-cold", cl::init(false), cl::ZeroOrMore,
- cl::desc("This works together with --csprof-cold-thres. If the total count "
- "of the profile after all merge is done is still smaller than the "
- "csprof-cold-thres, it will be trimmed unless csprof-keep-cold "
- "flag is specified."));
- using namespace llvm;
- using namespace sampleprof;
- namespace llvm {
- namespace sampleprof {
- // Initialize the MaxCompressionSize to -1 which means no size limit
- int32_t CSProfileGenerator::MaxCompressionSize = -1;
- static bool
- usePseudoProbes(const BinarySampleCounterMap &BinarySampleCounters) {
- return BinarySampleCounters.size() &&
- BinarySampleCounters.begin()->first->usePseudoProbes();
- }
- std::unique_ptr<ProfileGenerator>
- ProfileGenerator::create(const BinarySampleCounterMap &BinarySampleCounters,
- enum PerfScriptType SampleType) {
- std::unique_ptr<ProfileGenerator> ProfileGenerator;
- if (SampleType == PERF_LBR_STACK) {
- if (usePseudoProbes(BinarySampleCounters)) {
- ProfileGenerator.reset(
- new PseudoProbeCSProfileGenerator(BinarySampleCounters));
- } else {
- ProfileGenerator.reset(new CSProfileGenerator(BinarySampleCounters));
- }
- } else {
- // TODO:
- llvm_unreachable("Unsupported perfscript!");
- }
- return ProfileGenerator;
- }
- void ProfileGenerator::write(std::unique_ptr<SampleProfileWriter> Writer,
- StringMap<FunctionSamples> &ProfileMap) {
- Writer->write(ProfileMap);
- }
- void ProfileGenerator::write() {
- auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat);
- if (std::error_code EC = WriterOrErr.getError())
- exitWithError(EC, OutputFilename);
- write(std::move(WriterOrErr.get()), ProfileMap);
- }
- void ProfileGenerator::findDisjointRanges(RangeSample &DisjointRanges,
- const RangeSample &Ranges) {
- /*
- Regions may overlap with each other. Using the boundary info, find all
- disjoint ranges and their sample count. BoundaryPoint contains the count
- multiple samples begin/end at this points.
- |<--100-->| Sample1
- |<------200------>| Sample2
- A B C
- In the example above,
- Sample1 begins at A, ends at B, its value is 100.
- Sample2 beings at A, ends at C, its value is 200.
- For A, BeginCount is the sum of sample begins at A, which is 300 and no
- samples ends at A, so EndCount is 0.
- Then boundary points A, B, and C with begin/end counts are:
- A: (300, 0)
- B: (0, 100)
- C: (0, 200)
- */
- struct BoundaryPoint {
- // Sum of sample counts beginning at this point
- uint64_t BeginCount;
- // Sum of sample counts ending at this point
- uint64_t EndCount;
- BoundaryPoint() : BeginCount(0), EndCount(0){};
- void addBeginCount(uint64_t Count) { BeginCount += Count; }
- void addEndCount(uint64_t Count) { EndCount += Count; }
- };
- /*
- For the above example. With boundary points, follwing logic finds two
- disjoint region of
- [A,B]: 300
- [B+1,C]: 200
- If there is a boundary point that both begin and end, the point itself
- becomes a separate disjoint region. For example, if we have original
- ranges of
- |<--- 100 --->|
- |<--- 200 --->|
- A B C
- there are three boundary points with their begin/end counts of
- A: (100, 0)
- B: (200, 100)
- C: (0, 200)
- the disjoint ranges would be
- [A, B-1]: 100
- [B, B]: 300
- [B+1, C]: 200.
- */
- std::map<uint64_t, BoundaryPoint> Boundaries;
- for (auto Item : Ranges) {
- uint64_t Begin = Item.first.first;
- uint64_t End = Item.first.second;
- uint64_t Count = Item.second;
- if (Boundaries.find(Begin) == Boundaries.end())
- Boundaries[Begin] = BoundaryPoint();
- Boundaries[Begin].addBeginCount(Count);
- if (Boundaries.find(End) == Boundaries.end())
- Boundaries[End] = BoundaryPoint();
- Boundaries[End].addEndCount(Count);
- }
- uint64_t BeginAddress = 0;
- int Count = 0;
- for (auto Item : Boundaries) {
- uint64_t Address = Item.first;
- BoundaryPoint &Point = Item.second;
- if (Point.BeginCount) {
- if (BeginAddress)
- DisjointRanges[{BeginAddress, Address - 1}] = Count;
- Count += Point.BeginCount;
- BeginAddress = Address;
- }
- if (Point.EndCount) {
- assert(BeginAddress && "First boundary point cannot be 'end' point");
- DisjointRanges[{BeginAddress, Address}] = Count;
- Count -= Point.EndCount;
- BeginAddress = Address + 1;
- }
- }
- }
- FunctionSamples &
- CSProfileGenerator::getFunctionProfileForContext(StringRef ContextStr) {
- auto Ret = ProfileMap.try_emplace(ContextStr, FunctionSamples());
- if (Ret.second) {
- SampleContext FContext(Ret.first->first(), RawContext);
- FunctionSamples &FProfile = Ret.first->second;
- FProfile.setContext(FContext);
- }
- return Ret.first->second;
- }
- void CSProfileGenerator::updateBodySamplesforFunctionProfile(
- FunctionSamples &FunctionProfile, const FrameLocation &LeafLoc,
- uint64_t Count) {
- // Filter out invalid negative(int type) lineOffset
- if (LeafLoc.second.LineOffset & 0x80000000)
- return;
- // Use the maximum count of samples with same line location
- ErrorOr<uint64_t> R = FunctionProfile.findSamplesAt(
- LeafLoc.second.LineOffset, LeafLoc.second.Discriminator);
- uint64_t PreviousCount = R ? R.get() : 0;
- if (PreviousCount < Count) {
- FunctionProfile.addBodySamples(LeafLoc.second.LineOffset,
- LeafLoc.second.Discriminator,
- Count - PreviousCount);
- }
- }
- void CSProfileGenerator::populateFunctionBodySamples(
- FunctionSamples &FunctionProfile, const RangeSample &RangeCounter,
- ProfiledBinary *Binary) {
- // Compute disjoint ranges first, so we can use MAX
- // for calculating count for each location.
- RangeSample Ranges;
- findDisjointRanges(Ranges, RangeCounter);
- for (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) {
- uint64_t Offset = Binary->virtualAddrToOffset(IP.Address);
- auto LeafLoc = Binary->getInlineLeafFrameLoc(Offset);
- if (LeafLoc.hasValue()) {
- // Recording body sample for this specific context
- updateBodySamplesforFunctionProfile(FunctionProfile, *LeafLoc, Count);
- }
- // Accumulate total sample count even it's a line with invalid debug info
- FunctionProfile.addTotalSamples(Count);
- // Move to next IP within the range
- IP.advance();
- }
- }
- }
- void CSProfileGenerator::populateFunctionBoundarySamples(
- StringRef ContextId, FunctionSamples &FunctionProfile,
- const BranchSample &BranchCounters, ProfiledBinary *Binary) {
- for (auto Entry : BranchCounters) {
- uint64_t SourceOffset = Entry.first.first;
- uint64_t TargetOffset = Entry.first.second;
- uint64_t Count = Entry.second;
- // Get the callee name by branch target if it's a call branch
- StringRef CalleeName = FunctionSamples::getCanonicalFnName(
- Binary->getFuncFromStartOffset(TargetOffset));
- if (CalleeName.size() == 0)
- continue;
- // Record called target sample and its count
- auto LeafLoc = Binary->getInlineLeafFrameLoc(SourceOffset);
- if (!LeafLoc.hasValue())
- continue;
- FunctionProfile.addCalledTargetSamples(LeafLoc->second.LineOffset,
- LeafLoc->second.Discriminator,
- CalleeName, Count);
- // Record head sample for called target(callee)
- std::ostringstream OCalleeCtxStr;
- if (ContextId.find(" @ ") != StringRef::npos) {
- OCalleeCtxStr << ContextId.rsplit(" @ ").first.str();
- OCalleeCtxStr << " @ ";
- }
- OCalleeCtxStr << getCallSite(*LeafLoc) << " @ " << CalleeName.str();
- FunctionSamples &CalleeProfile =
- getFunctionProfileForContext(OCalleeCtxStr.str());
- assert(Count != 0 && "Unexpected zero weight branch");
- CalleeProfile.addHeadSamples(Count);
- }
- }
- static FrameLocation getCallerContext(StringRef CalleeContext,
- StringRef &CallerNameWithContext) {
- StringRef CallerContext = CalleeContext.rsplit(" @ ").first;
- CallerNameWithContext = CallerContext.rsplit(':').first;
- auto ContextSplit = CallerContext.rsplit(" @ ");
- StringRef CallerFrameStr = ContextSplit.second.size() == 0
- ? ContextSplit.first
- : ContextSplit.second;
- FrameLocation LeafFrameLoc = {"", {0, 0}};
- StringRef Funcname;
- SampleContext::decodeContextString(CallerFrameStr, Funcname,
- LeafFrameLoc.second);
- LeafFrameLoc.first = Funcname.str();
- return LeafFrameLoc;
- }
- void CSProfileGenerator::populateInferredFunctionSamples() {
- for (const auto &Item : ProfileMap) {
- const StringRef CalleeContext = Item.first();
- const FunctionSamples &CalleeProfile = Item.second;
- // If we already have head sample counts, we must have value profile
- // for call sites added already. Skip to avoid double counting.
- if (CalleeProfile.getHeadSamples())
- continue;
- // If we don't have context, nothing to do for caller's call site.
- // This could happen for entry point function.
- if (CalleeContext.find(" @ ") == StringRef::npos)
- continue;
- // Infer Caller's frame loc and context ID through string splitting
- StringRef CallerContextId;
- FrameLocation &&CallerLeafFrameLoc =
- getCallerContext(CalleeContext, CallerContextId);
- // It's possible that we haven't seen any sample directly in the caller,
- // in which case CallerProfile will not exist. But we can't modify
- // ProfileMap while iterating it.
- // TODO: created function profile for those callers too
- if (ProfileMap.find(CallerContextId) == ProfileMap.end())
- continue;
- FunctionSamples &CallerProfile = ProfileMap[CallerContextId];
- // Since we don't have call count for inlined functions, we
- // estimate it from inlinee's profile using entry body sample.
- uint64_t EstimatedCallCount = CalleeProfile.getEntrySamples();
- // If we don't have samples with location, use 1 to indicate live.
- if (!EstimatedCallCount && !CalleeProfile.getBodySamples().size())
- EstimatedCallCount = 1;
- CallerProfile.addCalledTargetSamples(
- CallerLeafFrameLoc.second.LineOffset,
- CallerLeafFrameLoc.second.Discriminator,
- CalleeProfile.getContext().getNameWithoutContext(), EstimatedCallCount);
- CallerProfile.addBodySamples(CallerLeafFrameLoc.second.LineOffset,
- CallerLeafFrameLoc.second.Discriminator,
- EstimatedCallCount);
- CallerProfile.addTotalSamples(EstimatedCallCount);
- }
- }
- void CSProfileGenerator::mergeAndTrimColdProfile(
- StringMap<FunctionSamples> &ProfileMap) {
- // Nothing to merge if sample threshold is zero
- if (!CSProfColdThres)
- return;
- // Filter the cold profiles from ProfileMap and move them into a tmp
- // container
- std::vector<std::pair<StringRef, const FunctionSamples *>> ToRemoveVec;
- for (const auto &I : ProfileMap) {
- const FunctionSamples &FunctionProfile = I.second;
- if (FunctionProfile.getTotalSamples() >= CSProfColdThres)
- continue;
- ToRemoveVec.emplace_back(I.getKey(), &I.second);
- }
- // Remove the code profile from ProfileMap and merge them into BaseProileMap
- StringMap<FunctionSamples> BaseProfileMap;
- for (const auto &I : ToRemoveVec) {
- auto Ret = BaseProfileMap.try_emplace(
- I.second->getContext().getNameWithoutContext(), FunctionSamples());
- FunctionSamples &BaseProfile = Ret.first->second;
- BaseProfile.merge(*I.second);
- ProfileMap.erase(I.first);
- }
- // Merge the base profiles into ProfileMap;
- for (const auto &I : BaseProfileMap) {
- // Filter the cold base profile
- if (!CSProfKeepCold && I.second.getTotalSamples() < CSProfColdThres &&
- ProfileMap.find(I.getKey()) == ProfileMap.end())
- continue;
- // Merge the profile if the original profile exists, otherwise just insert
- // as a new profile
- FunctionSamples &OrigProfile = getFunctionProfileForContext(I.getKey());
- OrigProfile.merge(I.second);
- }
- }
- void CSProfileGenerator::write(std::unique_ptr<SampleProfileWriter> Writer,
- StringMap<FunctionSamples> &ProfileMap) {
- mergeAndTrimColdProfile(ProfileMap);
- // Add bracket for context key to support different profile binary format
- StringMap<FunctionSamples> CxtWithBracketPMap;
- for (const auto &Item : ProfileMap) {
- std::string ContextWithBracket = "[" + Item.first().str() + "]";
- auto Ret = CxtWithBracketPMap.try_emplace(ContextWithBracket, Item.second);
- assert(Ret.second && "Must be a unique context");
- SampleContext FContext(Ret.first->first(), RawContext);
- FunctionSamples &FProfile = Ret.first->second;
- FProfile.setName(FContext.getNameWithContext(true));
- FProfile.setContext(FContext);
- }
- Writer->write(CxtWithBracketPMap);
- }
- // Helper function to extract context prefix string stack
- // Extract context stack for reusing, leaf context stack will
- // be added compressed while looking up function profile
- static void
- extractPrefixContextStack(SmallVectorImpl<std::string> &ContextStrStack,
- const SmallVectorImpl<const PseudoProbe *> &Probes,
- ProfiledBinary *Binary) {
- for (const auto *P : Probes) {
- Binary->getInlineContextForProbe(P, ContextStrStack, true);
- }
- }
- void PseudoProbeCSProfileGenerator::generateProfile() {
- // Enable pseudo probe functionalities in SampleProf
- 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());
- SmallVector<std::string, 16> ContextStrStack;
- extractPrefixContextStack(ContextStrStack, CtxKey->Probes, Binary);
- // Fill in function body samples from probes, also infer caller's samples
- // from callee's probe
- populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStrStack,
- Binary);
- // Fill in boundary samples for a call probe
- populateBoundarySamplesWithProbes(CI.second.BranchCounter,
- ContextStrStack, 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,
- SmallVectorImpl<std::string> &ContextStrStack, 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(ContextStrStack, 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.getContext().getNameWithoutContext(), Count);
- }
- }
- }
- }
- void PseudoProbeCSProfileGenerator::populateBoundarySamplesWithProbes(
- const BranchSample &BranchCounter,
- SmallVectorImpl<std::string> &ContextStrStack, 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(ContextStrStack, 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(
- SmallVectorImpl<std::string> &ContextStrStack,
- const PseudoProbeFuncDesc *LeafFuncDesc) {
- assert(ContextStrStack.size() && "Profile context must have the leaf frame");
- // Compress the context string except for the leaf frame
- std::string LeafFrame = ContextStrStack.back();
- ContextStrStack.pop_back();
- CSProfileGenerator::compressRecursionContext(ContextStrStack);
- std::ostringstream OContextStr;
- for (uint32_t I = 0; I < ContextStrStack.size(); I++) {
- if (OContextStr.str().size())
- OContextStr << " @ ";
- OContextStr << ContextStrStack[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 << " @ ";
- OContextStr << StringRef(LeafFrame).split(":").first.str();
- FunctionSamples &FunctionProile =
- getFunctionProfileForContext(OContextStr.str());
- FunctionProile.setFunctionHash(LeafFuncDesc->FuncHash);
- return FunctionProile;
- }
- FunctionSamples &PseudoProbeCSProfileGenerator::getFunctionProfileForLeafProbe(
- SmallVectorImpl<std::string> &ContextStrStack, const PseudoProbe *LeafProbe,
- ProfiledBinary *Binary) {
- // Explicitly copy the context for appending the leaf context
- SmallVector<std::string, 16> ContextStrStackCopy(ContextStrStack.begin(),
- ContextStrStack.end());
- Binary->getInlineContextForProbe(LeafProbe, ContextStrStackCopy);
- // 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);
- ContextStrStackCopy.emplace_back(FuncDesc->FuncName + ":" +
- Twine(LeafProbe->Index).str());
- return getFunctionProfileForLeafProbe(ContextStrStackCopy, FuncDesc);
- }
- } // end namespace sampleprof
- } // end namespace llvm
|