1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
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 #include "llvm/MC/MCPseudoProbe.h"
10 #include "llvm/MC/MCAsmInfo.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCObjectFileInfo.h"
13 #include "llvm/MC/MCObjectStreamer.h"
14 #include "llvm/MC/MCStreamer.h"
15
16 #define DEBUG_TYPE "mcpseudoprobe"
17
18 using namespace llvm;
19
20 #ifndef NDEBUG
21 int MCPseudoProbeTable::DdgPrintIndent = 0;
22 #endif
23
buildSymbolDiff(MCObjectStreamer * MCOS,const MCSymbol * A,const MCSymbol * B)24 static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
25 const MCSymbol *B) {
26 MCContext &Context = MCOS->getContext();
27 MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
28 const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
29 const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
30 const MCExpr *AddrDelta =
31 MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
32 return AddrDelta;
33 }
34
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * LastProbe) const35 void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
36 const MCPseudoProbe *LastProbe) const {
37 // Emit Index
38 MCOS->emitULEB128IntValue(Index);
39 // Emit Type and the flag:
40 // Type (bit 0 to 3), with bit 4 to 6 for attributes.
41 // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
42 // the following field is a symbolic code address or an address delta.
43 assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
44 assert(Attributes <= 0x7 &&
45 "Probe attributes too big to encode, exceeding 7");
46 uint8_t PackedType = Type | (Attributes << 4);
47 uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
48 MCOS->emitInt8(Flag | PackedType);
49
50 if (LastProbe) {
51 // Emit the delta between the address label and LastProbe.
52 const MCExpr *AddrDelta =
53 buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
54 int64_t Delta;
55 if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
56 MCOS->emitSLEB128IntValue(Delta);
57 } else {
58 MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
59 }
60 } else {
61 // Emit label as a symbolic code address.
62 MCOS->emitSymbolValue(
63 Label, MCOS->getContext().getAsmInfo()->getCodePointerSize());
64 }
65
66 LLVM_DEBUG({
67 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
68 dbgs() << "Probe: " << Index << "\n";
69 });
70 }
71
~MCPseudoProbeInlineTree()72 MCPseudoProbeInlineTree::~MCPseudoProbeInlineTree() {
73 for (auto &Inlinee : Inlinees)
74 delete Inlinee.second;
75 }
76
77 MCPseudoProbeInlineTree *
getOrAddNode(InlineSite Site)78 MCPseudoProbeInlineTree::getOrAddNode(InlineSite Site) {
79 auto Iter = Inlinees.find(Site);
80 if (Iter == Inlinees.end()) {
81 auto *Node = new MCPseudoProbeInlineTree(std::get<0>(Site));
82 Inlinees[Site] = Node;
83 return Node;
84 } else {
85 return Iter->second;
86 }
87 }
88
addPseudoProbe(const MCPseudoProbe & Probe,const MCPseudoProbeInlineStack & InlineStack)89 void MCPseudoProbeInlineTree::addPseudoProbe(
90 const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
91 // The function should not be called on the root.
92 assert(isRoot() && "Should not be called on root");
93
94 // When it comes here, the input look like:
95 // Probe: GUID of C, ...
96 // InlineStack: [88, A], [66, B]
97 // which means, Function A inlines function B at call site with a probe id of
98 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
99 // A], [88, B], [66, C]} to locate the tree node where the probe should be
100 // added. Note that the edge [0, A] means A is the top-level function we are
101 // emitting probes for.
102
103 // Make a [0, A] edge.
104 // An empty inline stack means the function that the probe originates from
105 // is a top-level function.
106 InlineSite Top;
107 if (InlineStack.empty()) {
108 Top = InlineSite(Probe.getGuid(), 0);
109 } else {
110 Top = InlineSite(std::get<0>(InlineStack.front()), 0);
111 }
112
113 auto *Cur = getOrAddNode(Top);
114
115 // Make interior edges by walking the inline stack. Once it's done, Cur should
116 // point to the node that the probe originates from.
117 if (!InlineStack.empty()) {
118 auto Iter = InlineStack.begin();
119 auto Index = std::get<1>(*Iter);
120 Iter++;
121 for (; Iter != InlineStack.end(); Iter++) {
122 // Make an edge by using the previous probe id and current GUID.
123 Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
124 Index = std::get<1>(*Iter);
125 }
126 Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
127 }
128
129 Cur->Probes.push_back(Probe);
130 }
131
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * & LastProbe)132 void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
133 const MCPseudoProbe *&LastProbe) {
134 LLVM_DEBUG({
135 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
136 dbgs() << "Group [\n";
137 MCPseudoProbeTable::DdgPrintIndent += 2;
138 });
139 // Emit probes grouped by GUID.
140 if (Guid != 0) {
141 LLVM_DEBUG({
142 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
143 dbgs() << "GUID: " << Guid << "\n";
144 });
145 // Emit Guid
146 MCOS->emitInt64(Guid);
147 // Emit number of probes in this node
148 MCOS->emitULEB128IntValue(Probes.size());
149 // Emit number of direct inlinees
150 MCOS->emitULEB128IntValue(Inlinees.size());
151 // Emit probes in this group
152 for (const auto &Probe : Probes) {
153 Probe.emit(MCOS, LastProbe);
154 LastProbe = &Probe;
155 }
156 } else {
157 assert(Probes.empty() && "Root should not have probes");
158 }
159
160 // Emit descendent
161 for (const auto &Inlinee : Inlinees) {
162 if (Guid) {
163 // Emit probe index
164 MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
165 LLVM_DEBUG({
166 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
167 dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
168 });
169 }
170 // Emit the group
171 Inlinee.second->emit(MCOS, LastProbe);
172 }
173
174 LLVM_DEBUG({
175 MCPseudoProbeTable::DdgPrintIndent -= 2;
176 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
177 dbgs() << "]\n";
178 });
179 }
180
emit(MCObjectStreamer * MCOS)181 void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) {
182 MCContext &Ctx = MCOS->getContext();
183
184 for (auto &ProbeSec : MCProbeDivisions) {
185 const MCPseudoProbe *LastProbe = nullptr;
186 if (auto *S =
187 Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) {
188 // Switch to the .pseudoprobe section or a comdat group.
189 MCOS->SwitchSection(S);
190 // Emit probes grouped by GUID.
191 ProbeSec.second.emit(MCOS, LastProbe);
192 }
193 }
194 }
195
196 //
197 // This emits the pseudo probe tables.
198 //
emit(MCObjectStreamer * MCOS)199 void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
200 MCContext &Ctx = MCOS->getContext();
201 auto &ProbeTable = Ctx.getMCPseudoProbeTable();
202
203 // Bail out early so we don't switch to the pseudo_probe section needlessly
204 // and in doing so create an unnecessary (if empty) section.
205 auto &ProbeSections = ProbeTable.getProbeSections();
206 if (ProbeSections.empty())
207 return;
208
209 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
210
211 // Put out the probe.
212 ProbeSections.emit(MCOS);
213 }
214