clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
224 lines
9.2 KiB
C++
224 lines
9.2 KiB
C++
//===- Transforms/IPO/SampleContextTracker.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file
|
|
/// This file provides the interface for context-sensitive profile tracker used
|
|
/// by CSSPGO.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TRANSFORMS_IPO_SAMPLECONTEXTTRACKER_H
|
|
#define LLVM_TRANSFORMS_IPO_SAMPLECONTEXTTRACKER_H
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/iterator.h"
|
|
#include "llvm/ProfileData/SampleProf.h"
|
|
#include <map>
|
|
#include <queue>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
class CallBase;
|
|
class DILocation;
|
|
class Function;
|
|
class Instruction;
|
|
|
|
// Internal trie tree representation used for tracking context tree and sample
|
|
// profiles. The path from root node to a given node represents the context of
|
|
// that nodes' profile.
|
|
class ContextTrieNode {
|
|
public:
|
|
ContextTrieNode(ContextTrieNode *Parent = nullptr,
|
|
FunctionId FName = FunctionId(),
|
|
FunctionSamples *FSamples = nullptr,
|
|
LineLocation CallLoc = {0, 0})
|
|
: ParentContext(Parent), FuncName(FName), FuncSamples(FSamples),
|
|
CallSiteLoc(CallLoc){};
|
|
ContextTrieNode *getChildContext(const LineLocation &CallSite,
|
|
FunctionId ChildName);
|
|
ContextTrieNode *getHottestChildContext(const LineLocation &CallSite);
|
|
ContextTrieNode *getOrCreateChildContext(const LineLocation &CallSite,
|
|
FunctionId ChildName,
|
|
bool AllowCreate = true);
|
|
void removeChildContext(const LineLocation &CallSite, FunctionId ChildName);
|
|
std::map<uint64_t, ContextTrieNode> &getAllChildContext();
|
|
FunctionId getFuncName() const;
|
|
FunctionSamples *getFunctionSamples() const;
|
|
void setFunctionSamples(FunctionSamples *FSamples);
|
|
std::optional<uint32_t> getFunctionSize() const;
|
|
void addFunctionSize(uint32_t FSize);
|
|
LineLocation getCallSiteLoc() const;
|
|
ContextTrieNode *getParentContext() const;
|
|
void setParentContext(ContextTrieNode *Parent);
|
|
void setCallSiteLoc(const LineLocation &Loc);
|
|
void dumpNode();
|
|
void dumpTree();
|
|
|
|
private:
|
|
// Map line+discriminator location to child context
|
|
std::map<uint64_t, ContextTrieNode> AllChildContext;
|
|
|
|
// Link to parent context node
|
|
ContextTrieNode *ParentContext;
|
|
|
|
// Function name for current context
|
|
FunctionId FuncName;
|
|
|
|
// Function Samples for current context
|
|
FunctionSamples *FuncSamples;
|
|
|
|
// Function size for current context
|
|
std::optional<uint32_t> FuncSize;
|
|
|
|
// Callsite location in parent context
|
|
LineLocation CallSiteLoc;
|
|
};
|
|
|
|
// Profile tracker that manages profiles and its associated context. It
|
|
// provides interfaces used by sample profile loader to query context profile or
|
|
// base profile for given function or location; it also manages context tree
|
|
// manipulation that is needed to accommodate inline decisions so we have
|
|
// accurate post-inline profile for functions. Internally context profiles
|
|
// are organized in a trie, with each node representing profile for specific
|
|
// calling context and the context is identified by path from root to the node.
|
|
class SampleContextTracker {
|
|
public:
|
|
using ContextSamplesTy = std::vector<FunctionSamples *>;
|
|
|
|
SampleContextTracker() = default;
|
|
SampleContextTracker(SampleProfileMap &Profiles,
|
|
const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap);
|
|
// Populate the FuncToCtxtProfiles map after the trie is built.
|
|
void populateFuncToCtxtMap();
|
|
// Query context profile for a specific callee with given name at a given
|
|
// call-site. The full context is identified by location of call instruction.
|
|
FunctionSamples *getCalleeContextSamplesFor(const CallBase &Inst,
|
|
StringRef CalleeName);
|
|
// Get samples for indirect call targets for call site at given location.
|
|
std::vector<const FunctionSamples *>
|
|
getIndirectCalleeContextSamplesFor(const DILocation *DIL);
|
|
// Query context profile for a given location. The full context
|
|
// is identified by input DILocation.
|
|
FunctionSamples *getContextSamplesFor(const DILocation *DIL);
|
|
// Query context profile for a given sample contxt of a function.
|
|
FunctionSamples *getContextSamplesFor(const SampleContext &Context);
|
|
// Get all context profile for given function.
|
|
ContextSamplesTy &getAllContextSamplesFor(const Function &Func);
|
|
ContextSamplesTy &getAllContextSamplesFor(StringRef Name);
|
|
ContextTrieNode *getOrCreateContextPath(const SampleContext &Context,
|
|
bool AllowCreate);
|
|
// Query base profile for a given function. A base profile is a merged view
|
|
// of all context profiles for contexts that are not inlined.
|
|
FunctionSamples *getBaseSamplesFor(const Function &Func,
|
|
bool MergeContext = true);
|
|
// Query base profile for a given function by name.
|
|
FunctionSamples *getBaseSamplesFor(FunctionId Name,
|
|
bool MergeContext = true);
|
|
// Retrieve the context trie node for given profile context
|
|
ContextTrieNode *getContextFor(const SampleContext &Context);
|
|
// Get real function name for a given trie node.
|
|
StringRef getFuncNameFor(ContextTrieNode *Node) const;
|
|
// Mark a context profile as inlined when function is inlined.
|
|
// This makes sure that inlined context profile will be excluded in
|
|
// function's base profile.
|
|
void markContextSamplesInlined(const FunctionSamples *InlinedSamples);
|
|
ContextTrieNode &getRootContext();
|
|
void promoteMergeContextSamplesTree(const Instruction &Inst,
|
|
FunctionId CalleeName);
|
|
|
|
// Create a merged conext-less profile map.
|
|
void createContextLessProfileMap(SampleProfileMap &ContextLessProfiles);
|
|
ContextTrieNode *
|
|
getContextNodeForProfile(const FunctionSamples *FSamples) const {
|
|
auto I = ProfileToNodeMap.find(FSamples);
|
|
if (I == ProfileToNodeMap.end())
|
|
return nullptr;
|
|
return I->second;
|
|
}
|
|
HashKeyMap<std::unordered_map, FunctionId, ContextSamplesTy>
|
|
&getFuncToCtxtProfiles() {
|
|
return FuncToCtxtProfiles;
|
|
}
|
|
|
|
class Iterator : public llvm::iterator_facade_base<
|
|
Iterator, std::forward_iterator_tag, ContextTrieNode *,
|
|
std::ptrdiff_t, ContextTrieNode **, ContextTrieNode *> {
|
|
std::queue<ContextTrieNode *> NodeQueue;
|
|
|
|
public:
|
|
explicit Iterator() = default;
|
|
explicit Iterator(ContextTrieNode *Node) { NodeQueue.push(Node); }
|
|
Iterator &operator++() {
|
|
assert(!NodeQueue.empty() && "Iterator already at the end");
|
|
ContextTrieNode *Node = NodeQueue.front();
|
|
NodeQueue.pop();
|
|
for (auto &It : Node->getAllChildContext())
|
|
NodeQueue.push(&It.second);
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const Iterator &Other) const {
|
|
if (NodeQueue.empty() && Other.NodeQueue.empty())
|
|
return true;
|
|
if (NodeQueue.empty() || Other.NodeQueue.empty())
|
|
return false;
|
|
return NodeQueue.front() == Other.NodeQueue.front();
|
|
}
|
|
|
|
ContextTrieNode *operator*() const {
|
|
assert(!NodeQueue.empty() && "Invalid access to end iterator");
|
|
return NodeQueue.front();
|
|
}
|
|
};
|
|
|
|
Iterator begin() { return Iterator(&RootContext); }
|
|
Iterator end() { return Iterator(); }
|
|
|
|
#ifndef NDEBUG
|
|
// Get a context string from root to current node.
|
|
std::string getContextString(const FunctionSamples &FSamples) const;
|
|
std::string getContextString(ContextTrieNode *Node) const;
|
|
#endif
|
|
// Dump the internal context profile trie.
|
|
void dump();
|
|
|
|
private:
|
|
ContextTrieNode *getContextFor(const DILocation *DIL);
|
|
ContextTrieNode *getCalleeContextFor(const DILocation *DIL,
|
|
FunctionId CalleeName);
|
|
ContextTrieNode *getTopLevelContextNode(FunctionId FName);
|
|
ContextTrieNode &addTopLevelContextNode(FunctionId FName);
|
|
ContextTrieNode &promoteMergeContextSamplesTree(ContextTrieNode &NodeToPromo);
|
|
void mergeContextNode(ContextTrieNode &FromNode, ContextTrieNode &ToNode);
|
|
ContextTrieNode &
|
|
promoteMergeContextSamplesTree(ContextTrieNode &FromNode,
|
|
ContextTrieNode &ToNodeParent);
|
|
ContextTrieNode &moveContextSamples(ContextTrieNode &ToNodeParent,
|
|
const LineLocation &CallSite,
|
|
ContextTrieNode &&NodeToMove);
|
|
void setContextNode(const FunctionSamples *FSample, ContextTrieNode *Node) {
|
|
ProfileToNodeMap[FSample] = Node;
|
|
}
|
|
// Map from function name to context profiles (excluding base profile)
|
|
HashKeyMap<std::unordered_map, FunctionId, ContextSamplesTy>
|
|
FuncToCtxtProfiles;
|
|
|
|
// Map from current FunctionSample to the belonged context trie.
|
|
std::unordered_map<const FunctionSamples *, ContextTrieNode *>
|
|
ProfileToNodeMap;
|
|
|
|
// Map from function guid to real function names. Only used in md5 mode.
|
|
const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap;
|
|
|
|
// Root node for context trie tree
|
|
ContextTrieNode RootContext;
|
|
};
|
|
|
|
} // end namespace llvm
|
|
#endif // LLVM_TRANSFORMS_IPO_SAMPLECONTEXTTRACKER_H
|