diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h index f1010b312ee56..c250a9ede39bc 100644 --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -705,7 +705,8 @@ class IndexedMemProfReader { unsigned RadixTreeSize = 0; Error deserializeV2(const unsigned char *Start, const unsigned char *Ptr); - Error deserializeV3(const unsigned char *Start, const unsigned char *Ptr); + Error deserializeRadixTreeBased(const unsigned char *Start, + const unsigned char *Ptr); public: IndexedMemProfReader() = default; diff --git a/llvm/include/llvm/ProfileData/MemProf.h b/llvm/include/llvm/ProfileData/MemProf.h index e07a3189e4259..06d17438fa70f 100644 --- a/llvm/include/llvm/ProfileData/MemProf.h +++ b/llvm/include/llvm/ProfileData/MemProf.h @@ -35,10 +35,12 @@ enum IndexedVersion : uint64_t { // Version 3: Added a radix tree for call stacks. Switched to linear IDs for // frames and call stacks. Version3 = 3, + // Version 4: Added CalleeGuids to call site info. + Version4 = 4, }; constexpr uint64_t MinimumSupportedVersion = Version2; -constexpr uint64_t MaximumSupportedVersion = Version3; +constexpr uint64_t MaximumSupportedVersion = Version4; // Verify that the minimum and maximum satisfy the obvious constraint. static_assert(MinimumSupportedVersion <= MaximumSupportedVersion); diff --git a/llvm/include/llvm/ProfileData/MemProfYAML.h b/llvm/include/llvm/ProfileData/MemProfYAML.h index a3ca03eb92d2e..08dee253f615a 100644 --- a/llvm/include/llvm/ProfileData/MemProfYAML.h +++ b/llvm/include/llvm/ProfileData/MemProfYAML.h @@ -1,6 +1,7 @@ #ifndef LLVM_PROFILEDATA_MEMPROFYAML_H_ #define LLVM_PROFILEDATA_MEMPROFYAML_H_ +#include "llvm/ADT/SmallVector.h" #include "llvm/ProfileData/MemProf.h" #include "llvm/Support/Format.h" #include "llvm/Support/YAMLTraits.h" @@ -28,8 +29,9 @@ struct AllMemProfData { namespace yaml { template <> struct ScalarTraits { static void output(const memprof::GUIDHex64 &Val, void *, raw_ostream &Out) { - // Print GUID as a 16-digit hexadecimal number. - Out << format("0x%016" PRIx64, (uint64_t)Val); + // Print GUID as a hexadecimal number with 0x prefix, no padding to keep + // test strings compact. + Out << format("0x%" PRIx64, (uint64_t)Val); } static StringRef input(StringRef Scalar, void *, memprof::GUIDHex64 &Val) { // Reject decimal GUIDs. @@ -156,10 +158,43 @@ template <> struct MappingTraits { // treat the GUID and the fields within MemProfRecord at the same level as if // the GUID were part of MemProfRecord. template <> struct MappingTraits { + // Helper class to normalize CalleeGuids to use GUIDHex64 for YAML I/O. + class CallSiteInfoWithHex64Guids { + public: + CallSiteInfoWithHex64Guids(IO &) {} + CallSiteInfoWithHex64Guids(IO &, const memprof::CallSiteInfo &CS) + : Frames(CS.Frames) { + // Convert uint64_t GUIDs to GUIDHex64 for serialization. + CalleeGuids.reserve(CS.CalleeGuids.size()); + for (uint64_t Guid : CS.CalleeGuids) + CalleeGuids.push_back(memprof::GUIDHex64(Guid)); + } + + memprof::CallSiteInfo denormalize(IO &) { + memprof::CallSiteInfo CS; + CS.Frames = Frames; + // Convert GUIDHex64 back to uint64_t GUIDs after deserialization. + CS.CalleeGuids.reserve(CalleeGuids.size()); + for (memprof::GUIDHex64 HexGuid : CalleeGuids) + CS.CalleeGuids.push_back(HexGuid.value); + return CS; + } + + // Keep Frames as is, since MappingTraits handles its + // Function GUID. + decltype(memprof::CallSiteInfo::Frames) Frames; + // Use a vector of GUIDHex64 for CalleeGuids to leverage its ScalarTraits. + SmallVector CalleeGuids; + }; + static void mapping(IO &Io, memprof::CallSiteInfo &CS) { - Io.mapRequired("Frames", CS.Frames); - // Keep this optional to make it easier to write tests. - Io.mapOptional("CalleeGuids", CS.CalleeGuids); + // Use MappingNormalization to handle the conversion between + // memprof::CallSiteInfo and CallSiteInfoWithHex64Guids. + MappingNormalization + Keys(Io, CS); + Io.mapRequired("Frames", Keys->Frames); + // Map the normalized CalleeGuids (which are now GUIDHex64). + Io.mapOptional("CalleeGuids", Keys->CalleeGuids); } }; @@ -176,6 +211,20 @@ template <> struct MappingTraits { Io.mapRequired("HeapProfileRecords", Data.HeapProfileRecords); } }; + +template <> struct SequenceTraits> { + static size_t size(IO &io, SmallVector &Seq) { + return Seq.size(); + } + static memprof::GUIDHex64 & + element(IO &io, SmallVector &Seq, size_t Index) { + if (Index >= Seq.size()) + Seq.resize(Index + 1); + return Seq[Index]; + } + static const bool flow = true; +}; + } // namespace yaml } // namespace llvm @@ -184,5 +233,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(std::vector) LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::AllocationInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::CallSiteInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDMemProfRecordPair) +LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDHex64) // Used for CalleeGuids #endif // LLVM_PROFILEDATA_MEMPROFYAML_H_ diff --git a/llvm/lib/ProfileData/IndexedMemProfData.cpp b/llvm/lib/ProfileData/IndexedMemProfData.cpp index 5e78ffdb86d67..3d20f7a7a5778 100644 --- a/llvm/lib/ProfileData/IndexedMemProfData.cpp +++ b/llvm/lib/ProfileData/IndexedMemProfData.cpp @@ -214,23 +214,13 @@ static Error writeMemProfV2(ProfOStream &OS, return Error::success(); } -// Write out MemProf Version3 as follows: -// uint64_t Version -// uint64_t CallStackPayloadOffset = Offset for the call stack payload -// uint64_t RecordPayloadOffset = Offset for the record payload -// uint64_t RecordTableOffset = RecordTableGenerator.Emit -// uint64_t Num schema entries -// uint64_t Schema entry 0 -// uint64_t Schema entry 1 -// .... -// uint64_t Schema entry N - 1 -// Frames serialized one after another -// Call stacks encoded as a radix tree -// OnDiskChainedHashTable MemProfRecordData -static Error writeMemProfV3(ProfOStream &OS, - memprof::IndexedMemProfData &MemProfData, - bool MemProfFullSchema) { - OS.write(memprof::Version3); +static Error writeMemProfRadixTreeBased( + ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, + memprof::IndexedVersion Version, bool MemProfFullSchema) { + assert((Version == memprof::Version3 || Version == memprof::Version4) && + "Unsupported version for radix tree format"); + + OS.write(Version); // Write the specific version (V3 or V4) uint64_t HeaderUpdatePos = OS.tell(); OS.write(0ULL); // Reserve space for the memprof call stack payload offset. OS.write(0ULL); // Reserve space for the memprof record payload offset. @@ -258,13 +248,11 @@ static Error writeMemProfV3(ProfOStream &OS, NumElements); uint64_t RecordPayloadOffset = OS.tell(); - uint64_t RecordTableOffset = - writeMemProfRecords(OS, MemProfData.Records, &Schema, memprof::Version3, - &MemProfCallStackIndexes); + uint64_t RecordTableOffset = writeMemProfRecords( + OS, MemProfData.Records, &Schema, Version, &MemProfCallStackIndexes); - // IndexedMemProfReader::deserializeV3 computes the number of elements in the - // call stack array from the difference between CallStackPayloadOffset and - // RecordPayloadOffset. Verify that the computation works. + // Verify that the computation for the number of elements in the call stack + // array works. assert(CallStackPayloadOffset + NumElements * sizeof(memprof::LinearFrameId) == RecordPayloadOffset); @@ -279,6 +267,22 @@ static Error writeMemProfV3(ProfOStream &OS, return Error::success(); } +// Write out MemProf Version3 +static Error writeMemProfV3(ProfOStream &OS, + memprof::IndexedMemProfData &MemProfData, + bool MemProfFullSchema) { + return writeMemProfRadixTreeBased(OS, MemProfData, memprof::Version3, + MemProfFullSchema); +} + +// Write out MemProf Version4 +static Error writeMemProfV4(ProfOStream &OS, + memprof::IndexedMemProfData &MemProfData, + bool MemProfFullSchema) { + return writeMemProfRadixTreeBased(OS, MemProfData, memprof::Version4, + MemProfFullSchema); +} + // Write out the MemProf data in a requested version. Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, memprof::IndexedVersion MemProfVersionRequested, @@ -288,6 +292,8 @@ Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, return writeMemProfV2(OS, MemProfData, MemProfFullSchema); case memprof::Version3: return writeMemProfV3(OS, MemProfData, MemProfFullSchema); + case memprof::Version4: + return writeMemProfV4(OS, MemProfData, MemProfFullSchema); } return make_error( @@ -350,8 +356,8 @@ Error IndexedMemProfReader::deserializeV2(const unsigned char *Start, return Error::success(); } -Error IndexedMemProfReader::deserializeV3(const unsigned char *Start, - const unsigned char *Ptr) { +Error IndexedMemProfReader::deserializeRadixTreeBased( + const unsigned char *Start, const unsigned char *Ptr) { // The offset in the stream right before invoking // CallStackTableGenerator.Emit. const uint64_t CallStackPayloadOffset = @@ -382,7 +388,7 @@ Error IndexedMemProfReader::deserializeV3(const unsigned char *Start, MemProfRecordTable.reset(MemProfRecordHashTable::Create( /*Buckets=*/Start + RecordTableOffset, /*Payload=*/Start + RecordPayloadOffset, - /*Base=*/Start, memprof::RecordLookupTrait(memprof::Version3, Schema))); + /*Base=*/Start, memprof::RecordLookupTrait(Version, Schema))); return Error::success(); } @@ -395,8 +401,10 @@ Error IndexedMemProfReader::deserialize(const unsigned char *Start, const uint64_t FirstWord = support::endian::readNext(Ptr); - if (FirstWord == memprof::Version2 || FirstWord == memprof::Version3) { - // Everything is good. We can proceed to deserialize the rest. + // Check if the version is supported + if (FirstWord >= memprof::MinimumSupportedVersion && + FirstWord <= memprof::MaximumSupportedVersion) { + // Everything is good. We can proceed to deserialize the rest. Version = static_cast(FirstWord); } else { return make_error( @@ -413,12 +421,13 @@ Error IndexedMemProfReader::deserialize(const unsigned char *Start, return E; break; case memprof::Version3: - if (Error E = deserializeV3(Start, Ptr)) + case memprof::Version4: + // V3 and V4 share the same high-level structure (radix tree, linear IDs). + if (Error E = deserializeRadixTreeBased(Start, Ptr)) return E; break; } return Error::success(); } - } // namespace llvm diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index 295f2a633e6c7..e6c83430cd8e9 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -1456,16 +1456,6 @@ getMemProfRecordV2(const memprof::IndexedMemProfRecord &IndexedRecord, return Record; } -static Expected -getMemProfRecordV3(const memprof::IndexedMemProfRecord &IndexedRecord, - const unsigned char *FrameBase, - const unsigned char *CallStackBase) { - memprof::LinearFrameIdConverter FrameIdConv(FrameBase); - memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv); - memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv); - return Record; -} - Expected IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const { // TODO: Add memprof specific errors. @@ -1485,13 +1475,20 @@ IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const { assert(MemProfCallStackTable && "MemProfCallStackTable must be available"); return getMemProfRecordV2(IndexedRecord, *MemProfFrameTable, *MemProfCallStackTable); + // Combine V3 and V4 cases as the record conversion logic is the same. case memprof::Version3: + case memprof::Version4: assert(!MemProfFrameTable && "MemProfFrameTable must not be available"); assert(!MemProfCallStackTable && "MemProfCallStackTable must not be available"); assert(FrameBase && "FrameBase must be available"); assert(CallStackBase && "CallStackBase must be available"); - return getMemProfRecordV3(IndexedRecord, FrameBase, CallStackBase); + { + memprof::LinearFrameIdConverter FrameIdConv(FrameBase); + memprof::LinearCallStackIdConverter CSIdConv(CallStackBase, FrameIdConv); + memprof::MemProfRecord Record = IndexedRecord.toMemProfRecord(CSIdConv); + return Record; + } } return make_error( @@ -1505,7 +1502,7 @@ IndexedMemProfReader::getMemProfRecord(const uint64_t FuncNameHash) const { DenseMap> IndexedMemProfReader::getMemProfCallerCalleePairs() const { assert(MemProfRecordTable); - assert(Version == memprof::Version3); + assert(Version == memprof::Version3 || Version == memprof::Version4); memprof::LinearFrameIdConverter FrameIdConv(FrameBase); memprof::CallerCalleePairExtractor Extractor(CallStackBase, FrameIdConv, diff --git a/llvm/lib/ProfileData/MemProf.cpp b/llvm/lib/ProfileData/MemProf.cpp index 1e7d78005cd22..e497bbff67d2e 100644 --- a/llvm/lib/ProfileData/MemProf.cpp +++ b/llvm/lib/ProfileData/MemProf.cpp @@ -48,7 +48,9 @@ size_t IndexedAllocationInfo::serializedSize(const MemProfSchema &Schema, switch (Version) { case Version2: return serializedSizeV2(*this, Schema); + // Combine V3 and V4 as the size calculation is the same case Version3: + case Version4: return serializedSizeV3(*this, Schema); } llvm_unreachable("unsupported MemProf version"); @@ -78,10 +80,26 @@ static size_t serializedSizeV3(const IndexedMemProfRecord &Record, // The number of callsites we have information for. Result += sizeof(uint64_t); // The linear call stack ID. + // Note: V3 only stored the LinearCallStackId per call site. Result += Record.CallSites.size() * sizeof(LinearCallStackId); return Result; } +static size_t serializedSizeV4(const IndexedMemProfRecord &Record, + const MemProfSchema &Schema) { + // The number of alloc sites to serialize. + size_t Result = sizeof(uint64_t); + for (const IndexedAllocationInfo &N : Record.AllocSites) + Result += N.serializedSize(Schema, Version4); + + // The number of callsites we have information for. + Result += sizeof(uint64_t); + for (const auto &CS : Record.CallSites) + Result += sizeof(LinearCallStackId) + sizeof(uint64_t) + + CS.CalleeGuids.size() * sizeof(GlobalValue::GUID); + return Result; +} + size_t IndexedMemProfRecord::serializedSize(const MemProfSchema &Schema, IndexedVersion Version) const { switch (Version) { @@ -89,6 +107,8 @@ size_t IndexedMemProfRecord::serializedSize(const MemProfSchema &Schema, return serializedSizeV2(*this, Schema); case Version3: return serializedSizeV3(*this, Schema); + case Version4: + return serializedSizeV4(*this, Schema); } llvm_unreachable("unsupported MemProf version"); } @@ -134,6 +154,32 @@ static void serializeV3( } } +static void serializeV4( + const IndexedMemProfRecord &Record, const MemProfSchema &Schema, + raw_ostream &OS, + llvm::DenseMap &MemProfCallStackIndexes) { + using namespace support; + + endian::Writer LE(OS, llvm::endianness::little); + + LE.write(Record.AllocSites.size()); + for (const IndexedAllocationInfo &N : Record.AllocSites) { + assert(MemProfCallStackIndexes.contains(N.CSId)); + LE.write(MemProfCallStackIndexes[N.CSId]); + N.Info.serialize(Schema, OS); + } + + // Related contexts. + LE.write(Record.CallSites.size()); + for (const auto &CS : Record.CallSites) { + assert(MemProfCallStackIndexes.contains(CS.CSId)); + LE.write(MemProfCallStackIndexes[CS.CSId]); + LE.write(CS.CalleeGuids.size()); + for (const auto &Guid : CS.CalleeGuids) + LE.write(Guid); + } +} + void IndexedMemProfRecord::serialize( const MemProfSchema &Schema, raw_ostream &OS, IndexedVersion Version, llvm::DenseMap *MemProfCallStackIndexes) @@ -145,6 +191,9 @@ void IndexedMemProfRecord::serialize( case Version3: serializeV3(*this, Schema, OS, *MemProfCallStackIndexes); return; + case Version4: + serializeV4(*this, Schema, OS, *MemProfCallStackIndexes); + return; } llvm_unreachable("unsupported MemProf version"); } @@ -217,6 +266,47 @@ static IndexedMemProfRecord deserializeV3(const MemProfSchema &Schema, return Record; } +static IndexedMemProfRecord deserializeV4(const MemProfSchema &Schema, + const unsigned char *Ptr) { + using namespace support; + + IndexedMemProfRecord Record; + + // Read the meminfo nodes. + const uint64_t NumNodes = + endian::readNext(Ptr); + Record.AllocSites.reserve(NumNodes); + const size_t SerializedSize = PortableMemInfoBlock::serializedSize(Schema); + for (uint64_t I = 0; I < NumNodes; I++) { + IndexedAllocationInfo Node; + Node.CSId = + endian::readNext(Ptr); + Node.Info.deserialize(Schema, Ptr); + Ptr += SerializedSize; + Record.AllocSites.push_back(Node); + } + + // Read the callsite information. + const uint64_t NumCtxs = + endian::readNext(Ptr); + Record.CallSites.reserve(NumCtxs); + for (uint64_t J = 0; J < NumCtxs; J++) { + static_assert(sizeof(LinearCallStackId) <= sizeof(CallStackId)); + LinearCallStackId CSId = + endian::readNext(Ptr); + const uint64_t NumGuids = + endian::readNext(Ptr); + SmallVector Guids; + Guids.reserve(NumGuids); + for (uint64_t K = 0; K < NumGuids; ++K) + Guids.push_back( + endian::readNext(Ptr)); + Record.CallSites.emplace_back(CSId, std::move(Guids)); + } + + return Record; +} + IndexedMemProfRecord IndexedMemProfRecord::deserialize(const MemProfSchema &Schema, const unsigned char *Ptr, @@ -226,6 +316,8 @@ IndexedMemProfRecord::deserialize(const MemProfSchema &Schema, return deserializeV2(Schema, Ptr); case Version3: return deserializeV3(Schema, Ptr); + case Version4: + return deserializeV4(Schema, Ptr); } llvm_unreachable("unsupported MemProf version"); } diff --git a/llvm/test/tools/llvm-profdata/memprof-yaml.test b/llvm/test/tools/llvm-profdata/memprof-yaml.test index a72ef5925a844..9766cc50f37d7 100644 --- a/llvm/test/tools/llvm-profdata/memprof-yaml.test +++ b/llvm/test/tools/llvm-profdata/memprof-yaml.test @@ -1,10 +1,8 @@ ; RUN: split-file %s %t -; RUN: llvm-profdata merge %t/memprof-in.yaml -o %t/memprof-out.indexed +; COM: The text format only supports the latest version. +; RUN: llvm-profdata merge --memprof-version=4 %t/memprof-in.yaml -o %t/memprof-out.indexed ; RUN: llvm-profdata show --memory %t/memprof-out.indexed > %t/memprof-out.yaml -; RUN: cmp %t/memprof-in.yaml %t/memprof-out.yaml - -; This test is expected to fail until the profile format is updated to handle CalleeGuids. -; XFAIL: * +; RUN: diff -b %t/memprof-in.yaml %t/memprof-out.yaml ; Verify that the YAML output is identical to the YAML input. ;--- memprof-in.yaml @@ -32,9 +30,9 @@ HeapProfileRecords: - Frames: - { Function: 0x5555555555555555, LineOffset: 55, Column: 50, IsInlineFrame: true } - { Function: 0x6666666666666666, LineOffset: 66, Column: 60, IsInlineFrame: false } - CalleeGuids: [0x100, 0x200] + CalleeGuids: [ 0x100, 0x200 ] - Frames: - { Function: 0x7777777777777777, LineOffset: 77, Column: 70, IsInlineFrame: true } - { Function: 0x8888888888888888, LineOffset: 88, Column: 80, IsInlineFrame: false } - CalleeGuids: [0x300] + CalleeGuids: [ 0x300 ] ... diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 9a5d3f91d6256..885e06df6c390 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -336,7 +336,8 @@ static cl::opt MemProfVersionRequested( cl::desc("Specify the version of the memprof format to use"), cl::init(memprof::Version3), cl::values(clEnumValN(memprof::Version2, "2", "version 2"), - clEnumValN(memprof::Version3, "3", "version 3"))); + clEnumValN(memprof::Version3, "3", "version 3"), + clEnumValN(memprof::Version4, "4", "version 4"))); static cl::opt MemProfFullSchema( "memprof-full-schema", cl::Hidden, cl::sub(MergeSubcommand), diff --git a/llvm/unittests/ProfileData/MemProfTest.cpp b/llvm/unittests/ProfileData/MemProfTest.cpp index 3e430aa4eae58..ea36727df1bee 100644 --- a/llvm/unittests/ProfileData/MemProfTest.cpp +++ b/llvm/unittests/ProfileData/MemProfTest.cpp @@ -292,6 +292,51 @@ TEST(MemProf, RecordSerializationRoundTripVerion2) { EXPECT_EQ(Record, GotRecord); } +TEST(MemProf, RecordSerializationRoundTripVersion4) { + const auto Schema = getFullSchema(); + + MemInfoBlock Info(/*size=*/16, /*access_count=*/7, /*alloc_timestamp=*/1000, + /*dealloc_timestamp=*/2000, /*alloc_cpu=*/3, + /*dealloc_cpu=*/4, /*Histogram=*/0, /*HistogramSize=*/0); + + llvm::SmallVector CallStackIds = {0x123, 0x456}; + + llvm::SmallVector CallSites; + CallSites.push_back( + IndexedCallSiteInfo(0x333, {0xaaa, 0xbbb})); // CSId with GUIDs + CallSites.push_back(IndexedCallSiteInfo(0x444)); // CSId without GUIDs + + IndexedMemProfRecord Record; + for (const auto &CSId : CallStackIds) { + // Use the same info block for both allocation sites. + Record.AllocSites.emplace_back(CSId, Info); + } + Record.CallSites = std::move(CallSites); + + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + // Need a dummy map for V4 serialization + llvm::DenseMap DummyMap = { + {0x123, 1}, {0x456, 2}, {0x333, 3}, {0x444, 4}}; + Record.serialize(Schema, OS, Version4, &DummyMap); + + const IndexedMemProfRecord GotRecord = IndexedMemProfRecord::deserialize( + Schema, reinterpret_cast(Buffer.data()), Version4); + + // Create the expected record using the linear IDs from the dummy map. + IndexedMemProfRecord ExpectedRecord; + for (const auto &CSId : CallStackIds) { + ExpectedRecord.AllocSites.emplace_back(DummyMap[CSId], Info); + } + for (const auto &CSInfo : + Record.CallSites) { // Use original Record's CallSites to get GUIDs + ExpectedRecord.CallSites.emplace_back(DummyMap[CSInfo.CSId], + CSInfo.CalleeGuids); + } + + EXPECT_EQ(ExpectedRecord, GotRecord); +} + TEST(MemProf, RecordSerializationRoundTripVersion2HotColdSchema) { const auto Schema = getHotColdSchema(); @@ -791,7 +836,7 @@ TEST(MemProf, YAMLWriterFrame) { std::string Out = serializeInYAML(F); EXPECT_EQ(Out, R"YAML(--- -{ Function: 0x0123456789abcdef, LineOffset: 22, Column: 33, IsInlineFrame: true } +{ Function: 0x123456789abcdef, LineOffset: 22, Column: 33, IsInlineFrame: true } ... )YAML"); }