Skip to content

Commit c8fd7a8

Browse files
authored
[ctxprof] Profile section for flat profiles (llvm#129932)
A section for flat profiles (i.e. non-contextual). This is useful for debugging or for intentional cases where a root isn't identified. This patch adds the reader/writer support. `compiler-rt` changes follow in a subsequent change.
1 parent 3664b4e commit c8fd7a8

File tree

11 files changed

+190
-14
lines changed

11 files changed

+190
-14
lines changed

llvm/include/llvm/ProfileData/PGOCtxProfReader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ using CtxProfContextualProfiles =
174174
std::map<GlobalValue::GUID, PGOCtxProfContext>;
175175
struct PGOCtxProfile {
176176
CtxProfContextualProfiles Contexts;
177+
CtxProfFlatProfile FlatProfiles;
177178

178179
PGOCtxProfile() = default;
179180
PGOCtxProfile(const PGOCtxProfile &) = delete;
@@ -192,10 +193,12 @@ class PGOCtxProfileReader final {
192193
Expected<std::pair<std::optional<uint32_t>, PGOCtxProfContext>>
193194
readProfile(PGOCtxProfileBlockIDs Kind);
194195

196+
bool tryGetNextKnownBlockID(PGOCtxProfileBlockIDs &ID);
195197
bool canEnterBlockWithID(PGOCtxProfileBlockIDs ID);
196198
Error enterBlockWithID(PGOCtxProfileBlockIDs ID);
197199

198200
Error loadContexts(CtxProfContextualProfiles &P);
201+
Error loadFlatProfiles(CtxProfFlatProfile &P);
199202

200203
public:
201204
PGOCtxProfileReader(StringRef Buffer)

llvm/include/llvm/ProfileData/PGOCtxProfWriter.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@ namespace llvm {
2222
enum PGOCtxProfileRecords { Invalid = 0, Version, Guid, CalleeIndex, Counters };
2323

2424
enum PGOCtxProfileBlockIDs {
25-
ProfileMetadataBlockID = bitc::FIRST_APPLICATION_BLOCKID,
25+
FIRST_VALID = bitc::FIRST_APPLICATION_BLOCKID,
26+
ProfileMetadataBlockID = FIRST_VALID,
2627
ContextsSectionBlockID = ProfileMetadataBlockID + 1,
2728
ContextRootBlockID = ContextsSectionBlockID + 1,
2829
ContextNodeBlockID = ContextRootBlockID + 1,
30+
FlatProfilesSectionBlockID = ContextNodeBlockID + 1,
31+
FlatProfileBlockID = FlatProfilesSectionBlockID + 1,
32+
LAST_VALID = FlatProfileBlockID
2933
};
3034

3135
/// Write one or more ContextNodes to the provided raw_fd_stream.
@@ -83,6 +87,11 @@ class PGOCtxProfileWriter final : public ctx_profile::ProfileWriter {
8387
void writeContextual(const ctx_profile::ContextNode &RootNode) override;
8488
void endContextSection() override;
8589

90+
void startFlatSection();
91+
void writeFlatSection(ctx_profile::GUID Guid, const uint64_t *Buffer,
92+
size_t BufferSize);
93+
void endFlatSection();
94+
8695
// constants used in writing which a reader may find useful.
8796
static constexpr unsigned CodeLen = 2;
8897
static constexpr uint32_t CurrentVersion = 2;

llvm/lib/ProfileData/PGOCtxProfReader.cpp

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,24 +57,39 @@ Error PGOCtxProfileReader::unsupported(const Twine &Msg) {
5757
return make_error<InstrProfError>(instrprof_error::unsupported_version, Msg);
5858
}
5959

60-
bool PGOCtxProfileReader::canEnterBlockWithID(PGOCtxProfileBlockIDs ID) {
60+
bool PGOCtxProfileReader::tryGetNextKnownBlockID(PGOCtxProfileBlockIDs &ID) {
6161
auto Blk = advance();
6262
if (!Blk) {
6363
consumeError(Blk.takeError());
6464
return false;
6565
}
66-
return Blk->Kind == BitstreamEntry::SubBlock && Blk->ID == ID;
66+
if (Blk->Kind != BitstreamEntry::SubBlock)
67+
return false;
68+
if (PGOCtxProfileBlockIDs::FIRST_VALID > Blk->ID ||
69+
PGOCtxProfileBlockIDs::LAST_VALID < Blk->ID)
70+
return false;
71+
ID = static_cast<PGOCtxProfileBlockIDs>(Blk->ID);
72+
return true;
73+
}
74+
75+
bool PGOCtxProfileReader::canEnterBlockWithID(PGOCtxProfileBlockIDs ID) {
76+
PGOCtxProfileBlockIDs Test = {};
77+
return tryGetNextKnownBlockID(Test) && Test == ID;
6778
}
6879

6980
Error PGOCtxProfileReader::enterBlockWithID(PGOCtxProfileBlockIDs ID) {
7081
RET_ON_ERR(Cursor.EnterSubBlock(ID));
7182
return Error::success();
7283
}
7384

85+
// Note: we use PGOCtxProfContext for flat profiles also, as the latter are
86+
// structurally similar. Alternative modeling here seems a bit overkill at the
87+
// moment.
7488
Expected<std::pair<std::optional<uint32_t>, PGOCtxProfContext>>
7589
PGOCtxProfileReader::readProfile(PGOCtxProfileBlockIDs Kind) {
7690
assert((Kind == PGOCtxProfileBlockIDs::ContextRootBlockID ||
77-
Kind == PGOCtxProfileBlockIDs::ContextNodeBlockID) &&
91+
Kind == PGOCtxProfileBlockIDs::ContextNodeBlockID ||
92+
Kind == PGOCtxProfileBlockIDs::FlatProfileBlockID) &&
7893
"Unexpected profile kind");
7994
RET_ON_ERR(enterBlockWithID(Kind));
8095

@@ -176,22 +191,44 @@ Error PGOCtxProfileReader::readMetadata() {
176191
}
177192

178193
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-
}
194+
RET_ON_ERR(enterBlockWithID(PGOCtxProfileBlockIDs::ContextsSectionBlockID));
195+
while (canEnterBlockWithID(PGOCtxProfileBlockIDs::ContextRootBlockID)) {
196+
EXPECT_OR_RET(E, readProfile(PGOCtxProfileBlockIDs::ContextRootBlockID));
197+
auto Key = E->second.guid();
198+
if (!P.insert({Key, std::move(E->second)}).second)
199+
return wrongValue("Duplicate roots");
200+
}
201+
return Error::success();
202+
}
203+
204+
Error PGOCtxProfileReader::loadFlatProfiles(CtxProfFlatProfile &P) {
205+
RET_ON_ERR(
206+
enterBlockWithID(PGOCtxProfileBlockIDs::FlatProfilesSectionBlockID));
207+
while (canEnterBlockWithID(PGOCtxProfileBlockIDs::FlatProfileBlockID)) {
208+
EXPECT_OR_RET(E, readProfile(PGOCtxProfileBlockIDs::FlatProfileBlockID));
209+
auto Guid = E->second.guid();
210+
if (!P.insert({Guid, std::move(E->second.counters())}).second)
211+
return wrongValue("Duplicate flat profile entries");
187212
}
188213
return Error::success();
189214
}
190215

191216
Expected<PGOCtxProfile> PGOCtxProfileReader::loadProfiles() {
192217
RET_ON_ERR(readMetadata());
193218
PGOCtxProfile Ret;
194-
RET_ON_ERR(loadContexts(Ret.Contexts));
219+
PGOCtxProfileBlockIDs Test = {};
220+
for (auto I = 0; I < 2; ++I) {
221+
if (!tryGetNextKnownBlockID(Test))
222+
break;
223+
if (Test == PGOCtxProfileBlockIDs::ContextsSectionBlockID) {
224+
RET_ON_ERR(loadContexts(Ret.Contexts));
225+
} else if (Test == PGOCtxProfileBlockIDs::FlatProfilesSectionBlockID) {
226+
RET_ON_ERR(loadFlatProfiles(Ret.FlatProfiles));
227+
} else {
228+
return wrongValue("Unexpected section");
229+
}
230+
}
231+
195232
return std::move(Ret);
196233
}
197234

@@ -287,5 +324,17 @@ void llvm::convertCtxProfToYaml(raw_ostream &OS, const PGOCtxProfile &Profile) {
287324
toYaml(Out, Profile.Contexts);
288325
Out.postflightKey(nullptr);
289326
}
327+
if (!Profile.FlatProfiles.empty()) {
328+
Out.preflightKey("FlatProfiles", false, false, UseDefault, SaveInfo);
329+
Out.beginSequence();
330+
size_t ElemID = 0;
331+
for (const auto &[Guid, Counters] : Profile.FlatProfiles) {
332+
Out.preflightElement(ElemID++, SaveInfo);
333+
toYaml(Out, Guid, Counters, {});
334+
Out.postflightElement(nullptr);
335+
}
336+
Out.endSequence();
337+
Out.postflightKey(nullptr);
338+
}
290339
Out.endMapping();
291340
}

llvm/lib/ProfileData/PGOCtxProfWriter.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/ProfileData/PGOCtxProfWriter.h"
1414
#include "llvm/Bitstream/BitCodeEnums.h"
1515
#include "llvm/ProfileData/CtxInstrContextNode.h"
16+
#include "llvm/ProfileData/PGOCtxProfReader.h"
1617
#include "llvm/Support/CommandLine.h"
1718
#include "llvm/Support/Error.h"
1819
#include "llvm/Support/YAMLTraits.h"
@@ -59,6 +60,11 @@ PGOCtxProfileWriter::PGOCtxProfileWriter(
5960
DescribeRecord(PGOCtxProfileRecords::Guid, "GUID");
6061
DescribeRecord(PGOCtxProfileRecords::CalleeIndex, "CalleeIndex");
6162
DescribeRecord(PGOCtxProfileRecords::Counters, "Counters");
63+
DescribeBlock(PGOCtxProfileBlockIDs::FlatProfilesSectionBlockID,
64+
"FlatProfiles");
65+
DescribeBlock(PGOCtxProfileBlockIDs::FlatProfileBlockID, "Flat");
66+
DescribeRecord(PGOCtxProfileRecords::Guid, "GUID");
67+
DescribeRecord(PGOCtxProfileRecords::Counters, "Counters");
6268
}
6369
Writer.ExitBlock();
6470
Writer.EnterSubblock(PGOCtxProfileBlockIDs::ProfileMetadataBlockID, CodeLen);
@@ -108,12 +114,27 @@ void PGOCtxProfileWriter::startContextSection() {
108114
Writer.EnterSubblock(PGOCtxProfileBlockIDs::ContextsSectionBlockID, CodeLen);
109115
}
110116

117+
void PGOCtxProfileWriter::startFlatSection() {
118+
Writer.EnterSubblock(PGOCtxProfileBlockIDs::FlatProfilesSectionBlockID,
119+
CodeLen);
120+
}
121+
111122
void PGOCtxProfileWriter::endContextSection() { Writer.ExitBlock(); }
123+
void PGOCtxProfileWriter::endFlatSection() { Writer.ExitBlock(); }
112124

113125
void PGOCtxProfileWriter::writeContextual(const ContextNode &RootNode) {
114126
writeImpl(std::nullopt, RootNode);
115127
}
116128

129+
void PGOCtxProfileWriter::writeFlatSection(ctx_profile::GUID Guid,
130+
const uint64_t *Buffer,
131+
size_t Size) {
132+
Writer.EnterSubblock(PGOCtxProfileBlockIDs::FlatProfileBlockID, CodeLen);
133+
writeGuid(Guid);
134+
writeCounters({Buffer, Size});
135+
Writer.ExitBlock();
136+
}
137+
117138
namespace {
118139

119140
/// Representation of the context node suitable for yaml serialization /
@@ -123,8 +144,13 @@ struct SerializableCtxRepresentation {
123144
std::vector<uint64_t> Counters;
124145
std::vector<std::vector<SerializableCtxRepresentation>> Callsites;
125146
};
147+
148+
using SerializableFlatProfileRepresentation =
149+
std::pair<ctx_profile::GUID, std::vector<uint64_t>>;
150+
126151
struct SerializableProfileRepresentation {
127152
std::vector<SerializableCtxRepresentation> Contexts;
153+
std::vector<SerializableFlatProfileRepresentation> FlatProfiles;
128154
};
129155

130156
ctx_profile::ContextNode *
@@ -164,6 +190,7 @@ createNode(std::vector<std::unique_ptr<char[]>> &Nodes,
164190

165191
LLVM_YAML_IS_SEQUENCE_VECTOR(SerializableCtxRepresentation)
166192
LLVM_YAML_IS_SEQUENCE_VECTOR(std::vector<SerializableCtxRepresentation>)
193+
LLVM_YAML_IS_SEQUENCE_VECTOR(SerializableFlatProfileRepresentation)
167194
template <> struct yaml::MappingTraits<SerializableCtxRepresentation> {
168195
static void mapping(yaml::IO &IO, SerializableCtxRepresentation &SCR) {
169196
IO.mapRequired("Guid", SCR.Guid);
@@ -175,6 +202,15 @@ template <> struct yaml::MappingTraits<SerializableCtxRepresentation> {
175202
template <> struct yaml::MappingTraits<SerializableProfileRepresentation> {
176203
static void mapping(yaml::IO &IO, SerializableProfileRepresentation &SPR) {
177204
IO.mapOptional("Contexts", SPR.Contexts);
205+
IO.mapOptional("FlatProfiles", SPR.FlatProfiles);
206+
}
207+
};
208+
209+
template <> struct yaml::MappingTraits<SerializableFlatProfileRepresentation> {
210+
static void mapping(yaml::IO &IO,
211+
SerializableFlatProfileRepresentation &SFPR) {
212+
IO.mapRequired("Guid", SFPR.first);
213+
IO.mapRequired("Counters", SFPR.second);
178214
}
179215
};
180216

@@ -201,6 +237,12 @@ Error llvm::createCtxProfFromYAML(StringRef Profile, raw_ostream &Out) {
201237
}
202238
Writer.endContextSection();
203239
}
240+
if (!SPR.FlatProfiles.empty()) {
241+
Writer.startFlatSection();
242+
for (const auto &[Guid, Counters] : SPR.FlatProfiles)
243+
Writer.writeFlatSection(Guid, Counters.data(), Counters.size());
244+
Writer.endFlatSection();
245+
}
204246
if (EC)
205247
return createStringError(EC, "failed to write output");
206248
return Error::success();
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FlatProfiles:
2+
- Guid: 1
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
Contexts:
3+
- Guid: 1000
4+
Counters: [ 1, 2, 3 ]
5+
Callsites:
6+
- [ ]
7+
- - Guid: 2000
8+
Counters: [ 4, 5 ]
9+
- Guid: 18446744073709551613
10+
Counters: [ 6, 7, 8 ]
11+
- - Guid: 3000
12+
Counters: [ 40, 50 ]
13+
- Guid: 18446744073709551612
14+
Counters: [ 5, 9, 10 ]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
FlatProfiles:
3+
- Guid: 1234
4+
Counters: [ 5, 6, 7 ]
5+
- Guid: 5555
6+
Counters: [ 1 ]
7+
Contexts:
8+
- Guid: 1000
9+
Counters: [ 1, 2, 3 ]
10+
Callsites:
11+
- [ ]
12+
- - Guid: 2000
13+
Counters: [ 4, 5 ]
14+
- Guid: 18446744073709551613
15+
Counters: [ 6, 7, 8 ]
16+
- - Guid: 3000
17+
Counters: [ 40, 50 ]
18+
- Guid: 18446744073709551612
19+
Counters: [ 5, 9, 10 ]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
FlatProfiles:
3+
- Guid: 1234
4+
Counters: [ 5, 6, 7 ]
5+
- Guid: 5555
6+
Counters: [ 1 ]

llvm/test/tools/llvm-ctxprof-util/Inputs/valid.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,8 @@ Contexts:
1212
Counters: [ 40, 50 ]
1313
- Guid: 18446744073709551612
1414
Counters: [ 5, 9, 10 ]
15+
FlatProfiles:
16+
- Guid: 1234
17+
Counters: [ 5, 6, 7 ]
18+
- Guid: 5555
19+
Counters: [ 1 ]

llvm/test/tools/llvm-ctxprof-util/llvm-ctxprof-util-negative.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-no-ctx.yaml 2>&1 | FileCheck %s --check-prefix=NO_CTX
1010
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-no-counters.yaml 2>&1 | FileCheck %s --check-prefix=NO_COUNTERS
1111
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-bad-subctx.yaml 2>&1 | FileCheck %s --check-prefix=BAD_SUBCTX
12+
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/invalid-flat.yaml 2>&1 | FileCheck %s --check-prefix=BAD_FLAT
1213
; RUN: rm -rf %t
1314
; RUN: not llvm-ctxprof-util fromYAML --input %S/Inputs/valid.yaml --output %t/output.bitstream 2>&1 | FileCheck %s --check-prefix=NO_DIR
1415

@@ -21,4 +22,5 @@
2122
; NO_CTX: YAML:1:1: error: not a mapping
2223
; NO_COUNTERS: YAML:2:5: error: missing required key 'Counters'
2324
; BAD_SUBCTX: YAML:4:18: error: not a sequence
25+
; BAD_FLAT: YAML:2:5: error: missing required key 'Counters'
2426
; NO_DIR: failed to open output

llvm/test/tools/llvm-ctxprof-util/llvm-ctxprof-util.test

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
; RUN: llvm-ctxprof-util toYAML -input %t/valid.bitstream -output %t/valid2.yaml
99
; RUN: diff %t/valid2.yaml %S/Inputs/valid.yaml
1010

11+
12+
; RUN: llvm-ctxprof-util fromYAML -input %S/Inputs/valid-ctx-only.yaml -output %t/valid-ctx-only.bitstream
13+
; RUN: llvm-ctxprof-util toYAML -input %t/valid-ctx-only.bitstream -output %t/valid-ctx-only.yaml
14+
; RUN: diff %t/valid-ctx-only.yaml %S/Inputs/valid-ctx-only.yaml
15+
16+
; RUN: llvm-ctxprof-util fromYAML -input %S/Inputs/valid-flat-only.yaml -output %t/valid-flat-only.bitstream
17+
; RUN: llvm-ctxprof-util toYAML -input %t/valid-flat-only.bitstream -output %t/valid-flat-only.yaml
18+
; RUN: diff %t/valid-flat-only.yaml %S/Inputs/valid-flat-only.yaml
19+
20+
; This case is the "valid.yaml" case but with the flat profile first.
21+
; The output, though, should match valid.yaml
22+
; RUN: llvm-ctxprof-util fromYAML -input %S/Inputs/valid-flat-first.yaml -output %t/valid-flat-first.bitstream
23+
; RUN: llvm-ctxprof-util toYAML -input %t/valid-flat-first.bitstream -output %t/valid-flat-first.yaml
24+
; RUN: diff %t/valid-flat-first.yaml %S/Inputs/valid.yaml
25+
1126
; For the valid case, check against a reference output.
1227
; Note that uint64_t are printed as signed values by llvm-bcanalyzer:
1328
; * 18446744073709551613 in yaml is -3 in the output
@@ -22,7 +37,7 @@
2237
; EMPTY-NEXT: </Metadata>
2338

2439
; VALID: <BLOCKINFO_BLOCK/>
25-
; VALID-NEXT: <Metadata NumWords=33 BlockCodeSize=2>
40+
; VALID-NEXT: <Metadata NumWords=45 BlockCodeSize=2>
2641
; VALID-NEXT: <Version op0=2/>
2742
; VALID-NEXT: <Contexts NumWords=29 BlockCodeSize=2>
2843
; VALID-NEXT: <Root NumWords=20 BlockCodeSize=2>
@@ -49,4 +64,14 @@
4964
; VALID-NEXT: <Counters op0=5 op1=9 op2=10/>
5065
; VALID-NEXT: </Root>
5166
; VALID-NEXT: </Contexts>
67+
; VALID-NEXT: <FlatProfiles NumWords=10 BlockCodeSize=2>
68+
; VALID-NEXT: <Flat NumWords=3 BlockCodeSize=2>
69+
; VALID-NEXT: <GUID op0=1234/>
70+
; VALID-NEXT: <Counters op0=5 op1=6 op2=7/>
71+
; VALID-NEXT: </Flat>
72+
; VALID-NEXT: <Flat NumWords=2 BlockCodeSize=2>
73+
; VALID-NEXT: <GUID op0=5555/>
74+
; VALID-NEXT: <Counters op0=1/>
75+
; VALID-NEXT: </Flat>
76+
; VALID-NEXT: </FlatProfiles>
5277
; VALID-NEXT: </Metadata>

0 commit comments

Comments
 (0)