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