[compiler-rt] [scudo] Track maximum resident memory in cache (PR #219036)
Sadaf Ebrahimi via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 13:57:57 PDT 2026
https://github.com/sadafebrahimi created https://github.com/llvm/llvm-project/pull/219036
Add tracking for the resident memory in MapAllocatorCache. Unreleased cache entries where Time != 0 are assumed to be resident, while entries that have passed through releaseOlderThan where Time == 0 have had their physical pages discarded.
Tracking is performed by updating CurrentResidentBytes on store, remove, and release operations, recoding the peak in maxResidentBytes and reporting it in getStats.
>From 3bc912d70757457f8cf2b24f173a420ee29a955f Mon Sep 17 00:00:00 2001
From: Sadaf Ebrahimi <sadafebrahimi at google.com>
Date: Wed, 26 Aug 2026 20:49:58 +0000
Subject: [PATCH] [scudo] Track maximum resident memory in cache
Add tracking for the resident memory in MapAllocatorCache. Unreleased
cache entries where Time != 0 are assumed to be resident, while entries
that have passed through releaseOlderThan where Time == 0 have had
their physical pages discarded.
Tracking is performed by updating CurrentResidentBytes on store, remove,
and release operations, recoding the peak in maxResidentBytes and
reporting it in getStats.
---
compiler-rt/lib/scudo/standalone/secondary.h | 32 +++++++++++++++
.../scudo/standalone/tests/secondary_test.cpp | 41 +++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h
index 16e94f0cb7511..956ce7c6c8ffd 100644
--- a/compiler-rt/lib/scudo/standalone/secondary.h
+++ b/compiler-rt/lib/scudo/standalone/secondary.h
@@ -142,6 +142,9 @@ template <typename Config> class MapAllocatorNoCache {
return true;
}
+ uptr getMaxResidentBytesTestOnly() const { return 0; }
+ uptr getCurrentResidentBytesTestOnly() const { return 0; }
+
void getStats(UNUSED ScopedString *Str) {
Str->append("Secondary Cache Disabled\n");
}
@@ -565,6 +568,16 @@ class MapAllocatorCache {
void enable() NO_THREAD_SAFETY_ANALYSIS { Mutex.unlock(); }
+ uptr getMaxResidentBytesTestOnly() {
+ ScopedLock L(Mutex);
+ return MaxResidentBytes;
+ }
+
+ uptr getCurrentResidentBytesTestOnly() {
+ ScopedLock L(Mutex);
+ return CurrentResidentBytes;
+ }
+
void unmapTestOnly() { empty(); }
void releaseOlderThanTestOnly(u64 ReleaseTime) {
@@ -581,6 +594,11 @@ class MapAllocatorCache {
LRUEntries.push_front(AvailEntry);
if (OldestPresentEntry == nullptr && AvailEntry->Time != 0)
OldestPresentEntry = AvailEntry;
+ if (AvailEntry->Time != 0) {
+ CurrentResidentBytes += Entry.CommitSize;
+ if (CurrentResidentBytes > MaxResidentBytes)
+ MaxResidentBytes = CurrentResidentBytes;
+ }
}
void remove(CachedBlock *Entry) REQUIRES(Mutex) {
@@ -590,6 +608,8 @@ class MapAllocatorCache {
DCHECK(OldestPresentEntry == nullptr || OldestPresentEntry->Time != 0);
}
LRUEntries.remove(Entry);
+ if (Entry->Time != 0)
+ CurrentResidentBytes -= Entry->CommitSize;
Entry->invalidate();
AvailEntries.push_front(Entry);
}
@@ -604,6 +624,7 @@ class MapAllocatorCache {
MapInfo[N++] = Entry.MemMap;
LRUEntries.clear();
OldestPresentEntry = nullptr;
+ CurrentResidentBytes = 0;
}
for (uptr I = 0; I < N; I++) {
MemMapT &MemMap = MapInfo[I];
@@ -638,6 +659,7 @@ class MapAllocatorCache {
Entry->MemMap.releaseAndZeroPagesToOS(Entry->CommitBase,
Entry->CommitSize);
+ CurrentResidentBytes -= Entry->CommitSize;
Entry->Time = 0;
}
OldestPresentEntry = nullptr;
@@ -651,6 +673,8 @@ class MapAllocatorCache {
u32 CallsToRetrieve GUARDED_BY(Mutex) = 0;
u32 SuccessfulRetrieves GUARDED_BY(Mutex) = 0;
u32 EvictedCount GUARDED_BY(Mutex) = 0;
+ uptr CurrentResidentBytes GUARDED_BY(Mutex) = 0;
+ uptr MaxResidentBytes GUARDED_BY(Mutex) = 0;
atomic_uptr ReleaseToOsSkips = {};
CachedBlock Entries[Config::getEntriesArraySize()] GUARDED_BY(Mutex) = {};
@@ -736,6 +760,14 @@ template <typename Config> class MapAllocator {
void unmapTestOnly() { Cache.unmapTestOnly(); }
+ uptr getMaxResidentBytesTestOnly() {
+ return Cache.getMaxResidentBytesTestOnly();
+ }
+
+ uptr getCurrentResidentBytesTestOnly() {
+ return Cache.getCurrentResidentBytesTestOnly();
+ }
+
void getStats(ScopedString *Str);
private:
diff --git a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp
index a3cb493778f38..1665328abf5df 100644
--- a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp
@@ -680,3 +680,44 @@ TEST(ScudoSecondaryTest, ReleaseOlderThanGroups) {
EXPECT_EQ(*reinterpret_cast<scudo::u32 *>(Info.MemMaps[I].getBase()), 0U);
}
}
+
+TEST(ScudoSecondaryTest, AllocatorCacheMaxResidentBytes) {
+ CacheInfoType<TestCacheConfig> Info;
+
+ Info.Cache->setOption(scudo::Option::ReleaseInterval, -1);
+ Info.Cache->setOption(scudo::Option::MaxCacheEntriesCount, 10);
+ Info.Cache->setOption(scudo::Option::MaxCacheEntrySize, 1024 * 1024);
+
+ EXPECT_EQ(Info.Cache->getCurrentResidentBytesTestOnly(), 0U);
+ EXPECT_EQ(Info.Cache->getMaxResidentBytesTestOnly(), 0U);
+
+ Info.MemMaps.emplace_back(Info.allocate(1024));
+ const scudo::uptr Size1 = Info.MemMaps[0].getCapacity();
+ Info.storeMemMap(Info.MemMaps[0]);
+
+ EXPECT_EQ(Info.Cache->getCurrentResidentBytesTestOnly(), Size1);
+ EXPECT_EQ(Info.Cache->getMaxResidentBytesTestOnly(), Size1);
+
+ Info.MemMaps.emplace_back(Info.allocate(1024));
+ const scudo::uptr Size2 = Info.MemMaps[1].getCapacity();
+ Info.storeMemMap(Info.MemMaps[1]);
+
+ EXPECT_EQ(Info.Cache->getCurrentResidentBytesTestOnly(), Size1 + Size2);
+ EXPECT_EQ(Info.Cache->getMaxResidentBytesTestOnly(), Size1 + Size2);
+
+ const scudo::uptr PeakBytes = Size1 + Size2;
+
+ // Releasing pages should drop CurrentResidentBytes to 0, while
+ // MaxResidentBytes stays at peak
+ Info.Cache->releaseOlderThanTestOnly(UINT64_MAX);
+ EXPECT_EQ(Info.Cache->getCurrentResidentBytesTestOnly(), 0U);
+ EXPECT_EQ(Info.Cache->getMaxResidentBytesTestOnly(), PeakBytes);
+
+ // Store a third map to verify CurrentResidentBytes increases again
+ Info.MemMaps.emplace_back(Info.allocate(1024));
+ const scudo::uptr Size3 = Info.MemMaps[2].getCapacity();
+ Info.storeMemMap(Info.MemMaps[2]);
+
+ EXPECT_EQ(Info.Cache->getCurrentResidentBytesTestOnly(), Size3);
+ EXPECT_EQ(Info.Cache->getMaxResidentBytesTestOnly(), PeakBytes);
+}
More information about the llvm-commits
mailing list