Skip to content

Commit 9cd9f3a

Browse files
committed
[ctxprof] Prepare profile format for flat profiles
1 parent b41baaf commit 9cd9f3a

31 files changed

+458
-261
lines changed

compiler-rt/lib/ctx_profile/CtxInstrContextNode.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,14 @@ class ContextNode final {
114114
};
115115

116116
/// Abstraction for the parameter passed to `__llvm_ctx_profile_fetch`.
117+
/// `startContextSection` is called before any context roots are sent for
118+
/// writing. Then one or more `writeContextual` calls are made; finally,
119+
/// `endContextSection` is called.
117120
class ProfileWriter {
118121
public:
122+
virtual void startContextSection() = 0;
119123
virtual void writeContextual(const ctx_profile::ContextNode &RootNode) = 0;
124+
virtual void endContextSection() = 0;
120125
virtual ~ProfileWriter() = default;
121126
};
122127
} // namespace ctx_profile

compiler-rt/lib/ctx_profile/CtxInstrProfiling.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ bool __llvm_ctx_profile_fetch(ProfileWriter &Writer) {
298298
__sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
299299
&AllContextsMutex);
300300

301+
Writer.startContextSection();
301302
for (int I = 0, E = AllContextRoots.Size(); I < E; ++I) {
302303
auto *Root = AllContextRoots[I];
303304
__sanitizer::GenericScopedLock<__sanitizer::StaticSpinMutex> TakenLock(
@@ -308,6 +309,7 @@ bool __llvm_ctx_profile_fetch(ProfileWriter &Writer) {
308309
}
309310
Writer.writeContextual(*Root->FirstNode);
310311
}
312+
Writer.endContextSection();
311313
return true;
312314
}
313315

compiler-rt/lib/ctx_profile/tests/CtxInstrProfilingTest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,18 @@ TEST_F(ContextTest, Dump) {
183183
public:
184184
ContextRoot *const Root;
185185
const size_t Entries;
186+
187+
int EnteredSectionCount = 0;
188+
int ExitedSectionCount = 0;
189+
186190
bool State = false;
191+
187192
TestProfileWriter(ContextRoot *Root, size_t Entries)
188193
: Root(Root), Entries(Entries) {}
189194

190195
void writeContextual(const ContextNode &Node) override {
196+
EXPECT_EQ(EnteredSectionCount, 1);
197+
EXPECT_EQ(ExitedSectionCount, 0);
191198
EXPECT_FALSE(Root->Taken.TryLock());
192199
EXPECT_EQ(Node.guid(), 1U);
193200
EXPECT_EQ(Node.counters()[0], Entries);
@@ -205,7 +212,13 @@ TEST_F(ContextTest, Dump) {
205212
EXPECT_EQ(SN.subContexts()[0], nullptr);
206213
State = true;
207214
}
215+
void startContextSection() override { ++EnteredSectionCount; }
216+
void endContextSection() override {
217+
EXPECT_EQ(EnteredSectionCount, 1);
218+
++ExitedSectionCount;
219+
}
208220
};
221+
209222
TestProfileWriter W(&Root, 1);
210223
EXPECT_FALSE(W.State);
211224
__llvm_ctx_profile_fetch(W);
@@ -217,4 +230,6 @@ TEST_F(ContextTest, Dump) {
217230
EXPECT_FALSE(W2.State);
218231
__llvm_ctx_profile_fetch(W2);
219232
EXPECT_TRUE(W2.State);
233+
EXPECT_EQ(W2.EnteredSectionCount, 1);
234+
EXPECT_EQ(W2.ExitedSectionCount, 1);
220235
}

llvm/include/llvm/Analysis/CtxProfAnalysis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class PGOContextualProfile {
5454
return Profiles.Contexts;
5555
}
5656

57+
const PGOCtxProfile &profiles() const { return Profiles; }
58+
5759
bool isFunctionKnown(const Function &F) const {
5860
return getDefinedFunctionGUID(F) != 0;
5961
}

llvm/include/llvm/ProfileData/CtxInstrContextNode.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,14 @@ class ContextNode final {
114114
};
115115

116116
/// Abstraction for the parameter passed to `__llvm_ctx_profile_fetch`.
117+
/// `startContextSection` is called before any context roots are sent for
118+
/// writing. Then one or more `writeContextual` calls are made; finally,
119+
/// `endContextSection` is called.
117120
class ProfileWriter {
118121
public:
122+
virtual void startContextSection() = 0;
119123
virtual void writeContextual(const ctx_profile::ContextNode &RootNode) = 0;
124+
virtual void endContextSection() = 0;
120125
virtual ~ProfileWriter() = default;
121126
};
122127
} // namespace ctx_profile

llvm/include/llvm/ProfileData/PGOCtxProfReader.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,12 @@ class PGOCtxProfileReader final {
190190
Error unsupported(const Twine &);
191191

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

196200
public:
197201
PGOCtxProfileReader(StringRef Buffer)
@@ -201,7 +205,6 @@ class PGOCtxProfileReader final {
201205
Expected<PGOCtxProfile> loadProfiles();
202206
};
203207

204-
void convertCtxProfToYaml(raw_ostream &OS,
205-
const PGOCtxProfContext::CallTargetMapTy &);
208+
void convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &);
206209
} // namespace llvm
207210
#endif

llvm/include/llvm/ProfileData/PGOCtxProfWriter.h

Lines changed: 15 additions & 6 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,23 +62,30 @@ 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;
69+
const bool IncludeEmpty;
6570

66-
void writeCounters(const ctx_profile::ContextNode &Node);
71+
void writeGuid(ctx_profile::GUID Guid);
72+
void writeCounters(ArrayRef<uint64_t> Counters);
6773
void writeImpl(std::optional<uint32_t> CallerIndex,
6874
const ctx_profile::ContextNode &Node);
6975

