Skip to content

Commit ee7d20e

Browse files
jamesluoxhtyu
authored andcommitted
[CSSPGO] Migrate and refactor the decoder of Pseudo Probe
Migrate pseudo probe decoding logic in llvm-profgen to MC, so other LLVM-base program could reuse existing codes. Redesign object layout of encoded and decoded pseudo probes. Reviewed By: hoy Differential Revision: https://reviews.llvm.org/D106861
1 parent fe6ae81 commit ee7d20e

File tree

12 files changed

+692
-646
lines changed

12 files changed

+692
-646
lines changed

llvm/include/llvm/MC/MCPseudoProbe.h

Lines changed: 264 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,25 @@
4545
#define LLVM_MC_MCPSEUDOPROBE_H
4646

4747
#include "llvm/ADT/MapVector.h"
48+
#include "llvm/ADT/StringRef.h"
49+
#include "llvm/ADT/Twine.h"
50+
#include "llvm/IR/PseudoProbe.h"
4851
#include "llvm/MC/MCSection.h"
52+
#include "llvm/Support/Errc.h"
53+
#include "llvm/Support/Error.h"
54+
#include "llvm/Support/ErrorOr.h"
55+
#include "llvm/Support/WithColor.h"
56+
#include "llvm/Support/raw_ostream.h"
57+
#include <algorithm>
4958
#include <functional>
59+
#include <list>
5060
#include <map>
61+
#include <set>
62+
#include <sstream>
63+
#include <string>
64+
#include <system_error>
65+
#include <unordered_map>
66+
#include <unordered_set>
5167
#include <vector>
5268

