#ifndef LLVM_MC_MCPSEUDOPROBE_H
#define LLVM_MC_MCPSEUDOPROBE_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/PseudoProbe.h"
#include "llvm/Support/ErrorOr.h"
#include <list>
#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace llvm {
class MCSection;
class MCSymbol;
class MCObjectStreamer;
class raw_ostream;
enum class MCPseudoProbeFlag {
AddressDelta = 0x1,
};
struct MCPseudoProbeFuncDesc {
uint64_t FuncGUID = 0;
uint64_t FuncHash = 0;
std::string FuncName;
MCPseudoProbeFuncDesc(uint64_t GUID, uint64_t Hash, StringRef Name)
: FuncGUID(GUID), FuncHash(Hash), FuncName(Name){};
void print(raw_ostream &OS);
};
class MCDecodedPseudoProbe;
using InlineSite = std::tuple<uint64_t, uint32_t>;
using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>;
using GUIDProbeFunctionMap =
std::unordered_map<uint64_t, MCPseudoProbeFuncDesc>;
using AddressProbesMap =
std::unordered_map<uint64_t, std::list<MCDecodedPseudoProbe>>;
class MCDecodedPseudoProbeInlineTree;
class MCPseudoProbeBase {
protected:
uint64_t Guid;
uint64_t Index;
uint8_t Attributes;
uint8_t Type;
const static uint32_t PseudoProbeFirstId = 1;
public:
MCPseudoProbeBase(uint64_t G, uint64_t I, uint64_t At, uint8_t T)
: Guid(G), Index(I), Attributes(At), Type(T) {}
bool isEntry() const { return Index == PseudoProbeFirstId; }
uint64_t getGuid() const { return Guid; }
uint64_t getIndex() const { return Index; }
uint8_t getAttributes() const { return Attributes; }
uint8_t getType() const { return Type; }
bool isBlock() const {
return Type == static_cast<uint8_t>(PseudoProbeType::Block);
}
bool isIndirectCall() const {
return Type == static_cast<uint8_t>(PseudoProbeType::IndirectCall);
}
bool isDirectCall() const {
return Type == static_cast<uint8_t>(PseudoProbeType::DirectCall);
}
bool isCall() const { return isIndirectCall() || isDirectCall(); }
void setAttributes(uint8_t Attr) { Attributes = Attr; }
};
class MCPseudoProbe : public MCPseudoProbeBase {
MCSymbol *Label;
public:
MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type,
uint64_t Attributes)
: MCPseudoProbeBase(Guid, Index, Attributes, Type), Label(Label) {
assert(Type <= 0xFF && "Probe type too big to encode, exceeding 2^8");
assert(Attributes <= 0xFF &&
"Probe attributes too big to encode, exceeding 2^16");
}
MCSymbol *getLabel() const { return Label; }
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const;
};
using MCPseduoProbeFrameLocation = std::pair<StringRef, uint32_t>;
class MCDecodedPseudoProbe : public MCPseudoProbeBase {
uint64_t Address;
MCDecodedPseudoProbeInlineTree *InlineTree;
public:
MCDecodedPseudoProbe(uint64_t Ad, uint64_t G, uint32_t I, PseudoProbeType K,
uint8_t At, MCDecodedPseudoProbeInlineTree *Tree)
: MCPseudoProbeBase(G, I, At, static_cast<uint8_t>(K)), Address(Ad),
InlineTree(Tree){};
uint64_t getAddress() const { return Address; }
void setAddress(uint64_t Addr) { Address = Addr; }
MCDecodedPseudoProbeInlineTree *getInlineTreeNode() const {
return InlineTree;
}
void
getInlineContext(SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
const GUIDProbeFunctionMap &GUID2FuncMAP) const;
std::string
getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP) const;
void print(raw_ostream &OS, const GUIDProbeFunctionMap &GUID2FuncMAP,
bool ShowName) const;
};
template <typename ProbeType, typename DerivedProbeInlineTreeType>
class MCPseudoProbeInlineTreeBase {
struct InlineSiteHash {
uint64_t operator()(const InlineSite &Site) const {
return std::get<0>(Site) ^ std::get<1>(Site);
}
};
protected:
using InlinedProbeTreeMap = std::unordered_map<
InlineSite, std::unique_ptr<DerivedProbeInlineTreeType>, InlineSiteHash>;
InlinedProbeTreeMap Children;
std::vector<ProbeType> Probes;
MCPseudoProbeInlineTreeBase() {
static_assert(std::is_base_of<MCPseudoProbeInlineTreeBase,
DerivedProbeInlineTreeType>::value,
"DerivedProbeInlineTreeType must be subclass of "
"MCPseudoProbeInlineTreeBase");
}
public:
uint64_t Guid = 0;
bool isRoot() const { return Guid == 0; }
InlinedProbeTreeMap &getChildren() { return Children; }
const InlinedProbeTreeMap &getChildren() const { return Children; }
std::vector<ProbeType> &getProbes() { return Probes; }
void addProbes(ProbeType Probe) { Probes.push_back(Probe); }
MCPseudoProbeInlineTreeBase<ProbeType, DerivedProbeInlineTreeType> *Parent;
DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) {
auto Ret = Children.emplace(
Site, std::make_unique<DerivedProbeInlineTreeType>(Site));
Ret.first->second->Parent = this;
return Ret.first->second.get();
};
};
class MCPseudoProbeInlineTree
: public MCPseudoProbeInlineTreeBase<MCPseudoProbe,
MCPseudoProbeInlineTree> {
public:
MCPseudoProbeInlineTree() = default;
MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; }
MCPseudoProbeInlineTree(const InlineSite &Site) {
this->Guid = std::get<0>(Site);
}
void addPseudoProbe(const MCPseudoProbe &Probe,
const MCPseudoProbeInlineStack &InlineStack);
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe);
};
class MCDecodedPseudoProbeInlineTree
: public MCPseudoProbeInlineTreeBase<MCDecodedPseudoProbe *,
MCDecodedPseudoProbeInlineTree> {
public:
InlineSite ISite;
uint32_t ChildrenToProcess = 0;
MCDecodedPseudoProbeInlineTree() = default;
MCDecodedPseudoProbeInlineTree(const InlineSite &Site) : ISite(Site){};
bool hasInlineSite() const { return !isRoot() && !Parent->isRoot(); }
};
class MCPseudoProbeSection {
public:
void addPseudoProbe(MCSection *Sec, const MCPseudoProbe &Probe,
const MCPseudoProbeInlineStack &InlineStack) {
MCProbeDivisions[Sec].addPseudoProbe(Probe, InlineStack);
}
using MCProbeDivisionMap = std::map<MCSection *, MCPseudoProbeInlineTree>;
private:
MCProbeDivisionMap MCProbeDivisions;
public:
const MCProbeDivisionMap &getMCProbes() const { return MCProbeDivisions; }
bool empty() const { return MCProbeDivisions.empty(); }
void emit(MCObjectStreamer *MCOS);
};
class MCPseudoProbeTable {
MCPseudoProbeSection MCProbeSections;
public:
static void emit(MCObjectStreamer *MCOS);
MCPseudoProbeSection &getProbeSections() { return MCProbeSections; }
#ifndef NDEBUG
static int DdgPrintIndent;
#endif
};
class MCPseudoProbeDecoder {
GUIDProbeFunctionMap GUID2FuncDescMap;
AddressProbesMap Address2ProbesMap;
MCDecodedPseudoProbeInlineTree DummyInlineRoot;
const uint8_t *Data = nullptr;
const uint8_t *End = nullptr;
template <typename T> ErrorOr<T> readUnencodedNumber();
template <typename T> ErrorOr<T> readUnsignedNumber();
template <typename T> ErrorOr<T> readSignedNumber();
ErrorOr<StringRef> readString(uint32_t Size);
public:
bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size);
bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size);
bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size,
std::unordered_set<uint64_t> &GuildFilter);
bool buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree *Cur,
uint64_t &LastAddr,
std::unordered_set<uint64_t> &GuildFilter);
void printGUID2FuncDescMap(raw_ostream &OS);
void printProbeForAddress(raw_ostream &OS, uint64_t Address);
void printProbesForAllAddresses(raw_ostream &OS);
const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const;
const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const;
void getInlineContextForProbe(
const MCDecodedPseudoProbe *Probe,
SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
bool IncludeLeaf) const;
const AddressProbesMap &getAddress2ProbesMap() const {
return Address2ProbesMap;
}
AddressProbesMap &getAddress2ProbesMap() { return Address2ProbesMap; }
const GUIDProbeFunctionMap &getGUID2FuncDescMap() const {
return GUID2FuncDescMap;
}
const MCPseudoProbeFuncDesc *
getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) const;
const MCDecodedPseudoProbeInlineTree &getDummyInlineRoot() const {
return DummyInlineRoot;
}
};
}
#endif