85 lines
3.5 KiB
C++
85 lines
3.5 KiB
C++
|
//===- llvm/CodeGen/PseudoProbePrinter.cpp - Pseudo Probe Emission -------===//
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// This file contains support for writing pseudo probe info into asm files.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "PseudoProbePrinter.h"
|
||
|
#include "llvm/CodeGen/AsmPrinter.h"
|
||
|
#include "llvm/IR/DebugInfoMetadata.h"
|
||
|
#include "llvm/IR/Module.h"
|
||
|
#include "llvm/IR/PseudoProbe.h"
|
||
|
#include "llvm/MC/MCPseudoProbe.h"
|
||
|
#include "llvm/MC/MCStreamer.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
#define DEBUG_TYPE "pseudoprobe"
|
||
|
|
||
|
PseudoProbeHandler::~PseudoProbeHandler() = default;
|
||
|
|
||
|
PseudoProbeHandler::PseudoProbeHandler(AsmPrinter *A, Module *M) : Asm(A) {
|
||
|
NamedMDNode *FuncInfo = M->getNamedMetadata(PseudoProbeDescMetadataName);
|
||
|
assert(FuncInfo && "Pseudo probe descriptors are missing");
|
||
|
for (const auto *Operand : FuncInfo->operands()) {
|
||
|
const auto *MD = cast<MDNode>(Operand);
|
||
|
auto GUID =
|
||
|
mdconst::dyn_extract<ConstantInt>(MD->getOperand(0))->getZExtValue();
|
||
|
auto Name = cast<MDString>(MD->getOperand(2))->getString();
|
||
|
// We may see pairs with same name but different GUIDs here in LTO mode, due
|
||
|
// to static same-named functions inlined from other modules into this
|
||
|
// module. Function profiles with the same name will be merged no matter
|
||
|
// whether they are collected on the same function. Therefore we just pick
|
||
|
// up the last <Name, GUID> pair here to represent the same-named function
|
||
|
// collection and all probes from the collection will be merged into a
|
||
|
// single profile eventually.
|
||
|
Names[Name] = GUID;
|
||
|
}
|
||
|
|
||
|
LLVM_DEBUG(dump());
|
||
|
}
|
||
|
|
||
|
void PseudoProbeHandler::emitPseudoProbe(uint64_t Guid, uint64_t Index,
|
||
|
uint64_t Type, uint64_t Attr,
|
||
|
const DILocation *DebugLoc) {
|
||
|
// Gather all the inlined-at nodes.
|
||
|
// When it's done ReversedInlineStack looks like ([66, B], [88, A])
|
||
|
// which means, Function A inlines function B at calliste with a probe id 88,
|
||
|
// and B inlines C at probe 66 where C is represented by Guid.
|
||
|
SmallVector<InlineSite, 8> ReversedInlineStack;
|
||
|
auto *InlinedAt = DebugLoc ? DebugLoc->getInlinedAt() : nullptr;
|
||
|
while (InlinedAt) {
|
||
|
const DISubprogram *SP = InlinedAt->getScope()->getSubprogram();
|
||
|
// Use linkage name for C++ if possible.
|
||
|
auto Name = SP->getLinkageName();
|
||
|
if (Name.empty())
|
||
|
Name = SP->getName();
|
||
|
assert(Names.count(Name) && "Pseudo probe descriptor missing for function");
|
||
|
uint64_t CallerGuid = Names[Name];
|
||
|
uint64_t CallerProbeId = PseudoProbeDwarfDiscriminator::extractProbeIndex(
|
||
|
InlinedAt->getDiscriminator());
|
||
|
ReversedInlineStack.emplace_back(CallerGuid, CallerProbeId);
|
||
|
InlinedAt = InlinedAt->getInlinedAt();
|
||
|
}
|
||
|
|
||
|
SmallVector<InlineSite, 8> InlineStack(ReversedInlineStack.rbegin(),
|
||
|
ReversedInlineStack.rend());
|
||
|
Asm->OutStreamer->emitPseudoProbe(Guid, Index, Type, Attr, InlineStack);
|
||
|
}
|
||
|
|
||
|
#ifndef NDEBUG
|
||
|
void PseudoProbeHandler::dump() const {
|
||
|
dbgs() << "\n=============================\n";
|
||
|
dbgs() << "\nFunction Name to GUID map:\n";
|
||
|
dbgs() << "\n=============================\n";
|
||
|
for (const auto &Item : Names)
|
||
|
dbgs() << "Func: " << Item.first << " GUID: " << Item.second << "\n";
|
||
|
}
|
||
|
#endif
|