5369
namespace llvm {
@@ -62,69 +78,213 @@ enum class MCPseudoProbeFlag {
6278
AddressDelta = 0x1,
6379
};
6480

81+
// Function descriptor decoded from .pseudo_probe_desc section
82+
struct MCPseudoProbeFuncDesc {
83+
uint64_t FuncGUID = 0;
84+
uint64_t FuncHash = 0;
85+
std::string FuncName;
86+
87+
MCPseudoProbeFuncDesc(uint64_t GUID, uint64_t Hash, StringRef Name)
88+
: FuncGUID(GUID), FuncHash(Hash), FuncName(Name){};
89+
90+
void print(raw_ostream &OS);
91+
};
92+
93+
class MCPseudoProbe;
94+
class MCDecodedPseudoProbe;
95+
96+
// An inline frame has the form <Guid, ProbeID>
97+
using InlineSite = std::tuple<uint64_t, uint32_t>;
98+
using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>;
99+
// GUID to PseudoProbeFuncDesc map
100+
using GUIDProbeFunctionMap =
101+
std::unordered_map<uint64_t, MCPseudoProbeFuncDesc>;
102+
// Address to pseudo probes map.
103+
using AddressProbesMap =
104+
std::unordered_map<uint64_t, std::list<MCDecodedPseudoProbe>>;
105+
106+
class MCPseudoProbeInlineTree;
107+
class MCDecodedPseudoProbeInlineTree;
108+
109+
class MCPseudoProbeBase {
110+
protected:
111+
uint64_t Guid;
112+
uint64_t Index;
113+
uint8_t Attributes;
114+
uint8_t Type;
115+
// The value should be equal to PseudoProbeReservedId::Last + 1 which is
116+
// defined in SampleProfileProbe.h. The header file is not included here to
117+
// reduce the dependency from MC to IPO.
118+
const static uint32_t PseudoProbeFirstId = 1;
119+
120+
public:
121+
MCPseudoProbeBase(uint64_t G, uint64_t I, uint64_t At, uint8_t T)
122+
: Guid(G), Index(I), Attributes(At), Type(T) {}
123+
124+
bool isEntry() const { return Index == PseudoProbeFirstId; }
125+
126+
bool isTailCall() const {
127+
return Attributes & static_cast<uint8_t>(PseudoProbeAttributes::Reserved);
128+
}
129+
130+
uint64_t getGuid() const { return Guid; }
131+
132+
uint64_t getIndex() const { return Index; }
133+
134+
uint8_t getAttributes() const { return Attributes; }
135+
136+
uint8_t getType() const { return Type; }
137+
138+
bool isBlock() const {
139+
return Type == static_cast<uint8_t>(PseudoProbeType::Block);
140+
}
141+
142+
bool isIndirectCall() const {
143+
return Type == static_cast<uint8_t>(PseudoProbeType::IndirectCall);
144+
}
145+
146+
bool isDirectCall() const {
147+
return Type == static_cast<uint8_t>(PseudoProbeType::DirectCall);
148+
}
149+
150+
bool isCall() const { return isIndirectCall() || isDirectCall(); }
151+
152+
void setAttributes(uint8_t Attr) { Attributes = Attr; }
153+
};
154+
65155
/// Instances of this class represent a pseudo probe instance for a pseudo probe
66156
/// table entry, which is created during a machine instruction is assembled and
67157
/// uses an address from a temporary label created at the current address in the
68158
/// current section.
69-
class MCPseudoProbe {
159+
class MCPseudoProbe : public MCPseudoProbeBase {
70160
MCSymbol *Label;
71-
uint64_t Guid;
72-
uint64_t Index;
73-
uint8_t Type;
74-
uint8_t Attributes;
75161

76162
public:
77163
MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type,
78164
uint64_t Attributes)
79-
: Label(Label), Guid(Guid), Index(Index), Type(Type),
80-
Attributes(Attributes) {
165+
: MCPseudoProbeBase(Guid, Index, Attributes, Type), Label(Label) {
81166
assert(Type <= 0xFF && "Probe type too big to encode, exceeding 2^8");
82167
assert(Attributes <= 0xFF &&
83168
"Probe attributes too big to encode, exceeding 2^16");
84169
}
85170

86171
MCSymbol *getLabel() const { return Label; }
172+
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const;
173+
};
87174

88-
uint64_t getGuid() const { return Guid; }
175+
class MCDecodedPseudoProbe : public MCPseudoProbeBase {
176+
uint64_t Address;
177+
MCDecodedPseudoProbeInlineTree *InlineTree;
89178

90-
uint64_t getIndex() const { return Index; }
179+
public:
180+
MCDecodedPseudoProbe(uint64_t Ad, uint64_t G, uint32_t I, PseudoProbeType K,
181+
uint8_t At, MCDecodedPseudoProbeInlineTree *Tree)
182+
: MCPseudoProbeBase(G, I, At, static_cast<uint8_t>(K)), Address(Ad),
183+
InlineTree(Tree){};
91184

92-
uint8_t getType() const { return Type; }
185+
uint64_t getAddress() const { return Address; }
93186

94-
uint8_t getAttributes() const { return Attributes; }
187+
void setAddress(uint64_t Addr) { Address = Addr; }
95188

96-
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const;
189+
MCDecodedPseudoProbeInlineTree *getInlineTreeNode() const {
190+
return InlineTree;
191+
}
192+
193+
// Get the inlined context by traversing current inline tree backwards,
194+
// each tree node has its InlineSite which is taken as the context.
195+
// \p ContextStack is populated in root to leaf order
196+
void getInlineContext(SmallVectorImpl<std::string> &ContextStack,
197+
const GUIDProbeFunctionMap &GUID2FuncMAP,
198+
bool ShowName) const;
199+
200+
// Helper function to get the string from context stack
201+
std::string getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP,
202+
bool ShowName) const;
203+
204+
// Print pseudo probe while disassembling
205+
void print(raw_ostream &OS, const GUIDProbeFunctionMap &GUID2FuncMAP,
206+
bool ShowName) const;
97207
};
98208

99-
// An inline frame has the form <Guid, ProbeID>
100-
using InlineSite = std::tuple<uint64_t, uint32_t>;
101-
using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>;
209+
template <typename ProbeType, typename DerivedProbeInlineTreeType>
210+
class MCPseudoProbeInlineTreeBase {
211+
struct InlineSiteHash {
212+
uint64_t operator()(const InlineSite &Site) const {
213+
return std::get<0>(Site) ^ std::get<1>(Site);
214+
}
215+
};
216+
217+
protected:
218+
// Track children (e.g. inlinees) of current context
219+
using InlinedProbeTreeMap = std::unordered_map<
220+
InlineSite, std::unique_ptr<DerivedProbeInlineTreeType>, InlineSiteHash>;
221+
InlinedProbeTreeMap Children;
222+
// Set of probes that come with the function.
223+
std::vector<ProbeType> Probes;
224+
MCPseudoProbeInlineTreeBase() {
225+
static_assert(std::is_base_of<MCPseudoProbeInlineTreeBase,
226+
DerivedProbeInlineTreeType>::value,
227+
"DerivedProbeInlineTreeType must be subclass of "
228+
"MCPseudoProbeInlineTreeBase");
229+
}
230+
231+
public:
232+
uint64_t Guid = 0;
233+
234+
// Root node has a GUID 0.
235+
bool isRoot() const { return Guid == 0; }
236+
InlinedProbeTreeMap &getChildren() { return Children; }
237+
const InlinedProbeTreeMap &getChildren() const { return Children; }
238+
std::vector<ProbeType> &getProbes() { return Probes; }
239+
void addProbes(ProbeType Probe) { Probes.push_back(Probe); }
240+
// Caller node of the inline site
241+
MCPseudoProbeInlineTreeBase<ProbeType, DerivedProbeInlineTreeType> *Parent;
242+
DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) {
243+
auto Ret = Children.emplace(
244+
Site, std::make_unique<DerivedProbeInlineTreeType>(Site));
245+
Ret.first->second->Parent = this;
246+
return Ret.first->second.get();
247+
};
248+
};
102249

