214 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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);
 | |
| }
 |