Skip to content

Commit 0f3f636

Browse files
committed
[scudo] Update secondary cache time-based release logic.
Secondary cache entries are now released to the OS from least recent to most recent entries. This helps to avoid unnecessary scans of the cache since entries ready to be released (specifically, entries that are considered old relative to the configurable release interval) will always be at the tail of the list of committed entries by the LRU ordering. For this same reason, the OldestTime variable is no longer needed to indicate when releases are necessary so it has been removed.
1 parent 9e9971b commit 0f3f636

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

compiler-rt/lib/scudo/standalone/secondary.h

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ class MapAllocatorCache {
244244
// The cache is initially empty
245245
LRUHead = CachedBlock::InvalidEntry;
246246
LRUTail = CachedBlock::InvalidEntry;
247+
LastUnreleasedEntry = CachedBlock::InvalidEntry;
247248

248249
// Available entries will be retrieved starting from the beginning of the
249250
// Entries array
@@ -318,9 +319,10 @@ class MapAllocatorCache {
318319
}
319320
CachedBlock PrevEntry = Quarantine[QuarantinePos];
320321
Quarantine[QuarantinePos] = Entry;
321-
if (OldestTime == 0)
322-
OldestTime = Entry.Time;
323322
Entry = PrevEntry;
323+
// Update the entry time to reflect the time that the
324+
// quarantined memory is placed in the Entries array
325+
Entry.Time = Time;
324326
}
325327

326328
// All excess entries are evicted from the cache
@@ -331,9 +333,6 @@ class MapAllocatorCache {
331333
}
332334

333335
insert(Entry);
334-
335-
if (OldestTime == 0)
336-
OldestTime = Entry.Time;
337336
} while (0);
338337

339338
for (MemMapT &EvictMemMap : EvictionMemMaps)
@@ -532,6 +531,9 @@ class MapAllocatorCache {
532531
Entries[LRUHead].Prev = static_cast<u16>(FreeIndex);
533532
}
534533

534+
if (LastUnreleasedEntry == CachedBlock::InvalidEntry)
535+
LastUnreleasedEntry = static_cast<u16>(FreeIndex);
536+
535537
Entries[FreeIndex] = Entry;
536538
Entries[FreeIndex].Next = LRUHead;
537539
Entries[FreeIndex].Prev = CachedBlock::InvalidEntry;
@@ -549,6 +551,9 @@ class MapAllocatorCache {
549551

550552
Entries[I].invalidate();
551553

554+
if (I == LastUnreleasedEntry)
555+
LastUnreleasedEntry = Entries[LastUnreleasedEntry].Prev;
556+
552557
if (I == LRUHead)
553558
LRUHead = Entries[I].Next;
554559
else
@@ -590,35 +595,37 @@ class MapAllocatorCache {
590595
}
591596
}
592597

593-
void releaseIfOlderThan(CachedBlock &Entry, u64 Time) REQUIRES(Mutex) {
594-
if (!Entry.isValid() || !Entry.Time)
595-
return;
596-
if (Entry.Time > Time) {
597-
if (OldestTime == 0 || Entry.Time < OldestTime)
598-
OldestTime = Entry.Time;
599-
return;
600-
}
598+
inline void release(CachedBlock &Entry) {
599+
DCHECK(Entry.Time != 0);
601600
Entry.MemMap.releaseAndZeroPagesToOS(Entry.CommitBase, Entry.CommitSize);
602601
Entry.Time = 0;
603602
}
604603

605604
void releaseOlderThan(u64 Time) EXCLUDES(Mutex) {
606605
ScopedLock L(Mutex);
607-
if (!EntriesCount || OldestTime == 0 || OldestTime > Time)
606+
if (!EntriesCount)
608607
return;
609-
OldestTime = 0;
610-
for (uptr I = 0; I < Config::getQuarantineSize(); I++)
611-
releaseIfOlderThan(Quarantine[I], Time);
612-
for (uptr I = 0; I < Config::getEntriesArraySize(); I++)
613-
releaseIfOlderThan(Entries[I], Time);
614-
}
615608

609+
for (uptr I = 0; I < Config::getQuarantineSize(); I++) {
610+
CachedBlock &ReleaseEntry = Quarantine[I];
611+
if (!ReleaseEntry.isValid() || !ReleaseEntry.Time ||
612+
ReleaseEntry.Time > Time)
613+
continue;
614+
release(ReleaseEntry);
615+
}
616+
617+
// Release oldest entries first by releasing from decommit base
618+
while (LastUnreleasedEntry != CachedBlock::InvalidEntry &&
619+
Entries[LastUnreleasedEntry].Time <= Time) {
620+
release(Entries[LastUnreleasedEntry]);
621+
LastUnreleasedEntry = Entries[LastUnreleasedEntry].Prev;
622+
}
623+
}
616624
HybridMutex Mutex;
617625
u32 EntriesCount GUARDED_BY(Mutex) = 0;
618626
u32 QuarantinePos GUARDED_BY(Mutex) = 0;
619627
atomic_u32 MaxEntriesCount = {};
620628
atomic_uptr MaxEntrySize = {};
621-
u64 OldestTime GUARDED_BY(Mutex) = 0;
622629
atomic_s32 ReleaseToOsIntervalMs = {};
623630
u32 CallsToRetrieve GUARDED_BY(Mutex) = 0;
624631
u32 SuccessfulRetrieves GUARDED_BY(Mutex) = 0;
@@ -633,6 +640,9 @@ class MapAllocatorCache {
633640
u16 LRUTail GUARDED_BY(Mutex) = 0;
634641
// The AvailableHead is the top of the stack of available entries
635642
u16 AvailableHead GUARDED_BY(Mutex) = 0;
643+
// The LastUnreleasedEntry is the least recently used entry that has not
644+
// been released
645+
u16 LastUnreleasedEntry GUARDED_BY(Mutex) = 0;
636646
};
637647

638648
template <typename Config> class MapAllocator {

0 commit comments

Comments
 (0)