LLVM 20.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"
21#include "llvm/Support/Error.h"
22#include <map>
23
24namespace llvm {
25class PGOContextualProfile;
26class PGOCtxProfContext;
27
28namespace internal {
29// When we traverse the contextual profile, we typically want to visit contexts
30// pertaining to a specific function. To avoid traversing the whole tree, we
31// want to keep a per-function list - which will be in preorder - of that
32// function's contexts. This happens in PGOContextualProfile. For memory use
33// efficiency, we want to make PGOCtxProfContext an intrusive double-linked list
34// node. We need to handle the cases where PGOCtxProfContext nodes are moved and
35// deleted: in both cases, we need to update the index (==list). We can do that
36// directly from the node in the list, without knowing who the "parent" of the
37// list is. That makes the ADT ilist overkill here. Finally, IndexNode is meant
38// to be an implementation detail of PGOCtxProfContext, and the only reason it's
39// factored out is to avoid implementing move semantics for all its members.
40class IndexNode {
41 // This class' members are intentionally private - it's a convenience
42 // implementation detail.
43 friend class ::llvm::PGOCtxProfContext;
44 friend class ::llvm::PGOContextualProfile;
45
46 IndexNode *Previous = nullptr;
47 IndexNode *Next = nullptr;
48
49 ~IndexNode() {
50 if (Next)
51 Next->Previous = Previous;
52 if (Previous)
53 Previous->Next = Next;
54 }
55
56 IndexNode(const IndexNode &Other) = delete;
57
59 // Copy the neighbor info
60 Next = Other.Next;
61 Previous = Other.Previous;
62
63 // Update the neighbors to point to this object
64 if (Other.Next)
65 Other.Next->Previous = this;
66 if (Other.Previous)
67 Other.Previous->Next = this;
68
69 // Make sure the dtor is a noop
70 Other.Next = nullptr;
71 Other.Previous = nullptr;
72 }
73 IndexNode() = default;
74};
75} // namespace internal
76
77/// A node (context) in the loaded contextual profile, suitable for mutation
78/// during IPO passes. We generally expect a fraction of counters and
79/// callsites to be populated. We continue to model counters as vectors, but
80/// callsites are modeled as a map of a map. The expectation is that, typically,
81/// there is a small number of indirect targets (usually, 1 for direct calls);
82/// but potentially a large number of callsites, and, as inlining progresses,
83/// the callsite count of a caller will grow.
85public:
86 using CallTargetMapTy = std::map<GlobalValue::GUID, PGOCtxProfContext>;
87 using CallsiteMapTy = std::map<uint32_t, CallTargetMapTy>;
88
89private:
90 friend class PGOCtxProfileReader;
92
93 GlobalValue::GUID GUID = 0;
95 CallsiteMapTy Callsites;
96
98 : GUID(G), Counters(std::move(Counters)) {}
99
101 getOrEmplace(uint32_t Index, GlobalValue::GUID G,
102 SmallVectorImpl<uint64_t> &&Counters);
103
104 // Create a bogus context object, used for anchoring the index double linked
105 // list - see IndexNode
106 PGOCtxProfContext() = default;
107
108public:
113
114 GlobalValue::GUID guid() const { return GUID; }
115 const SmallVectorImpl<uint64_t> &counters() const { return Counters; }
117
119 assert(!Counters.empty() &&
120 "Functions are expected to have at their entry BB instrumented, so "
121 "there should always be at least 1 counter.");
122 return Counters[0];
123 }
124
125 const CallsiteMapTy &callsites() const { return Callsites; }
126 CallsiteMapTy &callsites() { return Callsites; }
127
129 callsites()[CSId].emplace(Other.guid(), std::move(Other));
130 }
131
133 auto [_, Inserted] = callsites().try_emplace(CSId, std::move(Other));
134 (void)Inserted;
135 assert(Inserted &&
136 "CSId was expected to be newly created as result of e.g. inlining");
137 }
138
140
141 bool hasCallsite(uint32_t I) const {
142 return Callsites.find(I) != Callsites.end();
143 }
144
146 assert(hasCallsite(I) && "Callsite not found");
147 return Callsites.find(I)->second;
148 }
149
151 assert(hasCallsite(I) && "Callsite not found");
152 return Callsites.find(I)->second;
153 }
154
155 /// Insert this node's GUID as well as the GUIDs of the transitive closure of
156 /// child nodes, into the provided set (technically, all that is required of
157 /// `TSetOfGUIDs` is to have an `insert(GUID)` member)
158 template <class TSetOfGUIDs>
159 void getContainedGuids(TSetOfGUIDs &Guids) const {
160 Guids.insert(GUID);
161 for (const auto &[_, Callsite] : Callsites)
162 for (const auto &[_, Callee] : Callsite)
163 Callee.getContainedGuids(Guids);
164 }
165};
166
168 StringRef Magic;
169 BitstreamCursor Cursor;
170 Expected<BitstreamEntry> advance();
171 Error readMetadata();
172 Error wrongValue(const Twine &);
173 Error unsupported(const Twine &);
174
176 readContext(bool ExpectIndex);
177 bool canReadContext();
178
179public:
181 : Magic(Buffer.substr(0, PGOCtxProfileWriter::ContainerMagic.size())),
182 Cursor(Buffer.substr(PGOCtxProfileWriter::ContainerMagic.size())) {}
183
185};
186} // namespace llvm
187#endif
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
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:160
Tagged union holding either a T or a Error.
Definition: Error.h:481
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
void ingestContext(uint32_t CSId, PGOCtxProfContext &&Other)
CallsiteMapTy & callsites()
PGOCtxProfContext(const PGOCtxProfContext &)=delete
PGOCtxProfContext(PGOCtxProfContext &&)=default
std::map< GlobalValue::GUID, PGOCtxProfContext > CallTargetMapTy
const CallsiteMapTy & callsites() const
Expected< std::map< GlobalValue::GUID, PGOCtxProfContext > > loadContexts()
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:573
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
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:1697
@ 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:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858