LLVM 22.0.0git
PGOCtxProfReader.h
Go to the documentation of this file.
1//===--- PGOCtxProfReader.h - Contextual profile reader ---------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10///
11/// Reader for contextual iFDO profile, which comes in bitstream format.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_PROFILEDATA_CTXINSTRPROFILEREADER_H
16#define LLVM_PROFILEDATA_CTXINSTRPROFILEREADER_H
17
19#include "llvm/IR/GlobalValue.h"
22#include "llvm/Support/Error.h"
23#include <map>
24
25namespace llvm {
26class PGOContextualProfile;
27class PGOCtxProfContext;
28
29namespace internal {
30// When we traverse the contextual profile, we typically want to visit contexts
31// pertaining to a specific function. To avoid traversing the whole tree, we
32// want to keep a per-function list - which will be in preorder - of that
33// function's contexts. This happens in PGOContextualProfile. For memory use
34// efficiency, we want to make PGOCtxProfContext an intrusive double-linked list
35// node. We need to handle the cases where PGOCtxProfContext nodes are moved and
36// deleted: in both cases, we need to update the index (==list). We can do that
37// directly from the node in the list, without knowing who the "parent" of the
38// list is. That makes the ADT ilist overkill here. Finally, IndexNode is meant
39// to be an implementation detail of PGOCtxProfContext, and the only reason it's
40// factored out is to avoid implementing move semantics for all its members.
41class IndexNode {
42 // This class' members are intentionally private - it's a convenience
43 // implementation detail.
44 friend class ::llvm::PGOCtxProfContext;
45 friend class ::llvm::PGOContextualProfile;
46
47 IndexNode *Previous = nullptr;
48 IndexNode *Next = nullptr;
49
50 ~IndexNode() {
51 if (Next)
52 Next->Previous = Previous;
53 if (Previous)
54 Previous->Next = Next;
55 }
56
57 IndexNode(const IndexNode &Other) = delete;
58
60 // Copy the neighbor info
61 Next = Other.Next;
62 Previous = Other.Previous;
63
64 // Update the neighbors to point to this object
65 if (Other.Next)
66 Other.Next->Previous = this;
67 if (Other.Previous)
68 Other.Previous->Next = this;
69
70 // Make sure the dtor is a noop
71 Other.Next = nullptr;
72 Other.Previous = nullptr;
73 }
74 IndexNode() = default;
75};
76} // namespace internal
77
78// Setting initial capacity to 1 because all contexts must have at least 1
79// counter, and then, because all contexts belonging to a function have the same
80// size, there'll be at most one other heap allocation.
82 std::map<GlobalValue::GUID, SmallVector<uint64_t, 1>>;
83
84/// A node (context) in the loaded contextual profile, suitable for mutation
85/// during IPO passes. We generally expect a fraction of counters and
86/// callsites to be populated. We continue to model counters as vectors, but
87/// callsites are modeled as a map of a map. The expectation is that, typically,
88/// there is a small number of indirect targets (usually, 1 for direct calls);
89/// but potentially a large number of callsites, and, as inlining progresses,
90/// the callsite count of a caller will grow.
92public:
93 using CallTargetMapTy = std::map<GlobalValue::GUID, PGOCtxProfContext>;
94 using CallsiteMapTy = std::map<uint32_t, CallTargetMapTy>;
95
96private:
97 friend class PGOCtxProfileReader;
99
100 GlobalValue::GUID GUID = 0;
102 const std::optional<uint64_t> RootEntryCount{};
103 std::optional<CtxProfFlatProfile> Unhandled{};
104 CallsiteMapTy Callsites;
105
106 PGOCtxProfContext(
107 GlobalValue::GUID G, SmallVectorImpl<uint64_t> &&Counters,
108 std::optional<uint64_t> RootEntryCount = std::nullopt,
109 std::optional<CtxProfFlatProfile> &&Unhandled = std::nullopt)
110 : GUID(G), Counters(std::move(Counters)), RootEntryCount(RootEntryCount),
111 Unhandled(std::move(Unhandled)) {
112 assert(RootEntryCount.has_value() == Unhandled.has_value());
113 }
114
115 Expected<PGOCtxProfContext &>
116 getOrEmplace(uint32_t Index, GlobalValue::GUID G,
117 SmallVectorImpl<uint64_t> &&Counters);
118
119 // Create a bogus context object, used for anchoring the index double linked
120 // list - see IndexNode
121 PGOCtxProfContext() = default;
122
123public:
128
129 GlobalValue::GUID guid() const { return GUID; }
130 const SmallVectorImpl<uint64_t> &counters() const { return Counters; }
132
133 bool isRoot() const { return RootEntryCount.has_value(); }
134 uint64_t getTotalRootEntryCount() const { return RootEntryCount.value(); }
135
136 const CtxProfFlatProfile &getUnhandled() const { return Unhandled.value(); }
137
139 assert(!Counters.empty() &&
140 "Functions are expected to have at their entry BB instrumented, so "
141 "there should always be at least 1 counter.");
142 return Counters[0];
143 }
144
145 const CallsiteMapTy &callsites() const { return Callsites; }
146 CallsiteMapTy &callsites() { return Callsites; }
147
149 callsites()[CSId].emplace(Other.guid(), std::move(Other));
150 }
151
153 auto [_, Inserted] = callsites().try_emplace(CSId, std::move(Other));
154 (void)Inserted;
155 assert(Inserted &&
156 "CSId was expected to be newly created as result of e.g. inlining");
157 }
158
160
161 bool hasCallsite(uint32_t I) const {
162 return Callsites.find(I) != Callsites.end();
163 }
164
166 assert(hasCallsite(I) && "Callsite not found");
167 return Callsites.find(I)->second;
168 }
169
171 assert(hasCallsite(I) && "Callsite not found");
172 return Callsites.find(I)->second;
173 }
174
175 /// Insert this node's GUID as well as the GUIDs of the transitive closure of
176 /// child nodes, into the provided set (technically, all that is required of
177 /// `TSetOfGUIDs` is to have an `insert(GUID)` member)
178 template <class TSetOfGUIDs>
179 void getContainedGuids(TSetOfGUIDs &Guids) const {
180 Guids.insert(GUID);
181 for (const auto &[_, Callsite] : Callsites)
182 for (const auto &[_, Callee] : Callsite)
183 Callee.getContainedGuids(Guids);
184 }
185};
186
188 std::map<GlobalValue::GUID, PGOCtxProfContext>;
192
193 PGOCtxProfile() = default;
194 PGOCtxProfile(const PGOCtxProfile &) = delete;
197};
198
200 StringRef Magic;
201 BitstreamCursor Cursor;
202 Expected<BitstreamEntry> advance();
203 Error readMetadata();
204 Error wrongValue(const Twine &Msg);
205 Error unsupported(const Twine &Msg);
206
208 readProfile(PGOCtxProfileBlockIDs Kind);
209
210 bool tryGetNextKnownBlockID(PGOCtxProfileBlockIDs &ID);
211 bool canEnterBlockWithID(PGOCtxProfileBlockIDs ID);
212 Error enterBlockWithID(PGOCtxProfileBlockIDs ID);
213
214 Error loadContexts(CtxProfContextualProfiles &P);
215 Error loadFlatProfiles(CtxProfFlatProfile &P);
216 Error loadFlatProfileList(CtxProfFlatProfile &P);
217
218public:
220 : Magic(Buffer.substr(0, PGOCtxProfileWriter::ContainerMagic.size())),
221 Cursor(Buffer.substr(PGOCtxProfileWriter::ContainerMagic.size())) {}
222
224};
225
226LLVM_ABI void convertCtxProfToYaml(raw_ostream &OS,
227 const PGOCtxProfile &Profile);
228} // namespace llvm
229#endif
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_ABI
Definition: Compiler.h:213
uint32_t Index
uint64_t Size
#define _
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
Load MIR Sample Profile
#define P(N)
raw_pwrite_stream & OS
static StringRef substr(StringRef Str, uint64_t Len)
This represents a position within a bitcode file, implemented on top of a SimpleBitstreamCursor.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
Tagged union holding either a T or a Error.
Definition: Error.h:485
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
Definition: GlobalValue.h:577
The instrumented contextual profile, produced by the CtxProfAnalysis.
A node (context) in the loaded contextual profile, suitable for mutation during IPO passes.
CallTargetMapTy & callsite(uint32_t I)
SmallVectorImpl< uint64_t > & counters()
bool hasCallsite(uint32_t I) const
void resizeCounters(uint32_t Size)
GlobalValue::GUID guid() const
void ingestAllContexts(uint32_t CSId, CallTargetMapTy &&Other)
void getContainedGuids(TSetOfGUIDs &Guids) const
Insert this node's GUID as well as the GUIDs of the transitive closure of child nodes,...
PGOCtxProfContext & operator=(const PGOCtxProfContext &)=delete
const CallTargetMapTy & callsite(uint32_t I) const
PGOCtxProfContext & operator=(PGOCtxProfContext &&)=delete
uint64_t getEntrycount() const
const SmallVectorImpl< uint64_t > & counters() const
std::map< uint32_t, CallTargetMapTy > CallsiteMapTy
const CtxProfFlatProfile & getUnhandled() const
void ingestContext(uint32_t CSId, PGOCtxProfContext &&Other)
CallsiteMapTy & callsites()
PGOCtxProfContext(const PGOCtxProfContext &)=delete
uint64_t getTotalRootEntryCount() const
PGOCtxProfContext(PGOCtxProfContext &&)=default
std::map< GlobalValue::GUID, PGOCtxProfContext > CallTargetMapTy
const CallsiteMapTy & callsites() const
LLVM_ABI Expected< PGOCtxProfile > loadProfiles()
PGOCtxProfileReader(StringRef Buffer)
Write one or more ContextNodes to the provided raw_fd_stream.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:82
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition: STLExtras.h:1702
std::map< GlobalValue::GUID, PGOCtxProfContext > CtxProfContextualProfiles
std::map< GlobalValue::GUID, SmallVector< uint64_t, 1 > > CtxProfFlatProfile
@ Other
Any other memory.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1886
LLVM_ABI void convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &Profile)
PGOCtxProfileBlockIDs
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:856
PGOCtxProfile(PGOCtxProfile &&)=default
PGOCtxProfile()=default
PGOCtxProfile & operator=(PGOCtxProfile &&)=default
CtxProfFlatProfile FlatProfiles
PGOCtxProfile(const PGOCtxProfile &)=delete
CtxProfContextualProfiles Contexts