//===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/MC/MCPseudoProbe.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/MCStreamer.h" #define DEBUG_TYPE "mcpseudoprobe" using namespace llvm; #ifndef NDEBUG int MCPseudoProbeTable::DdgPrintIndent = 0; #endif static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A, const MCSymbol *B) { MCContext &Context = MCOS->getContext(); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context); const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context); const MCExpr *AddrDelta = MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context); return AddrDelta; } void MCPseudoProbe::emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const { // Emit Index MCOS->emitULEB128IntValue(Index); // Emit Type and the flag: // Type (bit 0 to 3), with bit 4 to 6 for attributes. // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether // the following field is a symbolic code address or an address delta. assert(Type <= 0xF && "Probe type too big to encode, exceeding 15"); assert(Attributes <= 0x7 && "Probe attributes too big to encode, exceeding 7"); uint8_t PackedType = Type | (Attributes << 4); uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0; MCOS->emitInt8(Flag | PackedType); if (LastProbe) { // Emit the delta between the address label and LastProbe. const MCExpr *AddrDelta = buildSymbolDiff(MCOS, Label, LastProbe->getLabel()); int64_t Delta; if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) { MCOS->emitSLEB128IntValue(Delta); } else { MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta)); } } else { // Emit label as a symbolic code address. MCOS->emitSymbolValue( Label, MCOS->getContext().getAsmInfo()->getCodePointerSize()); } LLVM_DEBUG({ dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "Probe: " << Index << "\n"; }); } MCPseudoProbeInlineTree::~MCPseudoProbeInlineTree() { for (auto &Inlinee : Inlinees) delete Inlinee.second; } MCPseudoProbeInlineTree * MCPseudoProbeInlineTree::getOrAddNode(InlineSite Site) { auto Iter = Inlinees.find(Site); if (Iter == Inlinees.end()) { auto *Node = new MCPseudoProbeInlineTree(std::get<0>(Site)); Inlinees[Site] = Node; return Node; } else { return Iter->second; } } void MCPseudoProbeInlineTree::addPseudoProbe( const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) { // The function should not be called on the root. assert(isRoot() && "Should not be called on root"); // When it comes here, the input look like: // Probe: GUID of C, ... // InlineStack: [88, A], [66, B] // which means, Function A inlines function B at call site with a probe id of // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0, // A], [88, B], [66, C]} to locate the tree node where the probe should be // added. Note that the edge [0, A] means A is the top-level function we are // emitting probes for. // Make a [0, A] edge. // An empty inline stack means the function that the probe originates from // is a top-level function. InlineSite Top; if (InlineStack.empty()) { Top = InlineSite(Probe.getGuid(), 0); } else { Top = InlineSite(std::get<0>(InlineStack.front()), 0); } auto *Cur = getOrAddNode(Top); // Make interior edges by walking the inline stack. Once it's done, Cur should // point to the node that the probe originates from. if (!InlineStack.empty()) { auto Iter = InlineStack.begin(); auto Index = std::get<1>(*Iter); Iter++; for (; Iter != InlineStack.end(); Iter++) { // Make an edge by using the previous probe id and current GUID. Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index)); Index = std::get<1>(*Iter); } Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index)); } Cur->Probes.push_back(Probe); } void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe) { LLVM_DEBUG({ dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent += 2; }); // Emit probes grouped by GUID. if (Guid != 0) { LLVM_DEBUG({ dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "GUID: " << Guid << "\n"; }); // Emit Guid MCOS->emitInt64(Guid); // Emit number of probes in this node MCOS->emitULEB128IntValue(Probes.size()); // Emit number of direct inlinees MCOS->emitULEB128IntValue(Inlinees.size()); // Emit probes in this group for (const auto &Probe : Probes) { Probe.emit(MCOS, LastProbe); LastProbe = &Probe; } } else { assert(Probes.empty() && "Root should not have probes"); } // Emit descendent for (const auto &Inlinee : Inlinees) { if (Guid) { // Emit probe index MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first)); LLVM_DEBUG({ dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n"; }); } // Emit the group Inlinee.second->emit(MCOS, LastProbe); } LLVM_DEBUG({ MCPseudoProbeTable::DdgPrintIndent -= 2; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "]\n"; }); } void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) { MCContext &Ctx = MCOS->getContext(); for (auto &ProbeSec : MCProbeDivisions) { const MCPseudoProbe *LastProbe = nullptr; if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) { // Switch to the .pseudoprobe section or a comdat group. MCOS->SwitchSection(S); // Emit probes grouped by GUID. ProbeSec.second.emit(MCOS, LastProbe); } } } // // This emits the pseudo probe tables. // void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) { MCContext &Ctx = MCOS->getContext(); auto &ProbeTable = Ctx.getMCPseudoProbeTable(); // Bail out early so we don't switch to the pseudo_probe section needlessly // and in doing so create an unnecessary (if empty) section. auto &ProbeSections = ProbeTable.getProbeSections(); if (ProbeSections.empty()) return; LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0); // Put out the probe. ProbeSections.emit(MCOS); }