LLVM 19.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
19#include "llvm/Support/Errc.h"
20#include "llvm/Support/Error.h"
21
22using namespace llvm;
23
24// FIXME(#92054) - these Error handling macros are (re-)invented in a few
25// places.
26#define EXPECT_OR_RET(LHS, RHS) \
27 auto LHS = RHS; \
28 if (!LHS) \
29 return LHS.takeError();
30
31#define RET_ON_ERR(EXPR) \
32 if (auto Err = (EXPR)) \
33 return Err;
34
36PGOContextualProfile::getOrEmplace(uint32_t Index, GlobalValue::GUID G,
38 auto [Iter, Inserted] = Callsites[Index].insert(
39 {G, PGOContextualProfile(G, std::move(Counters))});
40 if (!Inserted)
41 return make_error<InstrProfError>(instrprof_error::invalid_prof,
42 "Duplicate GUID for same callsite.");
43 return Iter->second;
44}
45
47 DenseSet<GlobalValue::GUID> &Guids) const {
48 Guids.insert(GUID);
49 for (const auto &[_, Callsite] : Callsites)
50 for (const auto &[_, Callee] : Callsite)
51 Callee.getContainedGuids(Guids);
52}
53
54Expected<BitstreamEntry> PGOCtxProfileReader::advance() {
56}
57
58Error PGOCtxProfileReader::wrongValue(const Twine &Msg) {
59 return make_error<InstrProfError>(instrprof_error::invalid_prof, Msg);
60}
61
62Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
63 return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
64}
65
66bool PGOCtxProfileReader::canReadContext() {
67 auto Blk = advance();
68 if (!Blk) {
69 consumeError(Blk.takeError());
70 return false;
71 }
72 return Blk->Kind == BitstreamEntry::SubBlock &&
74}
75
77PGOCtxProfileReader::readContext(bool ExpectIndex) {
79
80 std::optional<ctx_profile::GUID> Guid;
81 std::optional<SmallVector<uint64_t, 16>> Counters;
82 std::optional<uint32_t> CallsiteIndex;
83
84 SmallVector<uint64_t, 1> RecordValues;
85
86 // We don't prescribe the order in which the records come in, and we are ok
87 // if other unsupported records appear. We seek in the current subblock until
88 // we get all we know.
89 auto GotAllWeNeed = [&]() {
90 return Guid.has_value() && Counters.has_value() &&
91 (!ExpectIndex || CallsiteIndex.has_value());
92 };
93 while (!GotAllWeNeed()) {
94 RecordValues.clear();
95 EXPECT_OR_RET(Entry, advance());
96 if (Entry->Kind != BitstreamEntry::Record)
97 return wrongValue(
98 "Expected records before encountering more subcontexts");
99 EXPECT_OR_RET(ReadRecord,
100 Cursor.readRecord(bitc::UNABBREV_RECORD, RecordValues));
101 switch (*ReadRecord) {
103 if (RecordValues.size() != 1)
104 return wrongValue("The GUID record should have exactly one value");
105 Guid = RecordValues[0];
106 break;
108 Counters = std::move(RecordValues);
109 if (Counters->empty())
110 return wrongValue("Empty counters. At least the entry counter (one "
111 "value) was expected");
112 break;
114 if (!ExpectIndex)
115 return wrongValue("The root context should not have a callee index");
116 if (RecordValues.size() != 1)
117 return wrongValue("The callee index should have exactly one value");
118 CallsiteIndex = RecordValues[0];
119 break;
120 default:
121 // OK if we see records we do not understand, like records (profile
122 // components) introduced later.
123 break;
124 }
125 }
126
127 PGOContextualProfile Ret(*Guid, std::move(*Counters));
128
129 while (canReadContext()) {
130 EXPECT_OR_RET(SC, readContext(true));
131 auto &Targets = Ret.callsites()[*SC->first];
132 auto [_, Inserted] =
133 Targets.insert({SC->second.guid(), std::move(SC->second)});
134 if (!Inserted)
135 return wrongValue(
136 "Unexpected duplicate target (callee) at the same callsite.");
137 }
138 return std::make_pair(CallsiteIndex, std::move(Ret));
139}
140
141Error PGOCtxProfileReader::readMetadata() {
142 EXPECT_OR_RET(Blk, advance());
143 if (Blk->Kind != BitstreamEntry::SubBlock)
144 return unsupported("Expected Version record");
147 EXPECT_OR_RET(MData, advance());
148 if (MData->Kind != BitstreamEntry::Record)
149 return unsupported("Expected Version record");
150
154 return unsupported("Expected Version record");
155 if (Ver.size() != 1 || Ver[0] > PGOCtxProfileWriter::CurrentVersion)
156 return unsupported("Version " + Twine(*Code) +
157 " is higher than supported version " +
159 return Error::success();
160}
161
164 std::map<GlobalValue::GUID, PGOContextualProfile> Ret;
165 RET_ON_ERR(readMetadata());
166 while (canReadContext()) {
167 EXPECT_OR_RET(E, readContext(false));
168 auto Key = E->second.guid();
169 if (!Ret.insert({Key, std::move(E->second)}).second)
170 return wrongValue("Duplicate roots");
171 }
172 return std::move(Ret);
173}
#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.
@ AF_DontAutoprocessAbbrevs
If this flag is used, abbrev entries are returned just like normal records.
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.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:220
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
The loaded contextual profile, suitable for mutation during IPO passes.
void getContainedGuids(DenseSet< GlobalValue::GUID > &Guids) const
Expected< std::map< GlobalValue::GUID, PGOContextualProfile > > loadContexts()
static constexpr uint32_t CurrentVersion
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
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
@ SC
CHAIN = SC CHAIN, Imm128 - System call.
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