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