diff --git a/memory/build/malloc_decls.h b/memory/build/malloc_decls.h index 49a7437afca9..1b4a06135725 100644 --- a/memory/build/malloc_decls.h +++ b/memory/build/malloc_decls.h @@ -121,6 +121,12 @@ MALLOC_DECL(moz_create_arena_with_params, arena_id_t, arena_params_t*) // Passing an invalid id (inexistent or already disposed) to this function // will crash. The arena must be empty prior to calling this function. MALLOC_DECL(moz_dispose_arena, void, arena_id_t) + +// Set the default modifier for mMaxDirty. The value is the number of shifts +// applied to the value. Positive value is handled as <<, negative >>. +// Arenas may override the default modifier. +MALLOC_DECL(moz_set_max_dirty_page_modifier, void, int32_t) + # endif # if MALLOC_FUNCS & MALLOC_FUNCS_ARENA_ALLOC diff --git a/memory/build/mozjemalloc.cpp b/memory/build/mozjemalloc.cpp index daf65c128b54..21367c46a932 100644 --- a/memory/build/mozjemalloc.cpp +++ b/memory/build/mozjemalloc.cpp @@ -1138,6 +1138,9 @@ struct arena_t { // Maximum value allowed for mNumDirty. size_t mMaxDirty; + int32_t mMaxDirtyIncreaseOverride; + int32_t mMaxDirtyDecreaseOverride; + private: // Size/address-ordered tree of this arena's available runs. This tree // is used for first-best-fit run allocation. @@ -1290,6 +1293,11 @@ class ArenaCollection { delete aArena; } + void SetDefaultMaxDirtyPageModifier(int32_t aModifier) { + mDefaultMaxDirtyPageModifier = aModifier; + } + int32_t DefaultMaxDirtyPageModifier() { return mDefaultMaxDirtyPageModifier; } + using Tree = RedBlackTree; struct Iterator : Tree::Iterator { @@ -1328,6 +1336,7 @@ class ArenaCollection { arena_id_t mLastPublicArenaId; Tree mArenas; Tree mPrivateArenas; + Atomic mDefaultMaxDirtyPageModifier; }; static ArenaCollection gArenas; @@ -2760,8 +2769,20 @@ arena_run_t* arena_t::AllocRun(size_t aSize, bool aLarge, bool aZero) { void arena_t::Purge(bool aAll) { arena_chunk_t* chunk; size_t i, npages; + + int32_t modifier = gArenas.DefaultMaxDirtyPageModifier(); + if (modifier) { + int32_t arenaOverride = + modifier > 0 ? mMaxDirtyIncreaseOverride : mMaxDirtyDecreaseOverride; + if (arenaOverride) { + modifier = arenaOverride; + } + } + // If all is set purge all dirty pages. - size_t dirty_max = aAll ? 1 : mMaxDirty; + size_t dirty_max = aAll ? 1 + : modifier >= 0 ? mMaxDirty << modifier + : mMaxDirty >> -modifier; #ifdef MOZ_DEBUG size_t ndirty = 0; for (auto chunk : mChunksDirty.iter()) { @@ -3884,7 +3905,14 @@ arena_t::arena_t(arena_params_t* aParams, bool aIsPrivate) { default: break; } + + mMaxDirtyIncreaseOverride = aParams->mMaxDirtyIncreaseOverride; + mMaxDirtyDecreaseOverride = aParams->mMaxDirtyDecreaseOverride; + } else { + mMaxDirtyIncreaseOverride = 0; + mMaxDirtyDecreaseOverride = 0; } + mPRNG = nullptr; mIsPrivate = aIsPrivate; @@ -4837,6 +4865,11 @@ inline void MozJemalloc::moz_dispose_arena(arena_id_t aArenaId) { gArenas.DisposeArena(arena); } +template <> +inline void MozJemalloc::moz_set_max_dirty_page_modifier(int32_t aModifier) { + gArenas.SetDefaultMaxDirtyPageModifier(aModifier); +} + #define MALLOC_DECL(name, return_type, ...) \ template <> \ inline return_type MozJemalloc::moz_arena_##name( \ diff --git a/memory/build/mozjemalloc.h b/memory/build/mozjemalloc.h index 60700756f3c4..a74c3b2ec65c 100644 --- a/memory/build/mozjemalloc.h +++ b/memory/build/mozjemalloc.h @@ -65,6 +65,8 @@ struct DummyArenaAllocator { static void moz_dispose_arena(arena_id_t) {} + static void moz_set_max_dirty_page_modifier(int32_t) {} + #define MALLOC_DECL(name, return_type, ...) \ static return_type moz_arena_##name( \ arena_id_t, ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) { \ diff --git a/memory/build/mozjemalloc_types.h b/memory/build/mozjemalloc_types.h index 80d5493f4ae8..1ab2ce0b7120 100644 --- a/memory/build/mozjemalloc_types.h +++ b/memory/build/mozjemalloc_types.h @@ -65,10 +65,22 @@ typedef size_t arena_id_t; typedef struct arena_params_s { size_t mMaxDirty; + // Arena specific modifiers which override the value passed to + // moz_set_max_dirty_page_modifier. If value > 0 is passed to that function, + // and mMaxDirtyIncreaseOverride != 0, mMaxDirtyIncreaseOverride will be used + // instead, and similarly if value < 0 is passed and mMaxDirtyDecreaseOverride + // != 0, mMaxDirtyDecreaseOverride will be used as the modifier. + int32_t mMaxDirtyIncreaseOverride; + int32_t mMaxDirtyDecreaseOverride; + uint32_t mFlags; #ifdef __cplusplus - arena_params_s() : mMaxDirty(0), mFlags(0) {} + arena_params_s() + : mMaxDirty(0), + mMaxDirtyIncreaseOverride(0), + mMaxDirtyDecreaseOverride(0), + mFlags(0) {} #endif } arena_params_t; diff --git a/memory/replace/phc/PHC.cpp b/memory/replace/phc/PHC.cpp index b28c36232b18..3d7c944ca578 100644 --- a/memory/replace/phc/PHC.cpp +++ b/memory/replace/phc/PHC.cpp @@ -1454,6 +1454,11 @@ void replace_moz_dispose_arena(arena_id_t aArenaId) { return sMallocTable.moz_dispose_arena(aArenaId); } +void replace_moz_set_max_dirty_page_modifier(int32_t aModifier) { + // No need to do anything special here. + return sMallocTable.moz_set_max_dirty_page_modifier(aModifier); +} + void* replace_moz_arena_malloc(arena_id_t aArenaId, size_t aReqSize) { return PageMalloc(Some(aArenaId), aReqSize); } diff --git a/tools/profiler/core/memory_hooks.cpp b/tools/profiler/core/memory_hooks.cpp index be83c6bf82ee..59e87d607c2b 100644 --- a/tools/profiler/core/memory_hooks.cpp +++ b/tools/profiler/core/memory_hooks.cpp @@ -550,6 +550,10 @@ static void replace_moz_dispose_arena(arena_id_t aArenaId) { return gMallocTable.moz_dispose_arena(aArenaId); } +static void replace_moz_set_max_dirty_page_modifier(int32_t aModifier) { + return gMallocTable.moz_set_max_dirty_page_modifier(aModifier); +} + // Must come after all the replace_* funcs void replace_init(malloc_table_t* aMallocTable, ReplaceMallocBridge** aBridge) { gMallocTable = *aMallocTable;