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