Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- MCPseudoProbe.h - Pseudo probe encoding support ---------*- C++ -*-===// |
2 | // |
||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
4 | // See https://llvm.org/LICENSE.txt for license information. |
||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
6 | // |
||
7 | //===----------------------------------------------------------------------===// |
||
8 | // |
||
9 | // This file contains the declaration of the MCPseudoProbe to support the pseudo |
||
10 | // probe encoding for AutoFDO. Pseudo probes together with their inline context |
||
11 | // are encoded in a DFS recursive way in the .pseudoprobe sections. For each |
||
12 | // .pseudoprobe section, the encoded binary data consist of a single or mutiple |
||
13 | // function records each for one outlined function. A function record has the |
||
14 | // following format : |
||
15 | // |
||
16 | // FUNCTION BODY (one for each outlined function present in the text section) |
||
17 | // GUID (uint64) |
||
18 | // GUID of the function's source name which may be different from the |
||
19 | // actual binary linkage name. This GUID will be used to decode and |
||
20 | // generate a profile against the source function name. |
||
21 | // NPROBES (ULEB128) |
||
22 | // Number of probes originating from this function. |
||
23 | // NUM_INLINED_FUNCTIONS (ULEB128) |
||
24 | // Number of callees inlined into this function, aka number of |
||
25 | // first-level inlinees |
||
26 | // PROBE RECORDS |
||
27 | // A list of NPROBES entries. Each entry contains: |
||
28 | // INDEX (ULEB128) |
||
29 | // TYPE (uint4) |
||
30 | // 0 - block probe, 1 - indirect call, 2 - direct call |
||
31 | // ATTRIBUTE (uint3) |
||
32 | // 1 - reserved |
||
33 | // ADDRESS_TYPE (uint1) |
||
34 | // 0 - code address for regular probes (for downwards compatibility) |
||
35 | // - GUID of linkage name for sentinel probes |
||
36 | // 1 - address delta |
||
37 | // CODE_ADDRESS (uint64 or ULEB128) |
||
38 | // code address or address delta, depending on ADDRESS_TYPE |
||
39 | // INLINED FUNCTION RECORDS |
||
40 | // A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined |
||
41 | // callees. Each record contains: |
||
42 | // INLINE SITE |
||
43 | // ID of the callsite probe (ULEB128) |
||
44 | // FUNCTION BODY |
||
45 | // A FUNCTION BODY entry describing the inlined function. |
||
46 | // |
||
47 | // TODO: retire the ADDRESS_TYPE encoding for code addresses once compatibility |
||
48 | // is no longer an issue. |
||
49 | //===----------------------------------------------------------------------===// |
||
50 | |||
51 | #ifndef LLVM_MC_MCPSEUDOPROBE_H |
||
52 | #define LLVM_MC_MCPSEUDOPROBE_H |
||
53 | |||
54 | #include "llvm/ADT/DenseSet.h" |
||
55 | #include "llvm/ADT/SmallVector.h" |
||
56 | #include "llvm/ADT/StringRef.h" |
||
57 | #include "llvm/IR/PseudoProbe.h" |
||
58 | #include "llvm/Support/ErrorOr.h" |
||
59 | #include <list> |
||
60 | #include <map> |
||
61 | #include <memory> |
||
62 | #include <string> |
||
63 | #include <tuple> |
||
64 | #include <type_traits> |
||
65 | #include <unordered_map> |
||
66 | #include <unordered_set> |
||
67 | #include <vector> |
||
68 | |||
69 | namespace llvm { |
||
70 | |||
71 | class MCSymbol; |
||
72 | class MCObjectStreamer; |
||
73 | class raw_ostream; |
||
74 | |||
75 | enum class MCPseudoProbeFlag { |
||
76 | // If set, indicates that the probe is encoded as an address delta |
||
77 | // instead of a real code address. |
||
78 | AddressDelta = 0x1, |
||
79 | }; |
||
80 | |||
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 MCDecodedPseudoProbe; |
||
94 | |||
95 | // An inline frame has the form <CalleeGuid, ProbeID> |
||
96 | using InlineSite = std::tuple<uint64_t, uint32_t>; |
||
97 | using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>; |
||
98 | // GUID to PseudoProbeFuncDesc map |
||
99 | using GUIDProbeFunctionMap = |
||
100 | std::unordered_map<uint64_t, MCPseudoProbeFuncDesc>; |
||
101 | // Address to pseudo probes map. |
||
102 | using AddressProbesMap = |
||
103 | std::unordered_map<uint64_t, std::list<MCDecodedPseudoProbe>>; |
||
104 | |||
105 | class MCDecodedPseudoProbeInlineTree; |
||
106 | |||
107 | class MCPseudoProbeBase { |
||
108 | protected: |
||
109 | uint64_t Guid; |
||
110 | uint64_t Index; |
||
111 | uint8_t Attributes; |
||
112 | uint8_t Type; |
||
113 | // The value should be equal to PseudoProbeReservedId::Last + 1 which is |
||
114 | // defined in SampleProfileProbe.h. The header file is not included here to |
||
115 | // reduce the dependency from MC to IPO. |
||
116 | const static uint32_t PseudoProbeFirstId = 1; |
||
117 | |||
118 | public: |
||
119 | MCPseudoProbeBase(uint64_t G, uint64_t I, uint64_t At, uint8_t T) |
||
120 | : Guid(G), Index(I), Attributes(At), Type(T) {} |
||
121 | |||
122 | bool isEntry() const { return Index == PseudoProbeFirstId; } |
||
123 | |||
124 | uint64_t getGuid() const { return Guid; } |
||
125 | |||
126 | uint64_t getIndex() const { return Index; } |
||
127 | |||
128 | uint8_t getAttributes() const { return Attributes; } |
||
129 | |||
130 | uint8_t getType() const { return Type; } |
||
131 | |||
132 | bool isBlock() const { |
||
133 | return Type == static_cast<uint8_t>(PseudoProbeType::Block); |
||
134 | } |
||
135 | |||
136 | bool isIndirectCall() const { |
||
137 | return Type == static_cast<uint8_t>(PseudoProbeType::IndirectCall); |
||
138 | } |
||
139 | |||
140 | bool isDirectCall() const { |
||
141 | return Type == static_cast<uint8_t>(PseudoProbeType::DirectCall); |
||
142 | } |
||
143 | |||
144 | bool isCall() const { return isIndirectCall() || isDirectCall(); } |
||
145 | |||
146 | void setAttributes(uint8_t Attr) { Attributes = Attr; } |
||
147 | }; |
||
148 | |||
149 | /// Instances of this class represent a pseudo probe instance for a pseudo probe |
||
150 | /// table entry, which is created during a machine instruction is assembled and |
||
151 | /// uses an address from a temporary label created at the current address in the |
||
152 | /// current section. |
||
153 | class MCPseudoProbe : public MCPseudoProbeBase { |
||
154 | MCSymbol *Label; |
||
155 | |||
156 | public: |
||
157 | MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type, |
||
158 | uint64_t Attributes) |
||
159 | : MCPseudoProbeBase(Guid, Index, Attributes, Type), Label(Label) { |
||
160 | assert(Type <= 0xFF && "Probe type too big to encode, exceeding 2^8"); |
||
161 | assert(Attributes <= 0xFF && |
||
162 | "Probe attributes too big to encode, exceeding 2^16"); |
||
163 | } |
||
164 | |||
165 | MCSymbol *getLabel() const { return Label; } |
||
166 | void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const; |
||
167 | }; |
||
168 | |||
169 | // Represents a callsite with caller function name and probe id |
||
170 | using MCPseduoProbeFrameLocation = std::pair<StringRef, uint32_t>; |
||
171 | |||
172 | class MCDecodedPseudoProbe : public MCPseudoProbeBase { |
||
173 | uint64_t Address; |
||
174 | MCDecodedPseudoProbeInlineTree *InlineTree; |
||
175 | |||
176 | public: |
||
177 | MCDecodedPseudoProbe(uint64_t Ad, uint64_t G, uint32_t I, PseudoProbeType K, |
||
178 | uint8_t At, MCDecodedPseudoProbeInlineTree *Tree) |
||
179 | : MCPseudoProbeBase(G, I, At, static_cast<uint8_t>(K)), Address(Ad), |
||
180 | InlineTree(Tree){}; |
||
181 | |||
182 | uint64_t getAddress() const { return Address; } |
||
183 | |||
184 | void setAddress(uint64_t Addr) { Address = Addr; } |
||
185 | |||
186 | MCDecodedPseudoProbeInlineTree *getInlineTreeNode() const { |
||
187 | return InlineTree; |
||
188 | } |
||
189 | |||
190 | // Get the inlined context by traversing current inline tree backwards, |
||
191 | // each tree node has its InlineSite which is taken as the context. |
||
192 | // \p ContextStack is populated in root to leaf order |
||
193 | void |
||
194 | getInlineContext(SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack, |
||
195 | const GUIDProbeFunctionMap &GUID2FuncMAP) const; |
||
196 | |||
197 | // Helper function to get the string from context stack |
||
198 | std::string |
||
199 | getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP) const; |
||
200 | |||
201 | // Print pseudo probe while disassembling |
||
202 | void print(raw_ostream &OS, const GUIDProbeFunctionMap &GUID2FuncMAP, |
||
203 | bool ShowName) const; |
||
204 | }; |
||
205 | |||
206 | template <typename ProbeType, typename DerivedProbeInlineTreeType> |
||
207 | class MCPseudoProbeInlineTreeBase { |
||
208 | struct InlineSiteHash { |
||
209 | uint64_t operator()(const InlineSite &Site) const { |
||
210 | return std::get<0>(Site) ^ std::get<1>(Site); |
||
211 | } |
||
212 | }; |
||
213 | |||
214 | protected: |
||
215 | // Track children (e.g. inlinees) of current context |
||
216 | using InlinedProbeTreeMap = std::unordered_map< |
||
217 | InlineSite, std::unique_ptr<DerivedProbeInlineTreeType>, InlineSiteHash>; |
||
218 | InlinedProbeTreeMap Children; |
||
219 | // Set of probes that come with the function. |
||
220 | std::vector<ProbeType> Probes; |
||
221 | MCPseudoProbeInlineTreeBase() { |
||
222 | static_assert(std::is_base_of<MCPseudoProbeInlineTreeBase, |
||
223 | DerivedProbeInlineTreeType>::value, |
||
224 | "DerivedProbeInlineTreeType must be subclass of " |
||
225 | "MCPseudoProbeInlineTreeBase"); |
||
226 | } |
||
227 | |||
228 | public: |
||
229 | uint64_t Guid = 0; |
||
230 | |||
231 | // Root node has a GUID 0. |
||
232 | bool isRoot() const { return Guid == 0; } |
||
233 | InlinedProbeTreeMap &getChildren() { return Children; } |
||
234 | const InlinedProbeTreeMap &getChildren() const { return Children; } |
||
235 | std::vector<ProbeType> &getProbes() { return Probes; } |
||
236 | void addProbes(ProbeType Probe) { Probes.push_back(Probe); } |
||
237 | // Caller node of the inline site |
||
238 | MCPseudoProbeInlineTreeBase<ProbeType, DerivedProbeInlineTreeType> *Parent; |
||
239 | DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) { |
||
240 | auto Ret = Children.emplace( |
||
241 | Site, std::make_unique<DerivedProbeInlineTreeType>(Site)); |
||
242 | Ret.first->second->Parent = this; |
||
243 | return Ret.first->second.get(); |
||
244 | }; |
||
245 | }; |
||
246 | |||
247 | // A Tri-tree based data structure to group probes by inline stack. |
||
248 | // A tree is allocated for a standalone .text section. A fake |
||
249 | // instance is created as the root of a tree. |
||
250 | // A real instance of this class is created for each function, either a |
||
251 | // not inlined function that has code in .text section or an inlined function. |
||
252 | class MCPseudoProbeInlineTree |
||
253 | : public MCPseudoProbeInlineTreeBase<MCPseudoProbe, |
||
254 | MCPseudoProbeInlineTree> { |
||
255 | public: |
||
256 | MCPseudoProbeInlineTree() = default; |
||
257 | MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; } |
||
258 | MCPseudoProbeInlineTree(const InlineSite &Site) { |
||
259 | this->Guid = std::get<0>(Site); |
||
260 | } |
||
261 | |||
262 | // MCPseudoProbeInlineTree method based on Inlinees |
||
263 | void addPseudoProbe(const MCPseudoProbe &Probe, |
||
264 | const MCPseudoProbeInlineStack &InlineStack); |
||
265 | void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe); |
||
266 | }; |
||
267 | |||
268 | // inline tree node for the decoded pseudo probe |
||
269 | class MCDecodedPseudoProbeInlineTree |
||
270 | : public MCPseudoProbeInlineTreeBase<MCDecodedPseudoProbe *, |
||
271 | MCDecodedPseudoProbeInlineTree> { |
||
272 | public: |
||
273 | InlineSite ISite; |
||
274 | // Used for decoding |
||
275 | uint32_t ChildrenToProcess = 0; |
||
276 | |||
277 | MCDecodedPseudoProbeInlineTree() = default; |
||
278 | MCDecodedPseudoProbeInlineTree(const InlineSite &Site) : ISite(Site){}; |
||
279 | |||
280 | // Return false if it's a dummy inline site |
||
281 | bool hasInlineSite() const { return !isRoot() && !Parent->isRoot(); } |
||
282 | }; |
||
283 | |||
284 | /// Instances of this class represent the pseudo probes inserted into a compile |
||
285 | /// unit. |
||
286 | class MCPseudoProbeSections { |
||
287 | public: |
||
288 | void addPseudoProbe(MCSymbol *FuncSym, const MCPseudoProbe &Probe, |
||
289 | const MCPseudoProbeInlineStack &InlineStack) { |
||
290 | MCProbeDivisions[FuncSym].addPseudoProbe(Probe, InlineStack); |
||
291 | } |
||
292 | |||
293 | // TODO: Sort by getOrdinal to ensure a determinstic section order |
||
294 | using MCProbeDivisionMap = std::map<MCSymbol *, MCPseudoProbeInlineTree>; |
||
295 | |||
296 | private: |
||
297 | // A collection of MCPseudoProbe for each function. The MCPseudoProbes are |
||
298 | // grouped by GUIDs due to inlining that can bring probes from different |
||
299 | // functions into one function. |
||
300 | MCProbeDivisionMap MCProbeDivisions; |
||
301 | |||
302 | public: |
||
303 | const MCProbeDivisionMap &getMCProbes() const { return MCProbeDivisions; } |
||
304 | |||
305 | bool empty() const { return MCProbeDivisions.empty(); } |
||
306 | |||
307 | void emit(MCObjectStreamer *MCOS); |
||
308 | }; |
||
309 | |||
310 | class MCPseudoProbeTable { |
||
311 | // A collection of MCPseudoProbe in the current module grouped by |
||
312 | // functions. MCPseudoProbes will be encoded into a corresponding |
||
313 | // .pseudoprobe section. With functions emitted as separate comdats, |
||
314 | // a text section really only contains the code of a function solely, and the |
||
315 | // probes associated with the text section will be emitted into a standalone |
||
316 | // .pseudoprobe section that shares the same comdat group with the function. |
||
317 | MCPseudoProbeSections MCProbeSections; |
||
318 | |||
319 | public: |
||
320 | static void emit(MCObjectStreamer *MCOS); |
||
321 | |||
322 | MCPseudoProbeSections &getProbeSections() { return MCProbeSections; } |
||
323 | |||
324 | #ifndef NDEBUG |
||
325 | static int DdgPrintIndent; |
||
326 | #endif |
||
327 | }; |
||
328 | |||
329 | class MCPseudoProbeDecoder { |
||
330 | // GUID to PseudoProbeFuncDesc map. |
||
331 | GUIDProbeFunctionMap GUID2FuncDescMap; |
||
332 | |||
333 | // Address to probes map. |
||
334 | AddressProbesMap Address2ProbesMap; |
||
335 | |||
336 | // The dummy root of the inline trie, all the outlined function will directly |
||
337 | // be the children of the dummy root, all the inlined function will be the |
||
338 | // children of its inlineer. So the relation would be like: |
||
339 | // DummyRoot --> OutlinedFunc --> InlinedFunc1 --> InlinedFunc2 |
||
340 | MCDecodedPseudoProbeInlineTree DummyInlineRoot; |
||
341 | |||
342 | /// Points to the current location in the buffer. |
||
343 | const uint8_t *Data = nullptr; |
||
344 | |||
345 | /// Points to the end of the buffer. |
||
346 | const uint8_t *End = nullptr; |
||
347 | |||
348 | /// Whether encoding is based on a starting probe with absolute code address. |
||
349 | bool EncodingIsAddrBased = false; |
||
350 | |||
351 | // Decoding helper function |
||
352 | template <typename T> ErrorOr<T> readUnencodedNumber(); |
||
353 | template <typename T> ErrorOr<T> readUnsignedNumber(); |
||
354 | template <typename T> ErrorOr<T> readSignedNumber(); |
||
355 | ErrorOr<StringRef> readString(uint32_t Size); |
||
356 | |||
357 | public: |
||
358 | using Uint64Set = DenseSet<uint64_t>; |
||
359 | using Uint64Map = DenseMap<uint64_t, uint64_t>; |
||
360 | |||
361 | // Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map. |
||
362 | bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size); |
||
363 | |||
364 | // Decode pseudo_probe section to build address to probes map for specifed |
||
365 | // functions only. |
||
366 | bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size, |
||
367 | const Uint64Set &GuildFilter, |
||
368 | const Uint64Map &FuncStartAddrs); |
||
369 | |||
370 | bool buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree *Cur, |
||
371 | uint64_t &LastAddr, const Uint64Set &GuildFilter, |
||
372 | const Uint64Map &FuncStartAddrs); |
||
373 | |||
374 | // Print pseudo_probe_desc section info |
||
375 | void printGUID2FuncDescMap(raw_ostream &OS); |
||
376 | |||
377 | // Print pseudo_probe section info, used along with show-disassembly |
||
378 | void printProbeForAddress(raw_ostream &OS, uint64_t Address); |
||
379 | |||
380 | // do printProbeForAddress for all addresses |
||
381 | void printProbesForAllAddresses(raw_ostream &OS); |
||
382 | |||
383 | // Look up the probe of a call for the input address |
||
384 | const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const; |
||
385 | |||
386 | const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const; |
||
387 | |||
388 | // Helper function to populate one probe's inline stack into |
||
389 | // \p InlineContextStack. |
||
390 | // Current leaf location info will be added if IncludeLeaf is true |
||
391 | // Example: |
||
392 | // Current probe(bar:3) inlined at foo:2 then inlined at main:1 |
||
393 | // IncludeLeaf = true, Output: [main:1, foo:2, bar:3] |
||
394 | // IncludeLeaf = false, Output: [main:1, foo:2] |
||
395 | void getInlineContextForProbe( |
||
396 | const MCDecodedPseudoProbe *Probe, |
||
397 | SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack, |
||
398 | bool IncludeLeaf) const; |
||
399 | |||
400 | const AddressProbesMap &getAddress2ProbesMap() const { |
||
401 | return Address2ProbesMap; |
||
402 | } |
||
403 | |||
404 | AddressProbesMap &getAddress2ProbesMap() { return Address2ProbesMap; } |
||
405 | |||
406 | const GUIDProbeFunctionMap &getGUID2FuncDescMap() const { |
||
407 | return GUID2FuncDescMap; |
||
408 | } |
||
409 | |||
410 | const MCPseudoProbeFuncDesc * |
||
411 | getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) const; |
||
412 | |||
413 | const MCDecodedPseudoProbeInlineTree &getDummyInlineRoot() const { |
||
414 | return DummyInlineRoot; |
||
415 | } |
||
416 | }; |
||
417 | |||
418 | } // end namespace llvm |
||
419 | |||
420 | #endif // LLVM_MC_MCPSEUDOPROBE_H |