From 39f073938138a722969b2933ffb577557613d64b Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 23 May 2021 12:52:19 +0200 Subject: LibC+UE: Keep more unused chunked blocks around Previously each malloc size class would keep around a limited number of unused blocks which were marked with MADV_SET_VOLATILE which could then be reinitialized when additional blocks were needed. This changes malloc() so that it also keeps around a number of blocks without marking them with MADV_SET_VOLATILE. I termed these "hot" blocks whereas blocks which were marked as MADV_SET_VOLATILE are called "cold" blocks because they're more expensive to reinitialize. In the worst case this could increase memory usage per process by 1MB when a program requests a bunch of memory and frees all of it. Also, in order to make more efficient use of these unused blocks they're now shared between size classes. --- .../UserspaceEmulator/Emulator_syscalls.cpp | 3 ++ .../DevTools/UserspaceEmulator/MallocTracer.cpp | 50 ++++++++++++++-------- Userland/DevTools/UserspaceEmulator/MallocTracer.h | 3 ++ 3 files changed, 39 insertions(+), 17 deletions(-) (limited to 'Userland/DevTools') diff --git a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp index 33b0709c0f..63ef464052 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp @@ -1121,6 +1121,9 @@ int Emulator::virt$emuctl(FlatPtr arg1, FlatPtr arg2, FlatPtr arg3) case 3: tracer->target_did_realloc({}, arg3, arg2); return 0; + case 4: + tracer->target_did_change_chunk_size({}, arg3, arg2); + return 0; default: return -EINVAL; } diff --git a/Userland/DevTools/UserspaceEmulator/MallocTracer.cpp b/Userland/DevTools/UserspaceEmulator/MallocTracer.cpp index 4f00c21c52..c2c4a02303 100644 --- a/Userland/DevTools/UserspaceEmulator/MallocTracer.cpp +++ b/Userland/DevTools/UserspaceEmulator/MallocTracer.cpp @@ -36,6 +36,27 @@ inline void MallocTracer::for_each_mallocation(Callback callback) const }); } +void MallocTracer::update_metadata(MmapRegion& mmap_region, size_t chunk_size) +{ + mmap_region.set_malloc_metadata({}, + adopt_own(*new MallocRegionMetadata { + .region = mmap_region, + .address = mmap_region.base(), + .chunk_size = chunk_size, + .mallocations = {}, + })); + auto& malloc_data = *mmap_region.malloc_metadata(); + + bool is_chunked_block = malloc_data.chunk_size <= size_classes[num_size_classes - 1]; + if (is_chunked_block) + malloc_data.mallocations.resize((ChunkedBlock::block_size - sizeof(ChunkedBlock)) / malloc_data.chunk_size); + else + malloc_data.mallocations.resize(1); + + // Mark the containing mmap region as a malloc block! + mmap_region.set_malloc(true); +} + void MallocTracer::target_did_malloc(Badge, FlatPtr address, size_t size) { if (m_emulator.is_in_loader_code()) @@ -59,29 +80,24 @@ void MallocTracer::target_did_malloc(Badge, FlatPtr address, size_t si if (!mmap_region.is_malloc_block()) { auto chunk_size = mmap_region.read32(offsetof(CommonHeader, m_size)).value(); - mmap_region.set_malloc_metadata({}, - adopt_own(*new MallocRegionMetadata { - .region = mmap_region, - .address = mmap_region.base(), - .chunk_size = chunk_size, - .mallocations = {}, - })); - auto& malloc_data = *mmap_region.malloc_metadata(); - - bool is_chunked_block = malloc_data.chunk_size <= size_classes[num_size_classes - 1]; - if (is_chunked_block) - malloc_data.mallocations.resize((ChunkedBlock::block_size - sizeof(ChunkedBlock)) / malloc_data.chunk_size); - else - malloc_data.mallocations.resize(1); - - // Mark the containing mmap region as a malloc block! - mmap_region.set_malloc(true); + update_metadata(mmap_region, chunk_size); } auto* mallocation = mmap_region.malloc_metadata()->mallocation_for_address(address); VERIFY(mallocation); *mallocation = { address, size, true, false, m_emulator.raw_backtrace(), Vector() }; } +void MallocTracer::target_did_change_chunk_size(Badge, FlatPtr block, size_t chunk_size) +{ + if (m_emulator.is_in_loader_code()) + return; + auto* region = m_emulator.mmu().find_region({ 0x23, block }); + VERIFY(region); + VERIFY(is(*region)); + auto& mmap_region = static_cast(*region); + update_metadata(mmap_region, chunk_size); +} + ALWAYS_INLINE Mallocation* MallocRegionMetadata::mallocation_for_address(FlatPtr address) const { auto index = chunk_index_for_address(address); diff --git a/Userland/DevTools/UserspaceEmulator/MallocTracer.h b/Userland/DevTools/UserspaceEmulator/MallocTracer.h index a294828e86..8d35d9ed04 100644 --- a/Userland/DevTools/UserspaceEmulator/MallocTracer.h +++ b/Userland/DevTools/UserspaceEmulator/MallocTracer.h @@ -61,6 +61,7 @@ public: void target_did_malloc(Badge, FlatPtr address, size_t); void target_did_free(Badge, FlatPtr address); void target_did_realloc(Badge, FlatPtr address, size_t); + void target_did_change_chunk_size(Badge, FlatPtr, size_t); void audit_read(const Region&, FlatPtr address, size_t); void audit_write(const Region&, FlatPtr address, size_t); @@ -79,6 +80,8 @@ private: void dump_memory_graph(); void populate_memory_graph(); + void update_metadata(MmapRegion& mmap_region, size_t chunk_size); + Emulator& m_emulator; MemoryGraph m_memory_graph {}; -- cgit v1.2.3