103250
// A Tri-tree based data structure to group probes by inline stack.
104251
// A tree is allocated for a standalone .text section. A fake
105252
// instance is created as the root of a tree.
106253
// A real instance of this class is created for each function, either an
107254
// unlined function that has code in .text section or an inlined function.
108-
class MCPseudoProbeInlineTree {
109-
uint64_t Guid;
110-
// Set of probes that come with the function.
111-
std::vector<MCPseudoProbe> Probes;
112-
// Use std::map for a deterministic output.
113-
std::map<InlineSite, MCPseudoProbeInlineTree *> Inlinees;
114-
115-
// Root node has a GUID 0.
116-
bool isRoot() { return Guid == 0; }
117-
MCPseudoProbeInlineTree *getOrAddNode(InlineSite Site);
118255

256+
class MCPseudoProbeInlineTree
257+
: public MCPseudoProbeInlineTreeBase<MCPseudoProbe,
258+
MCPseudoProbeInlineTree> {
119259
public:
120260
MCPseudoProbeInlineTree() = default;
121-
MCPseudoProbeInlineTree(uint64_t Guid) : Guid(Guid) {}
122-
~MCPseudoProbeInlineTree();
261+
MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; }
262+
MCPseudoProbeInlineTree(const InlineSite &Site) {
263+
this->Guid = std::get<0>(Site);
264+
}
265+
266+
// MCPseudoProbeInlineTree method based on Inlinees
123267
void addPseudoProbe(const MCPseudoProbe &Probe,
124268
const MCPseudoProbeInlineStack &InlineStack);
125269
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe);
126270
};
127271

