LLVM 20.0.0git
PGOCtxProfReader.cpp
Go to the documentation of this file.
1//===- PGOCtxProfReader.cpp - Contextual Instrumentation profile reader ---===//
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// Read a contextual profile into a datastructure suitable for maintenance
10// throughout IPO
11//
12//===----------------------------------------------------------------------===//
13
20#include "llvm/Support/Errc.h"
21#include "llvm/Support/Error.h"
22
23using namespace llvm;
24
25// FIXME(#92054) - these Error handling macros are (re-)invented in a few
26// places.
27#define EXPECT_OR_RET(LHS, RHS) \
28 auto LHS = RHS; \
29 if (!LHS) \
30 return LHS.takeError();
31
32#define RET_ON_ERR(EXPR) \
33 if (auto Err = (EXPR)) \
34 return Err;
35
37PGOCtxProfContext::getOrEmplace(uint32_t Index, GlobalValue::GUID G,
39 auto [Iter, Inserted] =
40 Callsites[Index].insert({G, PGOCtxProfContext(G, std::move(Counters))});
41 if (!Inserted)
42 return make_error<InstrProfError>(instrprof_error::invalid_prof,
43 "Duplicate GUID for same callsite.");
44 return Iter->second;
45}
46
48 DenseSet<GlobalValue::GUID> &Guids) const {
49 Guids.insert(GUID);
50 for (const auto &[_, Callsite] : Callsites)
51 for (const auto &[_, Callee] : Callsite)
52 Callee.getContainedGuids(Guids);
53}
54
55Expected<BitstreamEntry> PGOCtxProfileReader::advance() {
57}
58
59Error PGOCtxProfileReader::wrongValue(const Twine &Msg) {
60 return make_error<InstrProfError>(instrprof_error::invalid_prof, Msg);
61}
62
63Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
64 return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
65}
66
67bool PGOCtxProfileReader::canReadContext() {
68 auto Blk = advance();
69 if (!Blk) {
70 consumeError(Blk.takeError());
71 return false;
72 }
73 return Blk->Kind == BitstreamEntry::SubBlock &&
75}
76
78PGOCtxProfileReader::readContext(bool ExpectIndex) {
80
81 std::optional<ctx_profile::GUID> Guid;
82 std::optional<SmallVector<uint64_t, 16>> Counters;
83 std::optional<uint32_t> CallsiteIndex;
84
85 SmallVector<uint64_t, 1> RecordValues;
86
87 // We don't prescribe the order in which the records come in, and we are ok
88 // if other unsupported records appear. We seek in the current subblock until
89 // we get all we know.
90 auto GotAllWeNeed = [&]() {
91 return Guid.has_value() && Counters.has_value() &&
92 (!ExpectIndex || CallsiteIndex.has_value());
93 };
94 while (!GotAllWeNeed()) {
95 RecordValues.clear();
96 EXPECT_OR_RET(Entry, advance());
97 if (Entry->Kind != BitstreamEntry::Record)
98 return wrongValue(
99 "Expected records before encountering more subcontexts");
100 EXPECT_OR_RET(ReadRecord,
101 Cursor.readRecord(bitc::UNABBREV_RECORD, RecordValues));
102 switch (*ReadRecord) {
104 if (RecordValues.size() != 1)
105 return wrongValue("The GUID record should have exactly one value");
106 Guid = RecordValues[0];
107 break;
109 Counters = std::move(RecordValues);
110 if (Counters->empty())
111 return wrongValue("Empty counters. At least the entry counter (one "
112 "value) was expected");
113 break;
115 if (!ExpectIndex)
116 return wrongValue("The root context should not have a callee index");
117 if (RecordValues.size() != 1)
118 return wrongValue("The callee index should have exactly one value");
119 CallsiteIndex = RecordValues[0];
120 break;
121 default:
122 // OK if we see records we do not understand, like records (profile
123 // components) introduced later.
124 break;
125 }
126 }
127
128 PGOCtxProfContext Ret(*Guid, std::move(*Counters));
129
130 while (canReadContext()) {
131 EXPECT_OR_RET(SC, readContext(true));
132 auto &Targets = Ret.callsites()[*SC->first];
133 auto [_, Inserted] =
134 Targets.insert({SC->second.guid(), std::move(SC->second)});
135 if (!Inserted)
136 return wrongValue(
137 "Unexpected duplicate target (callee) at the same callsite.");
138 }
139 return std::make_pair(CallsiteIndex, std::move(Ret));
140}
141
142Error PGOCtxProfileReader::readMetadata() {
145 return make_error<InstrProfError>(instrprof_error::invalid_prof,
146 "Invalid magic");
147
149 RET_ON_ERR(Cursor.advance().moveInto(Entry));
150 if (Entry.Kind != BitstreamEntry::SubBlock ||
152 return unsupported("Expected Block ID");
153 // We don't need the blockinfo to read the rest, it's metadata usable for e.g.
154 // llvm-bcanalyzer.
155 RET_ON_ERR(Cursor.SkipBlock());
156
157 EXPECT_OR_RET(Blk, advance());
158 if (Blk->Kind != BitstreamEntry::SubBlock)
159 return unsupported("Expected Version record");
162 EXPECT_OR_RET(MData, advance());
163 if (MData->Kind != BitstreamEntry::Record)
164 return unsupported("Expected Version record");
165
169 return unsupported("Expected Version record");
170 if (Ver.size() != 1 || Ver[0] > PGOCtxProfileWriter::CurrentVersion)
171 return unsupported("Version " + Twine(*Code) +
172 " is higher than supported version " +
174 return Error::success();
175}
176
179 std::map<GlobalValue::GUID, PGOCtxProfContext> Ret;
180 RET_ON_ERR(readMetadata());
181 while (canReadContext()) {
182 EXPECT_OR_RET(E, readContext(false));
183 auto Key = E->second.guid();
184 if (!Ret.insert({Key, std::move(E->second)}).second)
185 return wrongValue("Duplicate roots");
186 }
187 return std::move(Ret);
188}
#define _
#define G(x, y, z)
Definition: MD5.cpp:56
#define RET_ON_ERR(EXPR)
#define EXPECT_OR_RET(LHS, RHS)
Reader for contextual iFDO profile, which comes in bitstream format.
This file contains some functions that are useful when dealing with strings.
Expected< BitstreamEntry > advance(unsigned Flags=0)
Advance the current bitstream, returning the next entry in the stream.
Expected< unsigned > readRecord(unsigned AbbrevID, SmallVectorImpl< uint64_t > &Vals, StringRef *Blob=nullptr)
Error EnterSubBlock(unsigned BlockID, unsigned *NumWordsP=nullptr)
Having read the ENTER_SUBBLOCK abbrevid, and enter the block.
@ AF_DontAutoprocessAbbrevs
If this flag is used, abbrev entries are returned just like normal records.
Error SkipBlock()
Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body of this block.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:211
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
A node (context) in the loaded contextual profile, suitable for mutation during IPO passes.
void getContainedGuids(DenseSet< GlobalValue::GUID > &Guids) const
Expected< std::map< GlobalValue::GUID, PGOCtxProfContext > > loadContexts()
static constexpr uint32_t CurrentVersion
static constexpr StringRef ContainerMagic
size_t size() const
Definition: SmallVector.h:91
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:586
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:149
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
@ Entry
Definition: COFF.h:826
@ SC
CHAIN = SC CHAIN, Imm128 - System call.
@ BLOCKINFO_BLOCK_ID
BLOCKINFO_BLOCK is used to define metadata about blocks, for example, standard abbrevs that should be...
Definition: BitCodeEnums.h:69
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1069
@ ContextNodeBlockID
@ ProfileMetadataBlockID
When advancing through a bitstream cursor, each advance can discover a few different kinds of entries...