7076
public:
7177
PGOCtxProfileWriter(raw_ostream &Out,
72-
std::optional<unsigned> VersionOverride = std::nullopt);
78+
std::optional<unsigned> VersionOverride = std::nullopt,
79+
bool IncludeEmpty = false);
7380
~PGOCtxProfileWriter() { Writer.ExitBlock(); }
7481

75-
void write(const ctx_profile::ContextNode &);
82+
void startContextSection() override;
83+
void writeContextual(const ctx_profile::ContextNode &RootNode) override;
84+
void endContextSection() override;
7685

7786
// constants used in writing which a reader may find useful.
7887
static constexpr unsigned CodeLen = 2;
79-
static constexpr uint32_t CurrentVersion = 1;
88+
static constexpr uint32_t CurrentVersion = 2;
8089
static constexpr unsigned VBREncodingBits = 6;
8190
static constexpr StringRef ContainerMagic = "CTXP";
8291
};

llvm/lib/Analysis/CtxProfAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ PreservedAnalyses CtxProfAnalysisPrinterPass::run(Module &M,
180180

181181
if (Mode == PrintMode::Everything)
182182
OS << "\nCurrent Profile:\n";
183-
convertCtxProfToYaml(OS, C.contexts());
183+
convertCtxProfToYaml(OS, C.profiles());
184184
OS << "\n";
185185
if (Mode == PrintMode::YAML)
186186
return PreservedAnalyses::all();

llvm/lib/ProfileData/PGOCtxProfReader.cpp

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "llvm/Support/Error.h"
2020
#include "llvm/Support/ErrorHandling.h"
2121
#include "llvm/Support/YAMLTraits.h"
22-
#include <iterator>
2322
#include <utility>
2423

2524
using namespace llvm;
@@ -58,26 +57,34 @@ Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
5857
return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
5958
}
6059

61-
bool PGOCtxProfileReader::canReadContext() {
60+
bool PGOCtxProfileReader::canEnterBlockWithID(PGOCtxProfileBlockIDs ID) {
6261
auto Blk = advance();
6362
if (!Blk) {
6463
consumeError(Blk.takeError());
6564
return false;
6665
}
67-
return Blk->Kind == BitstreamEntry::SubBlock &&
68-
Blk->ID == PGOCtxProfileBlockIDs::ContextNodeBlockID;
66+
return Blk->Kind == BitstreamEntry::SubBlock && Blk->ID == ID;
67+
}
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,15 +175,23 @@ Error PGOCtxProfileReader::readMetadata() {
168175
return Error::success();
169176
}
170177

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+
}
187+
}
188+
return Error::success();
189+
}
190+
171191
Expected<PGOCtxProfile> PGOCtxProfileReader::loadProfiles() {
172-
PGOCtxProfile Ret;
173192
RET_ON_ERR(readMetadata());
174-
while (canReadContext()) {
175-
EXPECT_OR_RET(E, readContext(false));
176-
auto Key = E->second.guid();
177-
if (!Ret.Contexts.insert({Key, std::move(E->second)}).second)
178-
return wrongValue("Duplicate roots");
179-
}
193+
PGOCtxProfile Ret;
194+
RET_ON_ERR(loadContexts(Ret.Contexts));
180195
return std::move(Ret);
181196
}
182197

@@ -224,41 +239,54 @@ void toYaml(yaml::Output &Out,
224239
Out.endSequence();
225240
}
226241

227-
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) {
228245
yaml::EmptyContext Empty;
229246
Out.beginMapping();
230247
void *SaveInfo = nullptr;
231248
bool UseDefault = false;
232249
{
233250
Out.preflightKey("Guid", /*Required=*/true, /*SameAsDefault=*/false,
234251
UseDefault, SaveInfo);
235-
auto Guid = Ctx.guid();
236252
yaml::yamlize(Out, Guid, true, Empty);
237253
Out.postflightKey(nullptr);
238254
}
239255
{
240256
Out.preflightKey("Counters", true, false, UseDefault, SaveInfo);
241257
Out.beginFlowSequence();
242-
for (size_t I = 0U, E = Ctx.counters().size(); I < E; ++I) {
258+
for (size_t I = 0U, E = Counters.size(); I < E; ++I) {
243259
Out.preflightFlowElement(I, SaveInfo);
244-
uint64_t V = Ctx.counters()[I];
260+
uint64_t V = Counters[I];
245261
yaml::yamlize(Out, V, true, Empty);
246262
Out.postflightFlowElement(SaveInfo);
247263
}
248264
Out.endFlowSequence();
249265
Out.postflightKey(nullptr);
250266
}
251-
if (!Ctx.callsites().empty()) {
267+
if (!Callsites.empty()) {
252268
Out.preflightKey("Callsites", true, false, UseDefault, SaveInfo);
253-
toYaml(Out, Ctx.callsites());
269+
toYaml(Out, Callsites);
254270
Out.postflightKey(nullptr);
255271
}
256272
Out.endMapping();
257273
}
274+
void toYaml(yaml::Output &Out, const PGOCtxProfContext &Ctx) {
275+
toYaml(Out, Ctx.guid(), Ctx.counters(), Ctx.callsites());
276+
}
277+
258278
} // namespace
259279

260-
void llvm::convertCtxProfToYaml(
261-
raw_ostream &OS, const PGOCtxProfContext::CallTargetMapTy &Profiles) {
280+
void llvm::convertCtxProfToYaml(raw_ostream &OS,
281+
const PGOCtxProfile &Profiles) {
262282
yaml::Output Out(OS);
263-
toYaml(Out, Profiles);
264-
}
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();
292+
}

0 commit comments

Comments
 (0)