Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ProfileData/PGOCtxProfReader.cpp
35233 views
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
14
#include "llvm/ProfileData/PGOCtxProfReader.h"
15
#include "llvm/Bitstream/BitCodeEnums.h"
16
#include "llvm/Bitstream/BitstreamReader.h"
17
#include "llvm/ProfileData/InstrProf.h"
18
#include "llvm/ProfileData/PGOCtxProfWriter.h"
19
#include "llvm/Support/Errc.h"
20
#include "llvm/Support/Error.h"
21
22
using 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
35
Expected<PGOContextualProfile &>
36
PGOContextualProfile::getOrEmplace(uint32_t Index, GlobalValue::GUID G,
37
SmallVectorImpl<uint64_t> &&Counters) {
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
46
void PGOContextualProfile::getContainedGuids(
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
54
Expected<BitstreamEntry> PGOCtxProfileReader::advance() {
55
return Cursor.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
56
}
57
58
Error PGOCtxProfileReader::wrongValue(const Twine &Msg) {
59
return make_error<InstrProfError>(instrprof_error::invalid_prof, Msg);
60
}
61
62
Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
63
return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
64
}
65
66
bool PGOCtxProfileReader::canReadContext() {
67
auto Blk = advance();
68
if (!Blk) {
69
consumeError(Blk.takeError());
70
return false;
71
}
72
return Blk->Kind == BitstreamEntry::SubBlock &&
73
Blk->ID == PGOCtxProfileBlockIDs::ContextNodeBlockID;
74
}
75
76
Expected<std::pair<std::optional<uint32_t>, PGOContextualProfile>>
77
PGOCtxProfileReader::readContext(bool ExpectIndex) {
78
RET_ON_ERR(Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID));
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) {
102
case PGOCtxProfileRecords::Guid:
103
if (RecordValues.size() != 1)
104
return wrongValue("The GUID record should have exactly one value");
105
Guid = RecordValues[0];
106
break;
107
case PGOCtxProfileRecords::Counters:
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;
113
case PGOCtxProfileRecords::CalleeIndex:
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
141
Error PGOCtxProfileReader::readMetadata() {
142
EXPECT_OR_RET(Blk, advance());
143
if (Blk->Kind != BitstreamEntry::SubBlock)
144
return unsupported("Expected Version record");
145
RET_ON_ERR(
146
Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID));
147
EXPECT_OR_RET(MData, advance());
148
if (MData->Kind != BitstreamEntry::Record)
149
return unsupported("Expected Version record");
150
151
SmallVector<uint64_t, 1> Ver;
152
EXPECT_OR_RET(Code, Cursor.readRecord(bitc::UNABBREV_RECORD, Ver));
153
if (*Code != PGOCtxProfileRecords::Version)
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 " +
158
Twine(PGOCtxProfileWriter::CurrentVersion));
159
return Error::success();
160
}
161
162
Expected<std::map<GlobalValue::GUID, PGOContextualProfile>>
163
PGOCtxProfileReader::loadContexts() {
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
}
174
175