blob: 8e991d1f78ff280b74fbb1e791a9a30b6d253663 [file] [log] [blame]
//===- bolt/Passes/InstrumentationSummary.h ---------------------*- 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
//
//===----------------------------------------------------------------------===//
//
// InstrumentationSummary holds all the data generated during
// the Instrumentation pass, which will be needed latter for runtime library
// binary emit and linking.
//
//===----------------------------------------------------------------------===//
#ifndef BOLT_PASSES_INSTRUMENTATION_SUMMARY_H
#define BOLT_PASSES_INSTRUMENTATION_SUMMARY_H
#include "llvm/ADT/DenseSet.h"
#include <string>
#include <vector>
namespace llvm {
class MCSymbol;
namespace bolt {
class BinaryFunction;
// All structs here are part of the program metadata serialization format and
// consist of POD types or array of POD types that are trivially mapped from
// disk to memory. This provides the runtime library with a basic
// understanding of the program structure, so it can build a CFG for each
// function and deduce execution counts for edges that don't require explicit
// counters. It also provides function names and offsets used when writing the
// fdata file.
// Location information -- analoguous to the concept of the same name in fdata
// writing/reading. The difference is that the name is stored as an index to a
// string table written separately.
struct LocDescription {
uint32_t FuncString;
uint32_t Offset;
};
// Inter-function control flow transfer instrumentation
struct CallDescription {
LocDescription FromLoc;
uint32_t FromNode; // Node refers to the CFG node index of the call site
LocDescription ToLoc;
uint32_t Counter;
const BinaryFunction *Target;
};
// Spans multiple counters during runtime - this is an indirect call site
struct IndCallDescription {
LocDescription FromLoc;
};
// This is an indirect call target (any entry point from any function). This
// is stored sorted in the binary for fast lookups during data writing.
struct IndCallTargetDescription {
LocDescription ToLoc;
const BinaryFunction *Target;
};
// Intra-function control flow transfer instrumentation
struct EdgeDescription {
LocDescription FromLoc;
uint32_t FromNode;
LocDescription ToLoc;
uint32_t ToNode;
uint32_t Counter;
};
// Basic block frequency (CFG node) instrumentation - only used for spanning
// tree leaf nodes.
struct InstrumentedNode {
uint32_t Node;
uint32_t Counter;
};
// Entry basic blocks for a function. We record their output addresses to
// check frequency of this address (via node number) against all tracked calls
// to this address and discover traffic coming from uninstrumented code.
struct EntryNode {
uint64_t Node;
uint64_t Address;
};
// Base struct organizing all metadata pertaining to a single function
struct FunctionDescription {
const BinaryFunction *Function;
std::vector<InstrumentedNode> LeafNodes;
std::vector<EdgeDescription> Edges;
DenseSet<std::pair<uint32_t, uint32_t>> EdgesSet;
std::vector<CallDescription> Calls;
std::vector<EntryNode> EntryNodes;
};
/// Holds the summary of the data generated by the Instrumentation Pass.
/// These information will be needed for binary emit.
struct InstrumentationSummary {
/// Identify all counters used in runtime while instrumentation is running
std::vector<MCSymbol *> Counters;
/// Stores function names, to be emitted to the runtime
std::string StringTable;
/// Pointer to runtime instrumentation handlers
MCSymbol *IndCallCounterFuncPtr;
MCSymbol *IndTailCallCounterFuncPtr;
/// Intra-function control flow and direct calls
std::vector<FunctionDescription> FunctionDescriptions;
/// Inter-function control flow via indirect calls
std::vector<IndCallDescription> IndCallDescriptions;
std::vector<IndCallTargetDescription> IndCallTargetDescriptions;
static constexpr uint64_t NUM_SERIALIZED_CONTAINERS = 4;
static constexpr uint64_t SERIALIZED_CONTAINER_SIZE =
sizeof(uint32_t) * NUM_SERIALIZED_CONTAINERS;
uint32_t getFDSize() const {
uint32_t FuncDescSize = 0;
for (const FunctionDescription &Func : FunctionDescriptions) {
// A function description consists of containers of different
// descriptions. We use vectors to store them and when serializing them,
// we first output a uint32_t-sized field for the number of elements of
// the vector and then we write each element, so a simple parser know
// where to stop.
FuncDescSize += SERIALIZED_CONTAINER_SIZE +
Func.Edges.size() * sizeof(EdgeDescription) +
Func.LeafNodes.size() * sizeof(InstrumentedNode) +
Func.Calls.size() * sizeof(CallDescription) +
Func.EntryNodes.size() * sizeof(EntryNode);
}
return FuncDescSize;
}
};
} // namespace bolt
} // namespace llvm
#endif