diff options
author | Kazu Hirata <kazu@google.com> | 2024-04-18 14:12:58 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-18 14:12:58 -0700 |
commit | 172f6ddfa7662a36e3a41db6bb944f7d72fd0b00 (patch) | |
tree | 57e5d885aeda67aa160c2134ebdce099d09d5c14 /llvm/unittests/ProfileData/InstrProfTest.cpp | |
parent | 7aad1ee70f2c6be603707ff52a13e0e22330e859 (diff) | |
download | llvm-172f6ddfa7662a36e3a41db6bb944f7d72fd0b00.zip llvm-172f6ddfa7662a36e3a41db6bb944f7d72fd0b00.tar.gz llvm-172f6ddfa7662a36e3a41db6bb944f7d72fd0b00.tar.bz2 |
[memprof] Add Version2 of the indexed MemProf format (#89100)
This patch adds Version2 of the indexed MemProf format. The new
format comes with a hash table from CallStackId to actual call stacks
llvm::SmallVector<FrameId>. The rest of the format refers to call
stacks with CallStackId. This "values + references" model effectively
deduplicates call stacks. Without this patch, a large indexed memprof
file of mine shrinks from 4.4GB to 1.6GB, a 64% reduction.
This patch does not make Version2 generally available yet as I am
planning to make a few more changes to the format.
Diffstat (limited to 'llvm/unittests/ProfileData/InstrProfTest.cpp')
-rw-r--r-- | llvm/unittests/ProfileData/InstrProfTest.cpp | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/llvm/unittests/ProfileData/InstrProfTest.cpp b/llvm/unittests/ProfileData/InstrProfTest.cpp index 82701c4..16b8b50 100644 --- a/llvm/unittests/ProfileData/InstrProfTest.cpp +++ b/llvm/unittests/ProfileData/InstrProfTest.cpp @@ -347,6 +347,9 @@ using ::llvm::memprof::IndexedMemProfRecord; using ::llvm::memprof::MemInfoBlock; using FrameIdMapTy = llvm::DenseMap<::llvm::memprof::FrameId, ::llvm::memprof::Frame>; +using CallStackIdMapTy = + llvm::DenseMap<::llvm::memprof::CallStackId, + ::llvm::SmallVector<::llvm::memprof::FrameId>>; static FrameIdMapTy getFrameMapping() { FrameIdMapTy Mapping; @@ -359,6 +362,14 @@ static FrameIdMapTy getFrameMapping() { return Mapping; } +static CallStackIdMapTy getCallStackMapping() { + CallStackIdMapTy Mapping; + Mapping.insert({0x111, {0, 1}}); + Mapping.insert({0x222, {2, 3}}); + Mapping.insert({0x333, {4, 5}}); + return Mapping; +} + IndexedMemProfRecord makeRecord( std::initializer_list<std::initializer_list<::llvm::memprof::FrameId>> AllocFrames, @@ -374,6 +385,21 @@ IndexedMemProfRecord makeRecord( return MR; } +IndexedMemProfRecord +makeRecordV2(std::initializer_list<::llvm::memprof::CallStackId> AllocFrames, + std::initializer_list<::llvm::memprof::CallStackId> CallSiteFrames, + const MemInfoBlock &Block = MemInfoBlock()) { + llvm::memprof::IndexedMemProfRecord MR; + for (const auto &CSId : AllocFrames) + // We don't populate IndexedAllocationInfo::CallStack because we use it only + // in Version0 and Version1. + MR.AllocSites.emplace_back(::llvm::SmallVector<memprof::FrameId>(), CSId, + Block); + for (const auto &CSId : CallSiteFrames) + MR.CallSiteIds.push_back(CSId); + return MR; +} + MATCHER_P(EqualsRecord, Want, "") { const memprof::MemProfRecord &Got = arg; @@ -408,7 +434,7 @@ MATCHER_P(EqualsRecord, Want, "") { return true; } -TEST_F(InstrProfTest, test_memprof) { +TEST_F(InstrProfTest, test_memprof_v0) { ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), Succeeded()); @@ -450,6 +476,67 @@ TEST_F(InstrProfTest, test_memprof) { EXPECT_THAT(WantRecord, EqualsRecord(Record)); } +TEST_F(InstrProfTest, test_memprof_v2) { + Writer.setMemProfVersionRequested(memprof::Version2); + + ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), + Succeeded()); + + const IndexedMemProfRecord IndexedMR = makeRecordV2( + /*AllocFrames=*/{0x111, 0x222}, + /*CallSiteFrames=*/{0x333}); + const FrameIdMapTy IdToFrameMap = getFrameMapping(); + const auto CSIdToCallStackMap = getCallStackMapping(); + for (const auto &I : IdToFrameMap) { + Writer.addMemProfFrame(I.first, I.getSecond(), Err); + } + for (const auto &I : CSIdToCallStackMap) { + Writer.addMemProfCallStack(I.first, I.getSecond(), Err); + } + Writer.addMemProfRecord(/*Id=*/0x9999, IndexedMR); + + auto Profile = Writer.writeBuffer(); + readProfile(std::move(Profile)); + + auto RecordOr = Reader->getMemProfRecord(0x9999); + ASSERT_THAT_ERROR(RecordOr.takeError(), Succeeded()); + const memprof::MemProfRecord &Record = RecordOr.get(); + + std::optional<memprof::FrameId> LastUnmappedFrameId; + auto IdToFrameCallback = [&](const memprof::FrameId Id) { + auto Iter = IdToFrameMap.find(Id); + if (Iter == IdToFrameMap.end()) { + LastUnmappedFrameId = Id; + return memprof::Frame(0, 0, 0, false); + } + return Iter->second; + }; + + std::optional<::llvm::memprof::CallStackId> LastUnmappedCSId; + auto CSIdToCallStackCallback = [&](::llvm::memprof::CallStackId CSId) { + llvm::SmallVector<memprof::Frame> Frames; + auto CSIter = CSIdToCallStackMap.find(CSId); + if (CSIter == CSIdToCallStackMap.end()) { + LastUnmappedCSId = CSId; + } else { + const ::llvm::SmallVector<::llvm::memprof::FrameId> &CS = + CSIter->getSecond(); + Frames.reserve(CS.size()); + for (::llvm::memprof::FrameId Id : CS) + Frames.push_back(IdToFrameCallback(Id)); + } + return Frames; + }; + + const ::llvm::memprof::MemProfRecord WantRecord = + IndexedMR.toMemProfRecord(CSIdToCallStackCallback); + ASSERT_EQ(LastUnmappedFrameId, std::nullopt) + << "could not map frame id: " << *LastUnmappedFrameId; + ASSERT_EQ(LastUnmappedCSId, std::nullopt) + << "could not map call stack id: " << *LastUnmappedCSId; + EXPECT_THAT(WantRecord, EqualsRecord(Record)); +} + TEST_F(InstrProfTest, test_memprof_getrecord_error) { ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), Succeeded()); |