blob: 2ee8db45cff3949b8bf5e5ec62b70f443d80e2af [file]
//===- bolt/Profile/YAMLProfileReader.h - YAML profile reader ---*- 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
//
//===----------------------------------------------------------------------===//
#ifndef BOLT_PROFILE_YAML_PROFILE_READER_H
#define BOLT_PROFILE_YAML_PROFILE_READER_H
#include "bolt/Profile/ProfileReaderBase.h"
#include "bolt/Profile/ProfileYAMLMapping.h"
#include <unordered_set>
namespace llvm {
class MCDecodedPseudoProbeInlineTree;
namespace bolt {
class YAMLProfileReader : public ProfileReaderBase {
public:
explicit YAMLProfileReader(StringRef Filename)
: ProfileReaderBase(Filename) {}
StringRef getReaderName() const override { return "YAML profile reader"; }
bool isTrustedSource() const override { return false; }
Error readProfilePreCFG(BinaryContext &BC) override {
return Error::success();
}
Error readProfile(BinaryContext &BC) override;
Error preprocessProfile(BinaryContext &BC) override;
bool hasLocalsWithFileName() const override;
bool mayHaveProfileData(const BinaryFunction &BF) override;
/// Check if the file contains YAML.
static bool isYAML(StringRef Filename);
using ProfileLookupMap =
DenseMap<uint32_t, yaml::bolt::BinaryFunctionProfile *>;
using GUIDInlineTreeMap =
std::unordered_map<uint64_t, const MCDecodedPseudoProbeInlineTree *>;
/// A class for matching binary functions in functions in the YAML profile.
/// First, a call graph is constructed for both profiled and binary functions.
/// Then functions are hashed based on the names of their callee/caller
/// functions. Finally, functions are matched based on these neighbor hashes.
class CallGraphMatcher {
public:
/// Constructs the call graphs for binary and profiled functions and
/// computes neighbor hashes for binary functions.
CallGraphMatcher(BinaryContext &BC, yaml::bolt::BinaryProfile &YamlBP,
ProfileLookupMap &IdToYAMLBF);
/// Returns the YamlBFs adjacent to the parameter YamlBF in the call graph.
std::optional<std::set<yaml::bolt::BinaryFunctionProfile *>>
getAdjacentYamlBFs(yaml::bolt::BinaryFunctionProfile &YamlBF) {
auto It = YamlBFAdjacencyMap.find(&YamlBF);
return It == YamlBFAdjacencyMap.end() ? std::nullopt
: std::make_optional(It->second);
}
/// Returns the binary functions with the parameter neighbor hash.
std::optional<BinaryFunctionListType>
getBFsWithNeighborHash(uint64_t NeighborHash) {
auto It = NeighborHashToBFs.find(NeighborHash);
return It == NeighborHashToBFs.end() ? std::nullopt
: std::make_optional(It->second);
}
private:
/// Adds edges to the binary function call graph given the callsites of the
/// parameter function.
void constructBFCG(BinaryContext &BC, yaml::bolt::BinaryProfile &YamlBP);
/// Using the constructed binary function call graph, computes and creates
/// mappings from "neighbor hash" (composed of the function names of callee
/// and caller functions of a function) to binary functions.
void computeBFNeighborHashes(BinaryContext &BC);
/// Constructs the call graph for profile functions.
void constructYAMLFCG(yaml::bolt::BinaryProfile &YamlBP,
ProfileLookupMap &IdToYAMLBF);
/// Adjacency map for binary functions in the call graph.
DenseMap<BinaryFunction *, std::set<BinaryFunction *>> BFAdjacencyMap;
/// Maps neighbor hashes to binary functions.
DenseMap<uint64_t, BinaryFunctionListType> NeighborHashToBFs;
/// Adjacency map for profile functions in the call graph.
DenseMap<yaml::bolt::BinaryFunctionProfile *,
std::set<yaml::bolt::BinaryFunctionProfile *>>
YamlBFAdjacencyMap;
};
// A class for matching inline tree nodes between profile and binary.
// Provides the mapping from profile inline tree node id to a
// corresponding binary MCDecodedPseudoProbeInlineTree node.
//
// The whole mapping process is the following:
//
// (profile) (binary)
// | blocks ^
// v |
// yaml::bolt::BinaryBasicBlockProfile ~= FlowBlock
// ||| probes ^ (majority vote)
// v ||| BBPseudoProbeToBlock
// yaml::bolt::PseudoProbeInfo MCDecodedPseudoProbe
// | InlineTreeIndex ^
// v | probe id
// [ profile node id (uint32_t) -> MCDecodedPseudoProbeInlineTree *]
// InlineTreeNodeMapTy
class InlineTreeNodeMapTy {
DenseMap<uint32_t, const MCDecodedPseudoProbeInlineTree *> Map;
void mapInlineTreeNode(uint32_t ProfileNodeIdx,
const MCDecodedPseudoProbeInlineTree *BinaryNode) {
auto Res = Map.try_emplace(ProfileNodeIdx, BinaryNode);
assert(Res.second &&
"Duplicate mapping from profile node index to binary inline tree");
(void)Res;
}
public:
/// Returns matched InlineTree * for a given profile inline_tree_id.
const MCDecodedPseudoProbeInlineTree *
getInlineTreeNode(uint32_t ProfileInlineTreeNodeId) const {
auto It = Map.find(ProfileInlineTreeNodeId);
if (It == Map.end())
return nullptr;
return It->second;
}
// Match up \p YamlInlineTree with binary inline tree rooted at \p Root.
// Return the number of matched nodes.
//
// This function populates the mapping from profile inline tree node id to a
// corresponding binary MCDecodedPseudoProbeInlineTree node.
size_t matchInlineTrees(
const MCPseudoProbeDecoder &Decoder,
const std::vector<yaml::bolt::InlineTreeNode> &YamlInlineTree,
const MCDecodedPseudoProbeInlineTree *Root);
};
// Partial probe matching specification: matched inline tree and corresponding
// BinaryFunctionProfile
using ProbeMatchSpec =
std::pair<InlineTreeNodeMapTy,
std::reference_wrapper<yaml::bolt::BinaryFunctionProfile>>;
private:
/// Adjustments for basic samples profiles (without LBR).
bool NormalizeByInsnCount{false};
bool NormalizeByCalls{false};
/// Binary profile in YAML format.
yaml::bolt::BinaryProfile YamlBP;
/// Map a function ID from a YAML profile to a BinaryFunction object.
DenseMap<uint32_t, BinaryFunction *> YamlProfileToFunction;
using FunctionSet = std::unordered_set<const BinaryFunction *>;
/// To keep track of functions that have a matched profile before the profile
/// is attributed.
FunctionSet ProfiledFunctions;
/// Maps profiled function id to function, for function matching with calls as
/// anchors.
ProfileLookupMap IdToYamLBF;
/// For LTO symbol resolution.
/// Map a common LTO prefix to a list of YAML profiles matching the prefix.
StringMap<std::vector<yaml::bolt::BinaryFunctionProfile *>> LTOCommonNameMap;
/// Map a common LTO prefix to a set of binary functions.
StringMap<std::unordered_set<BinaryFunction *>> LTOCommonNameFunctionMap;
/// Function names in profile.
StringSet<> ProfileFunctionNames;
/// BinaryFunction pointers indexed by YamlBP functions.
BinaryFunctionListType ProfileBFs;
// Pseudo probe function GUID to inline tree node
GUIDInlineTreeMap TopLevelGUIDToInlineTree;
// Mapping from a binary function to its partial match specification
// (YAML profile and its inline tree mapping to binary).
DenseMap<BinaryFunction *, std::vector<ProbeMatchSpec>> BFToProbeMatchSpecs;
/// Populate \p Function profile with the one supplied in YAML format.
bool parseFunctionProfile(BinaryFunction &Function,
const yaml::bolt::BinaryFunctionProfile &YamlBF);
/// Checks if a function profile matches a binary function.
bool profileMatches(const yaml::bolt::BinaryFunctionProfile &Profile,
const BinaryFunction &BF);
/// Infer function profile from stale data (collected on older binaries).
bool inferStaleProfile(BinaryFunction &Function,
const yaml::bolt::BinaryFunctionProfile &YamlBF,
const ArrayRef<ProbeMatchSpec> ProbeMatchSpecs);
/// Initialize maps for profile matching.
void buildNameMaps(BinaryContext &BC);
/// Matches functions using exact name.
size_t matchWithExactName();
/// Matches function using LTO comomon name.
size_t matchWithLTOCommonName();
/// Matches functions using exact hash.
size_t matchWithHash(BinaryContext &BC);
/// Matches functions using the call graph.
size_t matchWithCallGraph(BinaryContext &BC);
/// Matches functions using the call graph.
/// Populates BF->partial probe match spec map.
size_t matchWithPseudoProbes(BinaryContext &BC);
/// Matches functions with similarly named profiled functions.
size_t matchWithNameSimilarity(BinaryContext &BC);
/// Update matched YAML -> BinaryFunction pair.
void matchProfileToFunction(yaml::bolt::BinaryFunctionProfile &YamlBF,
BinaryFunction &BF) {
YamlProfileToFunction[YamlBF.Id] = &BF;
YamlBF.Used = true;
assert(!ProfiledFunctions.count(&BF) &&
"function already has an assigned profile");
ProfiledFunctions.emplace(&BF);
}
/// Check if the profile uses an event with a given \p Name.
bool usesEvent(StringRef Name) const;
};
} // namespace bolt
} // namespace llvm
#endif