mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
29e34b908b
Report dangling probes for frames that have real samples collected. Dangling probes are the probes associated to an empty block. When reported, sample count on a dangling probe will not be trusted by the compiler and we will rely on the counts inference algorithm to get the probe a reasonable count. This actually fixes a bug where previously only those dangling probes with samples collected were reported. This patch also fixes two existing issues. Pseudo probes are stored in `Address2ProbesMap` and their pointers are used in `PseudoProbeInlineTree`. Previously `std::vector` was used to store probes and the pointers to probes may get obsolete as the vector grows. I'm changing `std::vector` to `std::list` instead. The other issue is that all outlined functions shared the same inline frame previously due to the unchanged `Index` value as the dummy inlineSite identifier. Good results seen for SPEC2017 in general regarding profile quality. Reviewed By: wenlei, wlei Differential Revision: https://reviews.llvm.org/D100235
178 lines
6.5 KiB
C++
178 lines
6.5 KiB
C++
//===- MCPseudoProbe.h - Pseudo probe encoding support ---------*- C++ -*-===//
|
|
//
|
|
// 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 the declaration of the MCPseudoProbe to support the pseudo
|
|
// probe encoding for AutoFDO. Pseudo probes together with their inline context
|
|
// are encoded in a DFS recursive way in the .pseudoprobe sections. For each
|
|
// .pseudoprobe section, the encoded binary data consist of a single or mutiple
|
|
// function records each for one outlined function. A function record has the
|
|
// following format :
|
|
//
|
|
// FUNCTION BODY (one for each outlined function present in the text section)
|
|
// GUID (uint64)
|
|
// GUID of the function
|
|
// NPROBES (ULEB128)
|
|
// Number of probes originating from this function.
|
|
// NUM_INLINED_FUNCTIONS (ULEB128)
|
|
// Number of callees inlined into this function, aka number of
|
|
// first-level inlinees
|
|
// PROBE RECORDS
|
|
// A list of NPROBES entries. Each entry contains:
|
|
// INDEX (ULEB128)
|
|
// TYPE (uint4)
|
|
// 0 - block probe, 1 - indirect call, 2 - direct call
|
|
// ATTRIBUTE (uint3)
|
|
// 1 - reserved, 2 - dangling
|
|
// ADDRESS_TYPE (uint1)
|
|
// 0 - code address, 1 - address delta
|
|
// CODE_ADDRESS (uint64 or ULEB128)
|
|
// code address or address delta, depending on ADDRESS_TYPE
|
|
// INLINED FUNCTION RECORDS
|
|
// A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined
|
|
// callees. Each record contains:
|
|
// INLINE SITE
|
|
// ID of the callsite probe (ULEB128)
|
|
// FUNCTION BODY
|
|
// A FUNCTION BODY entry describing the inlined function.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_MC_MCPSEUDOPROBE_H
|
|
#define LLVM_MC_MCPSEUDOPROBE_H
|
|
|
|
#include "llvm/ADT/MapVector.h"
|
|
#include "llvm/MC/MCSection.h"
|
|
#include <functional>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
|
|
class MCStreamer;
|
|
class MCSymbol;
|
|
class MCObjectStreamer;
|
|
|
|
enum class MCPseudoProbeFlag {
|
|
// If set, indicates that the probe is encoded as an address delta
|
|
// instead of a real code address.
|
|
AddressDelta = 0x1,
|
|
};
|
|
|
|
/// Instances of this class represent a pseudo probe instance for a pseudo probe
|
|
/// table entry, which is created during a machine instruction is assembled and
|
|
/// uses an address from a temporary label created at the current address in the
|
|
/// current section.
|
|
class MCPseudoProbe {
|
|
MCSymbol *Label;
|
|
uint64_t Guid;
|
|
uint64_t Index;
|
|
uint8_t Type;
|
|
uint8_t Attributes;
|
|
|
|
public:
|
|
MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type,
|
|
uint64_t Attributes)
|
|
: Label(Label), Guid(Guid), Index(Index), Type(Type),
|
|
Attributes(Attributes) {
|
|
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; }
|
|
|
|
uint64_t getGuid() const { return Guid; }
|
|
|
|
uint64_t getIndex() const { return Index; }
|
|
|
|
uint8_t getType() const { return Type; }
|
|
|
|
uint8_t getAttributes() const { return Attributes; }
|
|
|
|
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const;
|
|
};
|
|
|
|
// An inline frame has the form <Guid, ProbeID>
|
|
using InlineSite = std::tuple<uint64_t, uint32_t>;
|
|
using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>;
|
|
|
|
// A Tri-tree based data structure to group probes by inline stack.
|
|
// A tree is allocated for a standalone .text section. A fake
|
|
// instance is created as the root of a tree.
|
|
// A real instance of this class is created for each function, either an
|
|
// unlined function that has code in .text section or an inlined function.
|
|
class MCPseudoProbeInlineTree {
|
|
uint64_t Guid;
|
|
// Set of probes that come with the function.
|
|
std::vector<MCPseudoProbe> Probes;
|
|
// Use std::map for a deterministic output.
|
|
std::map<InlineSite, MCPseudoProbeInlineTree *> Inlinees;
|
|
|
|
// Root node has a GUID 0.
|
|
bool isRoot() { return Guid == 0; }
|
|
MCPseudoProbeInlineTree *getOrAddNode(InlineSite Site);
|
|
|
|
public:
|
|
MCPseudoProbeInlineTree() = default;
|
|
MCPseudoProbeInlineTree(uint64_t Guid) : Guid(Guid) {}
|
|
~MCPseudoProbeInlineTree();
|
|
void addPseudoProbe(const MCPseudoProbe &Probe,
|
|
const MCPseudoProbeInlineStack &InlineStack);
|
|
void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe);
|
|
};
|
|
|
|
/// Instances of this class represent the pseudo probes inserted into a compile
|
|
/// unit.
|
|
class MCPseudoProbeSection {
|
|
public:
|
|
void addPseudoProbe(MCSection *Sec, const MCPseudoProbe &Probe,
|
|
const MCPseudoProbeInlineStack &InlineStack) {
|
|
MCProbeDivisions[Sec].addPseudoProbe(Probe, InlineStack);
|
|
}
|
|
|
|
// TODO: Sort by getOrdinal to ensure a determinstic section order
|
|
using MCProbeDivisionMap = std::map<MCSection *, MCPseudoProbeInlineTree>;
|
|
|
|
private:
|
|
// A collection of MCPseudoProbe for each text section. The MCPseudoProbes
|
|
// are grouped by GUID of the functions where they are from and will be
|
|
// encoded by groups. In the comdat scenario where a text section really only
|
|
// contains the code of a function solely, the probes associated with a comdat
|
|
// function are still grouped by GUIDs due to inlining that can bring probes
|
|
// from different functions into one function.
|
|
MCProbeDivisionMap MCProbeDivisions;
|
|
|
|
public:
|
|
const MCProbeDivisionMap &getMCProbes() const { return MCProbeDivisions; }
|
|
|
|
bool empty() const { return MCProbeDivisions.empty(); }
|
|
|
|
void emit(MCObjectStreamer *MCOS);
|
|
};
|
|
|
|
class MCPseudoProbeTable {
|
|
// A collection of MCPseudoProbe in the current module grouped by text
|
|
// sections. MCPseudoProbes will be encoded into a corresponding
|
|
// .pseudoprobe section. With functions emitted as separate comdats,
|
|
// a text section really only contains the code of a function solely, and the
|
|
// probes associated with the text section will be emitted into a standalone
|
|
// .pseudoprobe section that shares the same comdat group with the function.
|
|
MCPseudoProbeSection MCProbeSections;
|
|
|
|
public:
|
|
static void emit(MCObjectStreamer *MCOS);
|
|
|
|
MCPseudoProbeSection &getProbeSections() { return MCProbeSections; }
|
|
|
|
#ifndef NDEBUG
|
|
static int DdgPrintIndent;
|
|
#endif
|
|
};
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_MC_MCPSEUDOPROBE_H
|