Skip to content

Commit 099a0fa

Browse files
authored
[MemProf] Add v4 which contains CalleeGuids to CallSiteInfo. (#137394)
This patch adds CalleeGuids to the serialized format and increments the version number to 4. The unit tests are updated to include a new test for v4 and the YAML format is also updated to be able to roundtrip the v4 format.
1 parent 36541ec commit 099a0fa

File tree

9 files changed

+253
-58
lines changed

9 files changed

+253
-58
lines changed

llvm/include/llvm/ProfileData/InstrProfReader.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,8 @@ class IndexedMemProfReader {
705705
unsigned RadixTreeSize = 0;
706706

707707
Error deserializeV2(const unsigned char *Start, const unsigned char *Ptr);
708-
Error deserializeV3(const unsigned char *Start, const unsigned char *Ptr);
708+
Error deserializeRadixTreeBased(const unsigned char *Start,
709+
const unsigned char *Ptr);
709710

710711
public:
711712
IndexedMemProfReader() = default;

llvm/include/llvm/ProfileData/MemProf.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@ enum IndexedVersion : uint64_t {
3535
// Version 3: Added a radix tree for call stacks. Switched to linear IDs for
3636
// frames and call stacks.
3737
Version3 = 3,
38+
// Version 4: Added CalleeGuids to call site info.
39+
Version4 = 4,
3840
};
3941

4042
constexpr uint64_t MinimumSupportedVersion = Version2;
41-
constexpr uint64_t MaximumSupportedVersion = Version3;
43+
constexpr uint64_t MaximumSupportedVersion = Version4;
4244

4345
// Verify that the minimum and maximum satisfy the obvious constraint.
4446
static_assert(MinimumSupportedVersion <= MaximumSupportedVersion);

llvm/include/llvm/ProfileData/MemProfYAML.h

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef LLVM_PROFILEDATA_MEMPROFYAML_H_
22
#define LLVM_PROFILEDATA_MEMPROFYAML_H_
33

4+
#include "llvm/ADT/SmallVector.h"
45
#include "llvm/ProfileData/MemProf.h"
56
#include "llvm/Support/Format.h"
67
#include "llvm/Support/YAMLTraits.h"
@@ -28,8 +29,9 @@ struct AllMemProfData {
2829
namespace yaml {
2930
template <> struct ScalarTraits<memprof::GUIDHex64> {
3031
static void output(const memprof::GUIDHex64 &Val, void *, raw_ostream &Out) {
31-
// Print GUID as a 16-digit hexadecimal number.
32-
Out << format("0x%016" PRIx64, (uint64_t)Val);
32+
// Print GUID as a hexadecimal number with 0x prefix, no padding to keep
33+
// test strings compact.
34+
Out << format("0x%" PRIx64, (uint64_t)Val);
3335
}
3436
static StringRef input(StringRef Scalar, void *, memprof::GUIDHex64 &Val) {
3537
// Reject decimal GUIDs.
@@ -156,10 +158,43 @@ template <> struct MappingTraits<memprof::AllocationInfo> {
156158
// treat the GUID and the fields within MemProfRecord at the same level as if
157159
// the GUID were part of MemProfRecord.
158160
template <> struct MappingTraits<memprof::CallSiteInfo> {
161+
// Helper class to normalize CalleeGuids to use GUIDHex64 for YAML I/O.
162+
class CallSiteInfoWithHex64Guids {
163+
public:
164+
CallSiteInfoWithHex64Guids(IO &) {}
165+
CallSiteInfoWithHex64Guids(IO &, const memprof::CallSiteInfo &CS)
166+
: Frames(CS.Frames) {
167+
// Convert uint64_t GUIDs to GUIDHex64 for serialization.
168+
CalleeGuids.reserve(CS.CalleeGuids.size());
169+
for (uint64_t Guid : CS.CalleeGuids)
170+
CalleeGuids.push_back(memprof::GUIDHex64(Guid));
171+
}
172+
173+
memprof::CallSiteInfo denormalize(IO &) {
174+
memprof::CallSiteInfo CS;
175+
CS.Frames = Frames;
176+
// Convert GUIDHex64 back to uint64_t GUIDs after deserialization.
177+
CS.CalleeGuids.reserve(CalleeGuids.size());
178+
for (memprof::GUIDHex64 HexGuid : CalleeGuids)
179+
CS.CalleeGuids.push_back(HexGuid.value);
180+
return CS;
181+
}
182+
183+
// Keep Frames as is, since MappingTraits<memprof::Frame> handles its
184+
// Function GUID.
185+
decltype(memprof::CallSiteInfo::Frames) Frames;
186+
// Use a vector of GUIDHex64 for CalleeGuids to leverage its ScalarTraits.
187+
SmallVector<memprof::GUIDHex64> CalleeGuids;
188+
};
189+
159190
static void mapping(IO &Io, memprof::CallSiteInfo &CS) {
160-
Io.mapRequired("Frames", CS.Frames);
161-
// Keep this optional to make it easier to write tests.
162-
Io.mapOptional("CalleeGuids", CS.CalleeGuids);
191+
// Use MappingNormalization to handle the conversion between
192+
// memprof::CallSiteInfo and CallSiteInfoWithHex64Guids.
193+
MappingNormalization<CallSiteInfoWithHex64Guids, memprof::CallSiteInfo>
194+
Keys(Io, CS);
195+
Io.mapRequired("Frames", Keys->Frames);
196+
// Map the normalized CalleeGuids (which are now GUIDHex64).
197+
Io.mapOptional("CalleeGuids", Keys->CalleeGuids);
163198
}
164199
};
165200

@@ -176,6 +211,20 @@ template <> struct MappingTraits<memprof::AllMemProfData> {
176211
Io.mapRequired("HeapProfileRecords", Data.HeapProfileRecords);
177212
}
178213
};
214+
215+
template <> struct SequenceTraits<SmallVector<memprof::GUIDHex64>> {
216+
static size_t size(IO &io, SmallVector<memprof::GUIDHex64> &Seq) {
217+
return Seq.size();
218+
}
219+
static memprof::GUIDHex64 &
220+
element(IO &io, SmallVector<memprof::GUIDHex64> &Seq, size_t Index) {
221+
if (Index >= Seq.size())
222+
Seq.resize(Index + 1);
223+
return Seq[Index];
224+
}
225+
static const bool flow = true;
226+
};
227+
179228
} // namespace yaml
180229
} // namespace llvm
181230

@@ -184,5 +233,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(std::vector<memprof::Frame>)
184233
LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::AllocationInfo)
185234
LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::CallSiteInfo)
186235
LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDMemProfRecordPair)
236+
LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDHex64) // Used for CalleeGuids
187237

