-
Notifications
You must be signed in to change notification settings - Fork 11.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MC][NFC] Statically allocate storage for decoded pseudo probes and function records #102789
Merged
aaupov
merged 11 commits into
main
from
users/aaupov/spr/mcnfc-statically-allocate-storage-for-decoded-pseudo-probes-and-function-records
Aug 26, 2024
Merged
Changes from 8 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
023e1a4
[𝘀𝗽𝗿] changes to main this commit is based on
aaupov fc9bfe9
[𝘀𝗽𝗿] initial version
aaupov 7771414
[𝘀𝗽𝗿] changes introduced through rebase
aaupov aa535ef
further reduce MCDecodedPseudoProbe and InlineTree structure sizes
aaupov ddcbb59
Pass CurChildIndex by value
aaupov f13f9cd
[𝘀𝗽𝗿] changes introduced through rebase
aaupov 2b56ea1
Comment InjectedProbeMap, refactor MCPseudoProbeInlineTreeBase
aaupov 73d808a
s/ChildrenType/InlinedProbeTreeMap
aaupov 800dfcd
Add asserts, address comments
aaupov fa3b045
[𝘀𝗽𝗿] changes introduced through rebase
aaupov da8aa75
rebase
aaupov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,20 +54,21 @@ | |
#ifndef LLVM_MC_MCPSEUDOPROBE_H | ||
#define LLVM_MC_MCPSEUDOPROBE_H | ||
|
||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/DenseMap.h" | ||
#include "llvm/ADT/DenseSet.h" | ||
#include "llvm/ADT/SmallVector.h" | ||
#include "llvm/ADT/StringRef.h" | ||
#include "llvm/ADT/iterator.h" | ||
#include "llvm/IR/PseudoProbe.h" | ||
#include "llvm/Support/ErrorOr.h" | ||
#include <list> | ||
#include <functional> | ||
#include <map> | ||
#include <memory> | ||
#include <string> | ||
#include <tuple> | ||
#include <type_traits> | ||
#include <unordered_map> | ||
#include <unordered_set> | ||
#include <vector> | ||
|
||
namespace llvm { | ||
|
@@ -103,14 +104,15 @@ using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>; | |
using GUIDProbeFunctionMap = | ||
std::unordered_map<uint64_t, MCPseudoProbeFuncDesc>; | ||
// Address to pseudo probes map. | ||
using AddressProbesMap = std::map<uint64_t, std::list<MCDecodedPseudoProbe>>; | ||
using AddressProbesMap = | ||
std::map<uint64_t, | ||
std::vector<std::reference_wrapper<MCDecodedPseudoProbe>>>; | ||
|
||
class MCDecodedPseudoProbeInlineTree; | ||
|
||
class MCPseudoProbeBase { | ||
protected: | ||
uint64_t Guid; | ||
uint64_t Index; | ||
uint32_t Index; | ||
uint32_t Discriminator; | ||
uint8_t Attributes; | ||
uint8_t Type; | ||
|
@@ -120,14 +122,12 @@ class MCPseudoProbeBase { | |
const static uint32_t PseudoProbeFirstId = 1; | ||
|
||
public: | ||
MCPseudoProbeBase(uint64_t G, uint64_t I, uint64_t At, uint8_t T, uint32_t D) | ||
: Guid(G), Index(I), Discriminator(D), Attributes(At), Type(T) {} | ||
MCPseudoProbeBase(uint64_t I, uint64_t At, uint8_t T, uint32_t D) | ||
: Index(I), Discriminator(D), Attributes(At), Type(T) {} | ||
|
||
bool isEntry() const { return Index == PseudoProbeFirstId; } | ||
|
||
uint64_t getGuid() const { return Guid; } | ||
|
||
uint64_t getIndex() const { return Index; } | ||
uint32_t getIndex() const { return Index; } | ||
|
||
uint32_t getDiscriminator() const { return Discriminator; } | ||
|
||
|
@@ -157,18 +157,20 @@ class MCPseudoProbeBase { | |
/// uses an address from a temporary label created at the current address in the | ||
/// current section. | ||
class MCPseudoProbe : public MCPseudoProbeBase { | ||
uint64_t Guid; | ||
MCSymbol *Label; | ||
|
||
public: | ||
MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type, | ||
uint64_t Attributes, uint32_t Discriminator) | ||
: MCPseudoProbeBase(Guid, Index, Attributes, Type, Discriminator), | ||
: MCPseudoProbeBase(Index, Attributes, Type, Discriminator), Guid(Guid), | ||
Label(Label) { | ||
assert(Type <= 0xFF && "Probe type too big to encode, exceeding 2^8"); | ||
assert(Attributes <= 0xFF && | ||
"Probe attributes too big to encode, exceeding 2^16"); | ||
} | ||
|
||
uint64_t getGuid() const { return Guid; }; | ||
MCSymbol *getLabel() const { return Label; } | ||
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const; | ||
}; | ||
|
@@ -181,11 +183,11 @@ class MCDecodedPseudoProbe : public MCPseudoProbeBase { | |
MCDecodedPseudoProbeInlineTree *InlineTree; | ||
|
||
public: | ||
MCDecodedPseudoProbe(uint64_t Ad, uint64_t G, uint32_t I, PseudoProbeType K, | ||
uint8_t At, uint32_t D, | ||
MCDecodedPseudoProbeInlineTree *Tree) | ||
: MCPseudoProbeBase(G, I, At, static_cast<uint8_t>(K), D), Address(Ad), | ||
MCDecodedPseudoProbe(uint64_t Ad, uint32_t I, PseudoProbeType K, uint8_t At, | ||
uint32_t D, MCDecodedPseudoProbeInlineTree *Tree) | ||
: MCPseudoProbeBase(I, At, static_cast<uint8_t>(K), D), Address(Ad), | ||
InlineTree(Tree){}; | ||
uint64_t getGuid() const; | ||
|
||
uint64_t getAddress() const { return Address; } | ||
|
||
|
@@ -211,21 +213,14 @@ class MCDecodedPseudoProbe : public MCPseudoProbeBase { | |
bool ShowName) const; | ||
}; | ||
|
||
template <typename ProbeType, typename DerivedProbeInlineTreeType> | ||
template <typename ProbesType, typename DerivedProbeInlineTreeType, | ||
typename InlinedProbeTreeMap> | ||
class MCPseudoProbeInlineTreeBase { | ||
struct InlineSiteHash { | ||
uint64_t operator()(const InlineSite &Site) const { | ||
return std::get<0>(Site) ^ std::get<1>(Site); | ||
} | ||
}; | ||
|
||
protected: | ||
// Track children (e.g. inlinees) of current context | ||
using InlinedProbeTreeMap = std::unordered_map< | ||
InlineSite, std::unique_ptr<DerivedProbeInlineTreeType>, InlineSiteHash>; | ||
InlinedProbeTreeMap Children; | ||
// Set of probes that come with the function. | ||
std::vector<ProbeType> Probes; | ||
ProbesType Probes; | ||
MCPseudoProbeInlineTreeBase() { | ||
static_assert(std::is_base_of<MCPseudoProbeInlineTreeBase, | ||
DerivedProbeInlineTreeType>::value, | ||
|
@@ -240,12 +235,11 @@ class MCPseudoProbeInlineTreeBase { | |
bool isRoot() const { return Guid == 0; } | ||
InlinedProbeTreeMap &getChildren() { return Children; } | ||
const InlinedProbeTreeMap &getChildren() const { return Children; } | ||
std::vector<ProbeType> &getProbes() { return Probes; } | ||
const std::vector<ProbeType> &getProbes() const { return Probes; } | ||
void addProbes(ProbeType Probe) { Probes.push_back(Probe); } | ||
ProbesType &getProbes() { return Probes; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know where we require this function(anywhere can't replace with |
||
const ProbesType &getProbes() const { return Probes; } | ||
// Caller node of the inline site | ||
MCPseudoProbeInlineTreeBase<ProbeType, DerivedProbeInlineTreeType> *Parent = | ||
nullptr; | ||
MCPseudoProbeInlineTreeBase<ProbesType, DerivedProbeInlineTreeType, | ||
InlinedProbeTreeMap> *Parent = nullptr; | ||
DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) { | ||
auto Ret = Children.emplace( | ||
Site, std::make_unique<DerivedProbeInlineTreeType>(Site)); | ||
|
@@ -259,9 +253,17 @@ class MCPseudoProbeInlineTreeBase { | |
// instance is created as the root of a tree. | ||
// A real instance of this class is created for each function, either a | ||
// not inlined function that has code in .text section or an inlined function. | ||
struct InlineSiteHash { | ||
uint64_t operator()(const InlineSite &Site) const { | ||
return std::get<0>(Site) ^ std::get<1>(Site); | ||
} | ||
}; | ||
class MCPseudoProbeInlineTree | ||
: public MCPseudoProbeInlineTreeBase<MCPseudoProbe, | ||
MCPseudoProbeInlineTree> { | ||
: public MCPseudoProbeInlineTreeBase< | ||
std::vector<MCPseudoProbe>, MCPseudoProbeInlineTree, | ||
std::unordered_map<InlineSite, | ||
std::unique_ptr<MCPseudoProbeInlineTree>, | ||
InlineSiteHash>> { | ||
public: | ||
MCPseudoProbeInlineTree() = default; | ||
MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; } | ||
|
@@ -277,16 +279,31 @@ class MCPseudoProbeInlineTree | |
|
||
// inline tree node for the decoded pseudo probe | ||
class MCDecodedPseudoProbeInlineTree | ||
: public MCPseudoProbeInlineTreeBase<MCDecodedPseudoProbe *, | ||
MCDecodedPseudoProbeInlineTree> { | ||
public: | ||
InlineSite ISite; | ||
: public MCPseudoProbeInlineTreeBase< | ||
MCDecodedPseudoProbe *, MCDecodedPseudoProbeInlineTree, | ||
MutableArrayRef<MCDecodedPseudoProbeInlineTree>> { | ||
uint32_t NumProbes = 0; | ||
uint32_t ProbeId = 0; | ||
|
||
public: | ||
MCDecodedPseudoProbeInlineTree() = default; | ||
MCDecodedPseudoProbeInlineTree(const InlineSite &Site) : ISite(Site){}; | ||
MCDecodedPseudoProbeInlineTree(const InlineSite &Site, | ||
MCDecodedPseudoProbeInlineTree *Parent) | ||
: ProbeId(std::get<1>(Site)) { | ||
this->Guid = std::get<0>(Site); | ||
this->Parent = Parent; | ||
} | ||
|
||
// Return false if it's a dummy inline site | ||
bool hasInlineSite() const { return !isRoot() && !Parent->isRoot(); } | ||
InlineSite getInlineSite() const { return InlineSite(Guid, ProbeId); } | ||
void setProbes(MutableArrayRef<MCDecodedPseudoProbe> ProbesRef) { | ||
Probes = ProbesRef.data(); | ||
NumProbes = ProbesRef.size(); | ||
} | ||
auto getProbes() const { | ||
return MutableArrayRef<MCDecodedPseudoProbe>(Probes, NumProbes); | ||
} | ||
}; | ||
|
||
/// Instances of this class represent the pseudo probes inserted into a compile | ||
|
@@ -336,6 +353,20 @@ class MCPseudoProbeTable { | |
}; | ||
|
||
class MCPseudoProbeDecoder { | ||
// Decoded pseudo probes vector. | ||
std::vector<MCDecodedPseudoProbe> PseudoProbeVec; | ||
// Injected pseudo probes, identified by the containing inline tree node. | ||
// Need to keep injected probes separately for two reasons: | ||
// 1) Probes cannot be added to the PseudoProbeVec: appending may cause | ||
// reallocation so that pointers to its elements will become invalid. | ||
// 2) Probes belonging to function record must be contiguous in PseudoProbeVec | ||
// as owning InlineTree references them with an ArrayRef to save space. | ||
std::unordered_map<const MCDecodedPseudoProbeInlineTree *, | ||
std::vector<MCDecodedPseudoProbe>> | ||
InjectedProbeMap; | ||
// Decoded inline records vector. | ||
std::vector<MCDecodedPseudoProbeInlineTree> InlineTreeVec; | ||
|
||
// GUID to PseudoProbeFuncDesc map. | ||
GUIDProbeFunctionMap GUID2FuncDescMap; | ||
|
||
|
@@ -370,16 +401,18 @@ class MCPseudoProbeDecoder { | |
// Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map. | ||
bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size); | ||
|
||
// Decode pseudo_probe section to count the number of probes and inlined | ||
// function records for each function record. | ||
template <bool IsTopLevelFunc> | ||
bool countRecords(bool &Discard, uint32_t &ProbeCount, uint32_t &InlinedCount, | ||
const Uint64Set &GuidFilter); | ||
|
||
// Decode pseudo_probe section to build address to probes map for specifed | ||
// functions only. | ||
bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size, | ||
const Uint64Set &GuildFilter, | ||
const Uint64Map &FuncStartAddrs); | ||
|
||
bool buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree *Cur, | ||
uint64_t &LastAddr, const Uint64Set &GuildFilter, | ||
const Uint64Map &FuncStartAddrs); | ||
|
||
// Print pseudo_probe_desc section info | ||
void printGUID2FuncDescMap(raw_ostream &OS); | ||
|
||
|
@@ -422,6 +455,34 @@ class MCPseudoProbeDecoder { | |
const MCDecodedPseudoProbeInlineTree &getDummyInlineRoot() const { | ||
return DummyInlineRoot; | ||
} | ||
|
||
void addInjectedProbe(const MCDecodedPseudoProbe &Probe, uint64_t Address) { | ||
const MCDecodedPseudoProbeInlineTree *Parent = Probe.getInlineTreeNode(); | ||
InjectedProbeMap[Parent].emplace_back(Probe).setAddress(Address); | ||
} | ||
|
||
size_t | ||
getNumInjectedProbes(const MCDecodedPseudoProbeInlineTree *Parent) const { | ||
auto It = InjectedProbeMap.find(Parent); | ||
if (It == InjectedProbeMap.end()) | ||
return 0; | ||
return It->second.size(); | ||
} | ||
|
||
auto getInjectedProbes(MCDecodedPseudoProbeInlineTree *Parent) { | ||
auto It = InjectedProbeMap.find(Parent); | ||
assert(It != InjectedProbeMap.end()); | ||
return iterator_range(It->second); | ||
} | ||
|
||
private: | ||
// Recursively parse an inlining tree encoded in pseudo_probe section. Returns | ||
// whether the the top-level node should be skipped. | ||
template <bool IsTopLevelFunc> | ||
bool buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree *Cur, | ||
uint64_t &LastAddr, const Uint64Set &GuildFilter, | ||
const Uint64Map &FuncStartAddrs, | ||
const uint32_t CurChildIndex); | ||
}; | ||
|
||
} // end namespace llvm | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we need this change? seems it's not related to decoding pseudo probe, or is it because we allocate a fixed size of
MCDecodedPseudoProbe
, so later there is no way to add additional probe to the vector. To address this, we have to use a new containerInjectedProbeMap
to save new probes. If so, could you add comments to explain this(maybe in the definition ofInjectedProbeMap
)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's required because appending to ProbeVec may cause its reallocation so that pointers to its elements will become invalid. I'll leave a comment.