Skip to content

Commit 510c296

Browse files
committed
[ctxprof] Profile format support for flat profiles
1 parent 21d73ce commit 510c296

File tree

20 files changed

+238
-146
lines changed

20 files changed

+238
-146
lines changed

llvm/include/llvm/Analysis/CtxProfAnalysis.h

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ namespace llvm {
2121

2222
class CtxProfAnalysis;
2323

24-
// Setting initial capacity to 1 because all contexts must have at least 1
25-
// counter, and then, because all contexts belonging to a function have the same
26-
// size, there'll be at most one other heap allocation.
27-
using CtxProfFlatProfile =
28-
std::map<GlobalValue::GUID, SmallVector<uint64_t, 1>>;
29-
3024
/// The instrumented contextual profile, produced by the CtxProfAnalysis.
3125
class PGOContextualProfile {
3226
friend class CtxProfAnalysis;
@@ -38,7 +32,7 @@ class PGOContextualProfile {
3832
PGOCtxProfContext Index;
3933
FunctionInfo(StringRef Name) : Name(Name) {}
4034
};
41-
std::optional<PGOCtxProfContext::CallTargetMapTy> Profiles;
35+
std::optional<PGOCtxProfile> Profile;
4236
// For the GUIDs in this module, associate metadata about each function which
4337
// we'll need when we maintain the profiles during IPO transformations.
4438
std::map<GlobalValue::GUID, FunctionInfo> FuncInfo;
@@ -56,12 +50,12 @@ class PGOContextualProfile {
5650
PGOContextualProfile(const PGOContextualProfile &) = delete;
5751
PGOContextualProfile(PGOContextualProfile &&) = default;
5852

59-
operator bool() const { return Profiles.has_value(); }
60-
61-
const PGOCtxProfContext::CallTargetMapTy &profiles() const {
62-
return *Profiles;
53+
const PGOCtxProfContext::CallTargetMapTy &contexts() const {
54+
return Profile->Contexts;
6355
}
6456

57+
const PGOCtxProfile &profiles() const { return *Profile; }
58+
6559
bool isFunctionKnown(const Function &F) const {
6660
return getDefinedFunctionGUID(F) != 0;
6761
}

llvm/include/llvm/ProfileData/PGOCtxProfReader.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,24 @@ class PGOCtxProfContext final : public internal::IndexNode {
164164
}
165165
};
166166

167+
// Setting initial capacity to 1 because all contexts must have at least 1
168+
// counter, and then, because all contexts belonging to a function have the same
169+
// size, there'll be at most one other heap allocation.
170+
using CtxProfFlatProfile =
171+
std::map<GlobalValue::GUID, SmallVector<uint64_t, 1>>;
172+
173+
using CtxProfContextualProfiles =
174+
std::map<GlobalValue::GUID, PGOCtxProfContext>;
175+
struct PGOCtxProfile {
176+
CtxProfContextualProfiles Contexts;
177+
CtxProfFlatProfile FlatProfiles;
178+
179+
PGOCtxProfile() = default;
180+
PGOCtxProfile(const PGOCtxProfile &) = delete;
181+
PGOCtxProfile(PGOCtxProfile &&) = default;
182+
PGOCtxProfile &operator=(PGOCtxProfile &&) = default;
183+
};
184+
167185
class PGOCtxProfileReader final {
168186
StringRef Magic;
169187
BitstreamCursor Cursor;
@@ -173,18 +191,21 @@ class PGOCtxProfileReader final {
173191
Error unsupported(const Twine &);
174192

175193
Expected<std::pair<std::optional<uint32_t>, PGOCtxProfContext>>
176-
readContext(bool ExpectIndex);
177-
bool canReadContext();
194+
readProfile(PGOCtxProfileBlockIDs Kind);
195+
196+
bool canEnterBlockWithID(PGOCtxProfileBlockIDs ID);
197+
Error enterBlockWithID(PGOCtxProfileBlockIDs ID);
198+
199+
Error loadContexts(CtxProfContextualProfiles &);
178200

179201
public:
180202
PGOCtxProfileReader(StringRef Buffer)
181203
: Magic(Buffer.substr(0, PGOCtxProfileWriter::ContainerMagic.size())),
182204
Cursor(Buffer.substr(PGOCtxProfileWriter::ContainerMagic.size())) {}
183205

184-
Expected<std::map<GlobalValue::GUID, PGOCtxProfContext>> loadContexts();
206+
Expected<PGOCtxProfile> loadProfiles();
185207
};
186208

187-
void convertCtxProfToYaml(raw_ostream &OS,
188-
const PGOCtxProfContext::CallTargetMapTy &);
209+
void convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &);
189210
} // namespace llvm
190211
#endif

llvm/include/llvm/ProfileData/PGOCtxProfWriter.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ enum PGOCtxProfileRecords { Invalid = 0, Version, Guid, CalleeIndex, Counters };
2323

2424
enum PGOCtxProfileBlockIDs {
2525
ProfileMetadataBlockID = bitc::FIRST_APPLICATION_BLOCKID,
26-
ContextNodeBlockID = ProfileMetadataBlockID + 1
26+
ContextsSectionBlockID = ProfileMetadataBlockID + 1,
27+
ContextRootBlockID = ContextsSectionBlockID + 1,
28+
ContextNodeBlockID = ContextRootBlockID + 1,
2729
};
2830

2931
/// Write one or more ContextNodes to the provided raw_fd_stream.
@@ -60,10 +62,13 @@ enum PGOCtxProfileBlockIDs {
6062
/// like value profiling - which would appear as additional records. For
6163
/// example, value profiling would produce a new record with a new record ID,
6264
/// containing the profiled values (much like the counters)
63-
class PGOCtxProfileWriter final {
65+
class PGOCtxProfileWriter : public ctx_profile::ProfileWriter {
66+
enum class EmptyContextCriteria { None, EntryIsZero, AllAreZero };
67+
6468
BitstreamWriter Writer;
6569

66-
void writeCounters(const ctx_profile::ContextNode &Node);
70+
void writeGuid(ctx_profile::GUID Guid);
71+
void writeCounters(ArrayRef<uint64_t> Counters);
6772
void writeImpl(std::optional<uint32_t> CallerIndex,
6873
const ctx_profile::ContextNode &Node);
6974

@@ -72,11 +77,13 @@ class PGOCtxProfileWriter final {
7277
std::optional<unsigned> VersionOverride = std::nullopt);
7378
~PGOCtxProfileWriter() { Writer.ExitBlock(); }
7479

75-
void write(const ctx_profile::ContextNode &);
80+
void startContextSection() override;
81+
void writeContextual(const ctx_profile::ContextNode &RootNode) override;
82+
void endContextSection() override;
7683

7784
// constants used in writing which a reader may find useful.
7885
static constexpr unsigned CodeLen = 2;
79-
static constexpr uint32_t CurrentVersion = 1;
86+
static constexpr uint32_t CurrentVersion = 2;
8087
static constexpr unsigned VBREncodingBits = 6;
8188
static constexpr StringRef ContainerMagic = "CTXP";
8289
};

llvm/lib/Analysis/CtxProfAnalysis.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
8888
return {};
8989
}
9090
PGOCtxProfileReader Reader(MB.get()->getBuffer());
91-
auto MaybeCtx = Reader.loadContexts();
91+
auto MaybeCtx = Reader.loadProfiles();
9292
if (!MaybeCtx) {
9393
M.getContext().emitError("contextual profile file is invalid: " +
9494
toString(MaybeCtx.takeError()));
@@ -99,16 +99,16 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
9999
for (const auto &F : M)
100100
if (!F.isDeclaration())
101101
if (auto GUID = AssignGUIDPass::getGUID(F);
102-
MaybeCtx->find(GUID) != MaybeCtx->end())
102+
MaybeCtx->Contexts.find(GUID) != MaybeCtx->Contexts.end())
103103
ProfileRootsInModule.insert(GUID);
104104

105105
// Trim first the roots that aren't in this module.
106-
for (auto &[RootGuid, _] : llvm::make_early_inc_range(*MaybeCtx))
106+
for (auto &[RootGuid, _] : llvm::make_early_inc_range(MaybeCtx->Contexts))
107107
if (!ProfileRootsInModule.contains(RootGuid))
108-
MaybeCtx->erase(RootGuid);
108+
MaybeCtx->Contexts.erase(RootGuid);
109109
// If none of the roots are in the module, we have no profile (for this
110110
// module)
111-
if (MaybeCtx->empty())
111+
if (MaybeCtx->Contexts.empty())
112112
return {};
113113

114114
// OK, so we have a valid profile and it's applicable to roots in this module.
@@ -146,7 +146,7 @@ PGOContextualProfile CtxProfAnalysis::run(Module &M,
146146
}
147147
// If we made it this far, the Result is valid - which we mark by setting
148148
// .Profiles.
149-
Result.Profiles = std::move(*MaybeCtx);
149+
Result.Profile = std::move(*MaybeCtx);
150150
Result.initIndex();
151151
return Result;
152152
}
@@ -164,7 +164,7 @@ CtxProfAnalysisPrinterPass::CtxProfAnalysisPrinterPass(raw_ostream &OS)
164164
PreservedAnalyses CtxProfAnalysisPrinterPass::run(Module &M,
165165
ModuleAnalysisManager &MAM) {
166166
CtxProfAnalysis::Result &C = MAM.getResult<CtxProfAnalysis>(M);
167-
if (!C) {
167+
if (C.contexts().empty()) {
168168
OS << "No contextual profile was provided.\n";
169169
return PreservedAnalyses::all();
170170
}
@@ -245,7 +245,7 @@ void PGOContextualProfile::initIndex() {
245245
for (auto &[Guid, FI] : FuncInfo)
246246
InsertionPoints[Guid] = &FI.Index;
247247
preorderVisit<PGOCtxProfContext::CallTargetMapTy, PGOCtxProfContext>(
248-
*Profiles, [&](PGOCtxProfContext &Ctx) {
248+
Profile->Contexts, [&](PGOCtxProfContext &Ctx) {
249249
auto InsertIt = InsertionPoints.find(Ctx.guid());
250250
if (InsertIt == InsertionPoints.end())
251251
return;
@@ -270,7 +270,7 @@ void PGOContextualProfile::update(Visitor V, const Function &F) {
270270
void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
271271
if (!F)
272272
return preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
273-
const PGOCtxProfContext>(*Profiles, V);
273+
const PGOCtxProfContext>(Profile->Contexts, V);
274274
assert(isFunctionKnown(*F));
275275
GlobalValue::GUID G = getDefinedFunctionGUID(*F);
276276
for (const auto *Node = FuncInfo.find(G)->second.Index.Next; Node;
@@ -279,11 +279,11 @@ void PGOContextualProfile::visit(ConstVisitor V, const Function *F) const {
279279
}
280280

281281
const CtxProfFlatProfile PGOContextualProfile::flatten() const {
282-
assert(Profiles.has_value());
282+
assert(Profile.has_value());
283283
CtxProfFlatProfile Flat;
284284
preorderVisit<const PGOCtxProfContext::CallTargetMapTy,
285285
const PGOCtxProfContext>(
286-
*Profiles, [&](const PGOCtxProfContext &Ctx) {
286+
Profile->Contexts, [&](const PGOCtxProfContext &Ctx) {
287287
auto [It, Ins] = Flat.insert({Ctx.guid(), {}});
288288
if (Ins) {
289289
llvm::append_range(It->second, Ctx.counters());

llvm/lib/ProfileData/PGOCtxProfReader.cpp

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,26 +58,33 @@ Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
5858
return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
5959
}
6060

61-
bool PGOCtxProfileReader::canReadContext() {
61+
bool PGOCtxProfileReader::canEnterBlockWithID(PGOCtxProfileBlockIDs ID) {
6262
auto Blk = advance();
6363
if (!Blk) {
6464
consumeError(Blk.takeError());
6565
return false;
6666
}
67-
return Blk->Kind == BitstreamEntry::SubBlock &&
68-
Blk->ID == PGOCtxProfileBlockIDs::ContextNodeBlockID;
67+
return Blk->Kind == BitstreamEntry::SubBlock && Blk->ID == ID;
68+
}
69+
Error PGOCtxProfileReader::enterBlockWithID(PGOCtxProfileBlockIDs ID) {
70+
RET_ON_ERR(Cursor.EnterSubBlock(ID));
71+
return Error::success();
6972
}
7073

7174
Expected<std::pair<std::optional<uint32_t>, PGOCtxProfContext>>
72-
PGOCtxProfileReader::readContext(bool ExpectIndex) {
73-
RET_ON_ERR(Cursor.EnterSubBlock(PGOCtxProfileBlockIDs::ContextNodeBlockID));
75+
PGOCtxProfileReader::readProfile(PGOCtxProfileBlockIDs Kind) {
76+
assert((Kind == PGOCtxProfileBlockIDs::ContextRootBlockID ||
77+
Kind == PGOCtxProfileBlockIDs::ContextNodeBlockID) &&
78+
"Unexpected profile kind");
79+
RET_ON_ERR(enterBlockWithID(Kind));
7480

7581
std::optional<ctx_profile::GUID> Guid;
7682
std::optional<SmallVector<uint64_t, 16>> Counters;
7783
std::optional<uint32_t> CallsiteIndex;
7884

7985
SmallVector<uint64_t, 1> RecordValues;
8086

87+
const bool ExpectIndex = Kind == PGOCtxProfileBlockIDs::ContextNodeBlockID;
8188
// We don't prescribe the order in which the records come in, and we are ok
8289
// if other unsupported records appear. We seek in the current subblock until
8390
// we get all we know.
@@ -121,8 +128,8 @@ PGOCtxProfileReader::readContext(bool ExpectIndex) {
121128

122129
PGOCtxProfContext Ret(*Guid, std::move(*Counters));
123130

124-
while (canReadContext()) {
125-
EXPECT_OR_RET(SC, readContext(true));
131+
while (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextNodeBlockID)) {
132+
EXPECT_OR_RET(SC, readProfile(PGOCtxProfileBlockIDs::ContextNodeBlockID));
126133
auto &Targets = Ret.callsites()[*SC->first];
127134
auto [_, Inserted] =
128135
Targets.insert({SC->second.guid(), std::move(SC->second)});
@@ -168,16 +175,23 @@ Error PGOCtxProfileReader::readMetadata() {
168175
return Error::success();
169176
}
170177

171-
Expected<std::map<GlobalValue::GUID, PGOCtxProfContext>>
172-
PGOCtxProfileReader::loadContexts() {
173-
std::map<GlobalValue::GUID, PGOCtxProfContext> Ret;
174-
RET_ON_ERR(readMetadata());
175-
while (canReadContext()) {
176-
EXPECT_OR_RET(E, readContext(false));
177-
auto Key = E->second.guid();
178-
if (!Ret.insert({Key, std::move(E->second)}).second)
179-
return wrongValue("Duplicate roots");
178+
Error PGOCtxProfileReader::loadContexts(CtxProfContextualProfiles &P) {
179+
if (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextsSectionBlockID)) {
180+
RET_ON_ERR(enterBlockWithID(PGOCtxProfileBlockIDs::ContextsSectionBlockID));
181+
while (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextRootBlockID)) {
182+
EXPECT_OR_RET(E, readProfile(PGOCtxProfileBlockIDs::ContextRootBlockID));
183+
auto Key = E->second.guid();
184+
if (!P.insert({Key, std::move(E->second)}).second)
185+
return wrongValue("Duplicate roots");
186+
}
180187
}
188+
return Error::success();
189+
}
190+
191+
Expected<PGOCtxProfile> PGOCtxProfileReader::loadProfiles() {
192+
RET_ON_ERR(readMetadata());
193+
PGOCtxProfile Ret;
194+
RET_ON_ERR(loadContexts(Ret.Contexts));
181195
return std::move(Ret);
182196
}
183197

@@ -225,41 +239,54 @@ void toYaml(yaml::Output &Out,
225239
Out.endSequence();
226240
}
227241

228-
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
242+
void toYaml(yaml::Output &Out, GlobalValue::GUID Guid,
243+
const SmallVectorImpl<uint64_t> &Counters,
244+
const PGOCtxProfContext::CallsiteMapTy &Callsites) {
229245
yaml::EmptyContext Empty;
230246
Out.beginMapping();
231247
void *SaveInfo = nullptr;
232248
bool UseDefault = false;
233249
{
234250
Out.preflightKey("Guid", /*Required=*/true, /*SameAsDefault=*/false,
235251
UseDefault, SaveInfo);
236-
auto Guid = Ctx.guid();
237252
yaml::yamlize(Out, Guid, true, Empty);
238253
Out.postflightKey(nullptr);
239254
}
240255
{
241256
Out.preflightKey("Counters", true, false, UseDefault, SaveInfo);
242257
Out.beginFlowSequence();
243-
for (size_t I = 0U, E = Ctx.counters().size(); I < E; ++I) {
258+
for (size_t I = 0U, E = Counters.size(); I < E; ++I) {
244259
Out.preflightFlowElement(I, SaveInfo);
245-
uint64_t V = Ctx.counters()[I];
260+
uint64_t V = Counters[I];
246261
yaml::yamlize(Out, V, true, Empty);
247262
Out.postflightFlowElement(SaveInfo);
248263
}
249264
Out.endFlowSequence();
250265
Out.postflightKey(nullptr);
251266
}
252-
if (!Ctx.callsites().empty()) {
267+
if (!Callsites.empty()) {
253268
Out.preflightKey("Callsites", true, false, UseDefault, SaveInfo);
254-
toYaml(Out, Ctx.callsites());
269+
toYaml(Out, Callsites);
255270
Out.postflightKey(nullptr);
256271
}
257272
Out.endMapping();
258273
}
274+
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
275+
toYaml(Out, Ctx.guid(), Ctx.counters(), Ctx.callsites());
276+
}
277+
259278
} // namespace
260279

261-
void llvm::convertCtxProfToYaml(
262-
raw_ostream &OS, const PGOCtxProfContext::CallTargetMapTy &Profiles) {
280+
void llvm::convertCtxProfToYaml(raw_ostream &OS,
281+
const PGOCtxProfile &Profiles) {
263282
yaml::Output Out(OS);
264-
toYaml(Out, Profiles);
283+
void *SaveInfo = nullptr;
284+
bool UseDefault = false;
285+
Out.beginMapping();
286+
if (!Profiles.Contexts.empty()) {
287+
Out.preflightKey("Contexts", false, false, UseDefault, SaveInfo);
288+
toYaml(Out, Profiles.Contexts);
289+
Out.postflightKey(nullptr);
290+
}
291+
Out.endMapping();
265292
}

0 commit comments

Comments
 (0)