From fac9aac82129edd5d77c3aca3e9e6bbf39cc3220 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 17 Jun 2024 15:59:35 +0200 Subject: [PATCH] Move malloc_trim invocations to background thread (#14744) --- src/client/mesh_generator_thread.cpp | 15 +++++++++------ src/emerge.cpp | 2 ++ src/porting.cpp | 13 ++++++++++--- src/porting.h | 11 +++++++++-- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp index 32a01205d..21656aa6e 100644 --- a/src/client/mesh_generator_thread.cpp +++ b/src/client/mesh_generator_thread.cpp @@ -24,18 +24,20 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "map.h" #include "util/directiontables.h" +#include "porting.h" -static class BlockPlaceholder { -public: - MapNode data[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE]; +// Data placeholder used for copying from non-existent blocks +static struct BlockPlaceholder { + MapNode data[MapBlock::nodecount]; BlockPlaceholder() { - for (std::size_t i = 0; i < MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; i++) + for (std::size_t i = 0; i < MapBlock::nodecount; i++) data[i] = MapNode(CONTENT_IGNORE); } } block_placeholder; + /* QueuedMeshUpdate */ @@ -225,12 +227,13 @@ void MeshUpdateWorkerThread::doUpdate() while ((q = m_queue_in->pop())) { if (m_generation_interval) sleep_ms(m_generation_interval); + + porting::TriggerMemoryTrim(); + ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)"); MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data, *m_camera_offset); - - MeshUpdateResult r; r.p = q->p; r.mesh = mesh_new; diff --git a/src/emerge.cpp b/src/emerge.cpp index d6d6e630a..b53f298b3 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -662,6 +662,8 @@ void *EmergeThread::run() EmergeAction action; MapBlock *block = nullptr; + porting::TriggerMemoryTrim(); + if (!popBlockEmerge(&pos, &bedata)) { m_queue_event.wait(); continue; diff --git a/src/porting.cpp b/src/porting.cpp index 0763e92e1..a7601b101 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -920,22 +920,29 @@ double perf_freq = get_perf_freq(); * * As a workaround we track freed memory coarsely and call malloc_trim() once a * certain amount is reached. + * + * Because trimming can take more than 10ms and would cause jitter if done + * uncontrolled we have a separate function, which is called from background threads. */ static std::atomic memory_freed; -constexpr size_t MEMORY_TRIM_THRESHOLD = 128 * 1024 * 1024; +constexpr size_t MEMORY_TRIM_THRESHOLD = 256 * 1024 * 1024; void TrackFreedMemory(size_t amount) +{ + memory_freed.fetch_add(amount, std::memory_order_relaxed); +} + +void TriggerMemoryTrim() { constexpr auto MO = std::memory_order_relaxed; - memory_freed.fetch_add(amount, MO); if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) { // Synchronize call if (memory_freed.exchange(0, MO) < MEMORY_TRIM_THRESHOLD) return; // Leave some headroom for future allocations - malloc_trim(1 * 1024 * 1024); + malloc_trim(8 * 1024 * 1024); } } diff --git a/src/porting.h b/src/porting.h index 27fabe7cd..b5e23c1f9 100644 --- a/src/porting.h +++ b/src/porting.h @@ -290,15 +290,22 @@ void osSpecificInit(); // This attaches to the parents process console, or creates a new one if it doesnt exist. void attachOrCreateConsole(); +#if HAVE_MALLOC_TRIM /** * Call this after freeing bigger blocks of memory. Used on some platforms to * properly give memory back to the OS. * @param amount Number of bytes freed */ -#if HAVE_MALLOC_TRIM void TrackFreedMemory(size_t amount); + +/** + * Call this regularly from background threads. This performs the actual trimming + * and is potentially slow. + */ +void TriggerMemoryTrim(); #else -inline void TrackFreedMemory(size_t amount) { (void)amount; } +static inline void TrackFreedMemory(size_t amount) { (void)amount; } +static inline void TriggerMemoryTrim() { (void)0; } #endif #ifdef _WIN32