From 2420ba9814b28fb49c91af21ba55ade9b3eb1a74 Mon Sep 17 00:00:00 2001 From: Chia-hung Duan Date: Fri, 6 Oct 2023 20:12:20 +0000 Subject: [PATCH] [scudo] Improve the message of region exhaustion In this CL, we move the printing of allocator stats from primary.h to combined.h. This will also dump the secondary stats and reduce the log spam when an OOM happens Also change the symbol `F` to `E` to indicate region pages exhausted. It means the region can't map more pages for blocks but it may still have free blocks to allocate. `F` may hint the failure of fatel error in the region. Also update the related comments. --- compiler-rt/lib/scudo/standalone/combined.h | 8 ++++---- compiler-rt/lib/scudo/standalone/primary64.h | 18 ++++++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h index b013f03a73ae4..b1700e5ecef7f 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -367,10 +367,9 @@ class Allocator { auto *TSD = TSDRegistry.getTSDAndLock(&UnlockRequired); TSD->assertLocked(/*BypassCheck=*/!UnlockRequired); Block = TSD->getCache().allocate(ClassId); - // If the allocation failed, the most likely reason with a 32-bit primary - // is the region being full. In that event, retry in each successively - // larger class until it fits. If it fails to fit in the largest class, - // fallback to the Secondary. + // If the allocation failed, retry in each successively larger class until + // it fits. If it fails to fit in the largest class, fallback to the + // Secondary. if (UNLIKELY(!Block)) { while (ClassId < SizeClassMap::LargestClassId && !Block) Block = TSD->getCache().allocate(++ClassId); @@ -388,6 +387,7 @@ class Allocator { if (UNLIKELY(!Block)) { if (Options.get(OptionBit::MayReturnNull)) return nullptr; + printStats(); reportOutOfMemory(NeededSize); } diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h index ed0c4deaac2c8..6d160b4c64d75 100644 --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -214,7 +214,7 @@ template class SizeClassAllocator64 { return B; } - bool PrintStats = false; + bool ReportRegionExhausted = false; TransferBatch *B = nullptr; while (true) { @@ -235,19 +235,13 @@ template class SizeClassAllocator64 { const bool RegionIsExhausted = Region->Exhausted; if (!RegionIsExhausted) B = populateFreeListAndPopBatch(C, ClassId, Region); - PrintStats = !RegionIsExhausted && Region->Exhausted; + ReportRegionExhausted = !RegionIsExhausted && Region->Exhausted; break; } - // Note that `getStats()` requires locking each region so we can't call it - // while locking the Region->Mutex in the above. - if (UNLIKELY(PrintStats)) { - ScopedString Str; - getStats(&Str); - Str.append( - "Scudo OOM: The process has exhausted %zuM for size class %zu.\n", - RegionSize >> 20, getSizeByClassId(ClassId)); - Str.output(); + if (UNLIKELY(ReportRegionExhausted)) { + Printf("Can't populate more pages for size class %zu.\n", + getSizeByClassId(ClassId)); // Theoretically, BatchClass shouldn't be used up. Abort immediately when // it happens. @@ -978,7 +972,7 @@ template class SizeClassAllocator64 { "%s %02zu (%6zu): mapped: %6zuK popped: %7zu pushed: %7zu " "inuse: %6zu total: %6zu releases: %6zu last " "released: %6zuK latest pushed bytes: %6zuK region: 0x%zx (0x%zx)\n", - Region->Exhausted ? "F" : " ", ClassId, getSizeByClassId(ClassId), + Region->Exhausted ? "E" : " ", ClassId, getSizeByClassId(ClassId), Region->MemMapInfo.MappedUser >> 10, Region->FreeListInfo.PoppedBlocks, Region->FreeListInfo.PushedBlocks, InUseBlocks, TotalChunks, Region->ReleaseInfo.RangesReleased,