188238
#endif // LLVM_PROFILEDATA_MEMPROFYAML_H_

llvm/lib/ProfileData/IndexedMemProfData.cpp

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -214,23 +214,13 @@ static Error writeMemProfV2(ProfOStream &OS,
214214
return Error::success();
215215
}
216216

217-
// Write out MemProf Version3 as follows:
218-
// uint64_t Version
219-
// uint64_t CallStackPayloadOffset = Offset for the call stack payload
220-
// uint64_t RecordPayloadOffset = Offset for the record payload
221-
// uint64_t RecordTableOffset = RecordTableGenerator.Emit
222-
// uint64_t Num schema entries
223-
// uint64_t Schema entry 0
224-
// uint64_t Schema entry 1
225-
// ....
226-
// uint64_t Schema entry N - 1
227-
// Frames serialized one after another
228-
// Call stacks encoded as a radix tree
229-
// OnDiskChainedHashTable MemProfRecordData
230-
static Error writeMemProfV3(ProfOStream &OS,
231-
memprof::IndexedMemProfData &MemProfData,
232-
bool MemProfFullSchema) {
233-
OS.write(memprof::Version3);
217+
static Error writeMemProfRadixTreeBased(
218+
ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
219+
memprof::IndexedVersion Version, bool MemProfFullSchema) {
220+
assert((Version == memprof::Version3 || Version == memprof::Version4) &&
221+
"Unsupported version for radix tree format");
222+
223+
OS.write(Version); // Write the specific version (V3 or V4)
234224
uint64_t HeaderUpdatePos = OS.tell();
235225
OS.write(0ULL); // Reserve space for the memprof call stack payload offset.
236226
OS.write(0ULL); // Reserve space for the memprof record payload offset.
@@ -258,13 +248,11 @@ static Error writeMemProfV3(ProfOStream &OS,
258248
NumElements);
259249

260250
uint64_t RecordPayloadOffset = OS.tell();
261-
uint64_t RecordTableOffset =
262-
writeMemProfRecords(OS, MemProfData.Records, &Schema, memprof::Version3,
263-
&MemProfCallStackIndexes);
251+
uint64_t RecordTableOffset = writeMemProfRecords(
252+
OS, MemProfData.Records, &Schema, Version, &MemProfCallStackIndexes);
264253

265-
// IndexedMemProfReader::deserializeV3 computes the number of elements in the
266-
// call stack array from the difference between CallStackPayloadOffset and
267-
// RecordPayloadOffset. Verify that the computation works.
254+
// Verify that the computation for the number of elements in the call stack
255+
// array works.
268256
assert(CallStackPayloadOffset +
269257
NumElements * sizeof(memprof::LinearFrameId) ==
270258
RecordPayloadOffset);
@@ -279,6 +267,22 @@ static Error writeMemProfV3(ProfOStream &OS,
279267
return Error::success();
280268
}
281269

270+
// Write out MemProf Version3
271+
static Error writeMemProfV3(ProfOStream &OS,
272+
memprof::IndexedMemProfData &MemProfData,
273+
bool MemProfFullSchema) {
274+
return writeMemProfRadixTreeBased(OS, MemProfData, memprof::Version3,
275+
MemProfFullSchema);
276+
}
277+
278+
// Write out MemProf Version4
279+
static Error writeMemProfV4(ProfOStream &OS,
280+
memprof::IndexedMemProfData &MemProfData,
281+
bool MemProfFullSchema) {
282+
return writeMemProfRadixTreeBased(OS, MemProfData, memprof::Version4,
283+
MemProfFullSchema);
284+
}
285+
282286
// Write out the MemProf data in a requested version.
283287
Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
284288
memprof::IndexedVersion MemProfVersionRequested,
@@ -288,6 +292,8 @@ Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
288292
return writeMemProfV2(OS, MemProfData, MemProfFullSchema);
289293
case memprof::Version3:
290294
return writeMemProfV3(OS, MemProfData, MemProfFullSchema);
295+
case memprof::Version4:
296+
return writeMemProfV4(OS, MemProfData, MemProfFullSchema);
291297
}
292298

293299
return make_error<InstrProfError>(
@@ -350,8 +356,8 @@ Error IndexedMemProfReader::deserializeV2(const unsigned char *Start,
350356
return Error::success();
351357
}
352358

353-
Error IndexedMemProfReader::deserializeV3(const unsigned char *Start,
354-
const unsigned char *Ptr) {
359+
Error IndexedMemProfReader::deserializeRadixTreeBased(
360+
const unsigned char *Start, const unsigned char *Ptr) {
355361
// The offset in the stream right before invoking
356362
// CallStackTableGenerator.Emit.
357363
const uint64_t CallStackPayloadOffset =
@@ -382,7 +388,7 @@ Error IndexedMemProfReader::deserializeV3(const unsigned char *Start,
382388
MemProfRecordTable.reset(MemProfRecordHashTable::Create(
383389
/*Buckets=*/Start + RecordTableOffset,
384390
/*Payload=*/Start + RecordPayloadOffset,
385-
/*Base=*/Start, memprof::RecordLookupTrait(memprof::Version3, Schema)));
391+
/*Base=*/Start, memprof::RecordLookupTrait(Version, Schema)));
386392

387393
return Error::success();
388394
}
@@ -395,8 +401,10 @@ Error IndexedMemProfReader::deserialize(const unsigned char *Start,
395401
const uint64_t FirstWord =
396402
support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
397403

398-
if (FirstWord == memprof::Version2 || FirstWord == memprof::Version3) {
399-
// Everything is good. We can proceed to deserialize the rest.
404+
// Check if the version is supported
405+
if (FirstWord >= memprof::MinimumSupportedVersion &&
406+
FirstWord <= memprof::MaximumSupportedVersion) {
407+
// Everything is good. We can proceed to deserialize the rest.
400408
Version = static_cast<memprof::IndexedVersion>(FirstWord);
401409
} else {
402410
return make_error<InstrProfError>(
@@ -413,12 +421,13 @@ Error IndexedMemProfReader::deserialize(const unsigned char *Start,
413421
return E;
414422
break;
415423
case memprof::Version3:
416-
if (Error E = deserializeV3(Start, Ptr))
424+
case memprof::Version4:
425+
// V3 and V4 share the same high-level structure (radix tree, linear IDs).
426+
if (Error E = deserializeRadixTreeBased(Start, Ptr))
417427
return E;
418428
break;
419429
}
420430

421431
return Error::success();
422432
}
423-
424433
} // namespace llvm

llvm/lib/ProfileData/InstrProfReader.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,16 +1456,6 @@ getMemProfRecordV2(const memprof::IndexedMemProfRecord &IndexedRecord,
14561456
return Record;
14571457
}
14581458

1459-
static Expected<memprof::MemProfRecord>
1460-
getMemProfRecordV3(const memprof::IndexedMemProfRecord &IndexedRecord,
1461-
const unsigned char *FrameBase,
1462-
const unsigned char *CallStackBase) {
1463-
memprof::LinearFrameIdConverter FrameIdConv(FrameBase);
1464-
memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv);
1465-
memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv);
1466-
return Record;
1467-
}
1468-
14691459
Expected<memprof::MemProfRecord>
14701460
IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const {
14711461
// TODO: Add memprof specific errors.
@@ -1485,13 +1475,20 @@ IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const {
14851475
assert(MemProfCallStackTable && "MemProfCallStackTable must be available");
14861476
return getMemProfRecordV2(IndexedRecord, *MemProfFrameTable,
14871477
*MemProfCallStackTable);
1478+
// Combine V3 and V4 cases as the record conversion logic is the same.
14881479
case memprof::Version3:
1480+
case memprof::Version4:
14891481
assert(!MemProfFrameTable && "MemProfFrameTable must not be available");
14901482
assert(!MemProfCallStackTable &&
14911483
"MemProfCallStackTable must not be available");
14921484
assert(FrameBase && "FrameBase must be available");
14931485
assert(CallStackBase && "CallStackBase must be available");
1494-
return getMemProfRecordV3(IndexedRecord, FrameBase, CallStackBase);
1486+
{
1487+
memprof::LinearFrameIdConverter FrameIdConv(FrameBase);
1488+
memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv);
1489+
memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv);
1490+
return Record;
1491+
}
14951492
}
14961493

14971494
return make_error<InstrProfError>(
@@ -1505,7 +1502,7 @@ IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const {
15051502
DenseMap<uint64_t, SmallVector<memprof::CallEdgeTy, 0>>
15061503
IndexedMemProfReader::getMemProfCallerCalleePairs() const {
15071504
assert(MemProfRecordTable);
1508-
assert(Version == memprof::Version3);
1505+
assert(Version == memprof::Version3 || Version == memprof::Version4);
15091506

15101507
memprof::LinearFrameIdConverter FrameIdConv(FrameBase);
15111508
memprof::CallerCalleePairExtractor Extractor(CallStackBase, FrameIdConv,

0 commit comments

Comments
 (0)