272+
// inline tree node for the decoded pseudo probe
273+
class MCDecodedPseudoProbeInlineTree
274+
: public MCPseudoProbeInlineTreeBase<MCDecodedPseudoProbe *,
275+
MCDecodedPseudoProbeInlineTree> {
276+
public:
277+
InlineSite ISite;
278+
// Used for decoding
279+
uint32_t ChildrenToProcess = 0;
280+
281+
MCDecodedPseudoProbeInlineTree(){};
282+
MCDecodedPseudoProbeInlineTree(const InlineSite &Site) : ISite(Site){};
283+
284+
// Return false if it's a dummy inline site
285+
bool hasInlineSite() const { return std::get<0>(ISite) != 0; }
286+
};
287+
128288
/// Instances of this class represent the pseudo probes inserted into a compile
129289
/// unit.
130290
class MCPseudoProbeSection {
@@ -172,6 +332,83 @@ class MCPseudoProbeTable {
172332
static int DdgPrintIndent;
173333
#endif
174334
};
335+
336+
class MCPseudoProbeDecoder {
337+
// GUID to PseudoProbeFuncDesc map.
338+
GUIDProbeFunctionMap GUID2FuncDescMap;
339+
340+
// Address to probes map.
341+
AddressProbesMap Address2ProbesMap;
342+
343+
// The dummy root of the inline trie, all the outlined function will directly
344+
// be the children of the dummy root, all the inlined function will be the
345+
// children of its inlineer. So the relation would be like:
346+
// DummyRoot --> OutlinedFunc --> InlinedFunc1 --> InlinedFunc2
347+
MCDecodedPseudoProbeInlineTree DummyInlineRoot;
348+
349+
/// Points to the current location in the buffer.
350+
const uint8_t *Data = nullptr;
351+
352+
/// Points to the end of the buffer.
353+
const uint8_t *End = nullptr;
354+
355+
// Decoding helper function
356+
template <typename T> ErrorOr<T> readUnencodedNumber();
357+
template <typename T> ErrorOr<T> readUnsignedNumber();
358+
template <typename T> ErrorOr<T> readSignedNumber();
359+
ErrorOr<StringRef> readString(uint32_t Size);
360+
361+
public:
362+
// Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map.
363+
bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size);
364+
365+
// Decode pseudo_probe section to build address to probes map.
366+
bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size);
367+
368+
// Print pseudo_probe_desc section info
369+
void printGUID2FuncDescMap(raw_ostream &OS);
370+
371+
// Print pseudo_probe section info, used along with show-disassembly
372+
void printProbeForAddress(raw_ostream &OS, uint64_t Address);
373+
374+
// do printProbeForAddress for all addresses
375+
void printProbesForAllAddresses(raw_ostream &OS);
376+
377+
// Look up the probe of a call for the input address
378+
const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const;
379+
380+
const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const;
381+
382+
// Helper function to populate one probe's inline stack into
383+
// \p InlineContextStack.
384+
// Current leaf location info will be added if IncludeLeaf is true
385+
// Example:
386+
// Current probe(bar:3) inlined at foo:2 then inlined at main:1
387+
// IncludeLeaf = true, Output: [main:1, foo:2, bar:3]
388+
// IncludeLeaf = false, Output: [main:1, foo:2]
389+
void
390+
getInlineContextForProbe(const MCDecodedPseudoProbe *Probe,
391+
SmallVectorImpl<std::string> &InlineContextStack,
392+
bool IncludeLeaf) const;
393+
394+
const AddressProbesMap &getAddress2ProbesMap() const {
395+
return Address2ProbesMap;
396+
}
397+
398+
AddressProbesMap &getAddress2ProbesMap() { return Address2ProbesMap; }
399+
400+
const GUIDProbeFunctionMap &getGUID2FuncDescMap() const {
401+
return GUID2FuncDescMap;
402+
}
403+
404+
const MCPseudoProbeFuncDesc *
405+
getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) const;
406+
407+
const MCDecodedPseudoProbeInlineTree &getDummyInlineRoot() const {
408+
return DummyInlineRoot;
409+
}
410+
};
411+
175412
} // end namespace llvm
176413

177414
#endif // LLVM_MC_MCPSEUDOPROBE_H

llvm/lib/MC/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ add_llvm_component_library(LLVMMC
7070
Support
7171
BinaryFormat
7272
DebugInfoCodeView
73+
ProfileData
7374
)
7475

7576
add_subdirectory(MCParser)

0 commit comments

Comments
 (0)