| //===- 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); |
| } |