Skip to content
12 changes: 4 additions & 8 deletions bolt/include/bolt/Core/BinaryContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -757,10 +757,8 @@ class BinaryContext {
uint32_t NumExactMatchedBlocks{0};
/// the number of loosely matched basic blocks
uint32_t NumLooseMatchedBlocks{0};
/// the number of exactly pseudo probe matched basic blocks
uint32_t NumPseudoProbeExactMatchedBlocks{0};
/// the number of loosely pseudo probe matched basic blocks
uint32_t NumPseudoProbeLooseMatchedBlocks{0};
/// the number of pseudo probe matched basic blocks
uint32_t NumPseudoProbeMatchedBlocks{0};
/// the number of call matched basic blocks
uint32_t NumCallMatchedBlocks{0};
/// the total count of samples in the profile
Expand All @@ -769,10 +767,8 @@ class BinaryContext {
uint64_t ExactMatchedSampleCount{0};
/// the count of loosely matched samples
uint64_t LooseMatchedSampleCount{0};
/// the count of exactly pseudo probe matched samples
uint64_t PseudoProbeExactMatchedSampleCount{0};
/// the count of loosely pseudo probe matched samples
uint64_t PseudoProbeLooseMatchedSampleCount{0};
/// the count of pseudo probe matched samples
uint64_t PseudoProbeMatchedSampleCount{0};
/// the count of call matched samples
uint64_t CallMatchedSampleCount{0};
} Stats;
Expand Down
117 changes: 70 additions & 47 deletions bolt/include/bolt/Profile/YAMLProfileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ class YAMLProfileReader : public ProfileReaderBase {
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
Expand Down Expand Up @@ -110,51 +107,40 @@ class YAMLProfileReader : public ProfileReaderBase {
// (profile) (binary)
// | blocks ^
// v |
// yaml::bolt::BinaryBasicBlockProfile ~= FlowBlock
// ||| probes ^ (majority vote)
// v ||| BBPseudoProbeToBlock
// yaml::bolt::PseudoProbeInfo MCDecodedPseudoProbe
// BinaryBasicBlockProfile BasicBlock
// | probes ^
// v | address
// 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;
}
using InlineTreeNodeMapTy =
std::vector<const MCDecodedPseudoProbeInlineTree *>;

// 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
// Match up \p YamlInlineTree with binary inline tree rooted at \p Root.
// Return the number of matched nodes.
//
// This function populates the \p Map indexed by \p YamlInlineTree from
// profile inline tree node id to a corresponding binary
// MCDecodedPseudoProbeInlineTree node on a successful match or nullptr.
size_t matchInlineTreesImpl(
BinaryFunction &BF, yaml::bolt::BinaryFunctionProfile &YamlBF,
const MCDecodedPseudoProbeInlineTree &Root, uint32_t RootIdx,
ArrayRef<yaml::bolt::InlineTreeNode> YamlInlineTree,
MutableArrayRef<const MCDecodedPseudoProbeInlineTree *> Map, float Scale);

/// Support mapping the profile to the same binary function more than once.
/// The index is used to check and prevent recursive (backtracking) matches.
/// The value is a node map and scale factor, used to downscale outlined
/// profile when inlining it into the function.
using RootIdxToMapTy =
std::map<uint32_t, std::pair<InlineTreeNodeMapTy, float>>;
/// Probe matching specification: map from \p BinaryFunctionProfile to the
/// partial match specification \p RootIdxToMapTy.
using ProbeMatchSpec =
std::pair<InlineTreeNodeMapTy,
std::reference_wrapper<yaml::bolt::BinaryFunctionProfile>>;
std::unordered_map<const yaml::bolt::BinaryFunctionProfile *,
RootIdxToMapTy>;

private:
/// Adjustments for basic samples profiles (without LBR).
Expand Down Expand Up @@ -183,18 +169,43 @@ class YAMLProfileReader : public ProfileReaderBase {
/// Map a common LTO prefix to a set of binary functions.
StringMap<std::unordered_set<BinaryFunction *>> LTOCommonNameFunctionMap;

/// For pseudo probe function matching.
/// Set of profile GUIDs.
std::unordered_set<uint64_t> YamlGUIDs;
/// Map binary function GUID to binary function.
std::unordered_multimap<uint64_t, BinaryFunction *> GUIDToBF;

/// Function names in profile.
StringSet<> ProfileFunctionNames;

/// BinaryFunction pointers indexed by YamlBP functions.
std::vector<BinaryFunction *> 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;
DenseMap<BinaryFunction *, ProbeMatchSpec> BFToProbeMatchSpecs;

/// Pseudo probe matching stats.
struct {
// Inline tree root mismatch causes.
uint64_t MismatchingRootGUID{0};
uint64_t MismatchingRootHash{0};
// Inline tree internal node mismatch causes.
uint64_t MismatchingNodeHash{0};
uint64_t MissingProfileNode{0};
// Incomplete profile causes.
uint64_t MissingCallProbe{0};
uint64_t MissingCallee{0};
uint64_t MissingInlineTree{0};
uint64_t TotalCallSites{0};
uint64_t MissingCallCount{0};
uint64_t TotalCallCount{0};
// Total matched stats.
uint64_t MatchedRoots{0};
uint64_t MatchedNodes{0};
uint64_t AttemptedNodes{0};
uint64_t AttemptedRoots{0};
} ProbeMatchingStats;

/// Populate \p Function profile with the one supplied in YAML format.
bool parseFunctionProfile(BinaryFunction &Function,
Expand All @@ -207,7 +218,7 @@ class YAMLProfileReader : public ProfileReaderBase {
/// Infer function profile from stale data (collected on older binaries).
bool inferStaleProfile(BinaryFunction &Function,
const yaml::bolt::BinaryFunctionProfile &YamlBF,
const ArrayRef<ProbeMatchSpec> ProbeMatchSpecs);
const ProbeMatchSpec &ProbeMatchSpecs);

/// Initialize maps for profile matching.
void buildNameMaps(BinaryContext &BC);
Expand Down Expand Up @@ -242,6 +253,18 @@ class YAMLProfileReader : public ProfileReaderBase {
ProfiledFunctions.emplace(&BF);
}

/// Return a top-level binary inline tree node for a given \p BF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Return a top-level binary inline tree node for a given \p BF
/// Return a top-level binary inline tree node for a given \p BF.

const MCDecodedPseudoProbeInlineTree *
lookupTopLevelNode(const BinaryFunction &BF);

/// Match up \p BF binary inline trees starting at root or \p Node if set, and
/// \p YamlBF profile starting at \p NodeIdx and record the mapping in
/// BFToProbeMatchSpecs.
void matchInlineTrees(BinaryFunction &BF,
const MCDecodedPseudoProbeInlineTree *Node,
yaml::bolt::BinaryFunctionProfile &YamlBF,
uint32_t NodeIdx, float Scale);

/// Check if the profile uses an event with a given \p Name.
bool usesEvent(StringRef Name) const;
};
Expand Down
21 changes: 5 additions & 16 deletions bolt/lib/Passes/BinaryPasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1552,25 +1552,14 @@ Error PrintProgramStats::runOnFunctions(BinaryContext &BC) {
100.0 * BC.Stats.ExactMatchedSampleCount / BC.Stats.StaleSampleCount,
BC.Stats.ExactMatchedSampleCount, BC.Stats.StaleSampleCount);
BC.outs() << format(
"BOLT-INFO: inference found an exact pseudo probe match for %.2f%% of "
"BOLT-INFO: inference found pseudo probe match for %.2f%% of "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to print this info if pseudo probes are not present?

"basic blocks (%zu out of %zu stale) responsible for %.2f%% samples"
" (%zu out of %zu stale)\n",
100.0 * BC.Stats.NumPseudoProbeExactMatchedBlocks /
BC.Stats.NumStaleBlocks,
BC.Stats.NumPseudoProbeExactMatchedBlocks, BC.Stats.NumStaleBlocks,
100.0 * BC.Stats.PseudoProbeExactMatchedSampleCount /
100.0 * BC.Stats.NumPseudoProbeMatchedBlocks / BC.Stats.NumStaleBlocks,
BC.Stats.NumPseudoProbeMatchedBlocks, BC.Stats.NumStaleBlocks,
100.0 * BC.Stats.PseudoProbeMatchedSampleCount /
BC.Stats.StaleSampleCount,
BC.Stats.PseudoProbeExactMatchedSampleCount, BC.Stats.StaleSampleCount);
BC.outs() << format(
"BOLT-INFO: inference found a loose pseudo probe match for %.2f%% of "
"basic blocks (%zu out of %zu stale) responsible for %.2f%% samples"
" (%zu out of %zu stale)\n",
100.0 * BC.Stats.NumPseudoProbeLooseMatchedBlocks /
BC.Stats.NumStaleBlocks,
BC.Stats.NumPseudoProbeLooseMatchedBlocks, BC.Stats.NumStaleBlocks,
100.0 * BC.Stats.PseudoProbeLooseMatchedSampleCount /
BC.Stats.StaleSampleCount,
BC.Stats.PseudoProbeLooseMatchedSampleCount, BC.Stats.StaleSampleCount);
BC.Stats.PseudoProbeMatchedSampleCount, BC.Stats.StaleSampleCount);
BC.outs() << format(
"BOLT-INFO: inference found a call match for %.2f%% of basic "
"blocks"
Expand Down
Loading
Loading