aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/ProfileData/InstrProfTest.cpp
diff options
context:
space:
mode:
authorKazu Hirata <kazu@google.com>2024-04-18 14:12:58 -0700
committerGitHub <noreply@github.com>2024-04-18 14:12:58 -0700
commit172f6ddfa7662a36e3a41db6bb944f7d72fd0b00 (patch)
tree57e5d885aeda67aa160c2134ebdce099d09d5c14 /llvm/unittests/ProfileData/InstrProfTest.cpp
parent7aad1ee70f2c6be603707ff52a13e0e22330e859 (diff)
downloadllvm-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.cpp89
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());