Move malloc_trim invocations to background thread (#14744)

This commit is contained in:
sfan5 2024-06-17 15:59:35 +02:00 committed by GitHub
parent d7f4ce6cff
commit fac9aac821
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 30 additions and 11 deletions

@ -24,18 +24,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapblock.h" #include "mapblock.h"
#include "map.h" #include "map.h"
#include "util/directiontables.h" #include "util/directiontables.h"
#include "porting.h"
static class BlockPlaceholder { // Data placeholder used for copying from non-existent blocks
public: static struct BlockPlaceholder {
MapNode data[MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE]; MapNode data[MapBlock::nodecount];
BlockPlaceholder() 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); data[i] = MapNode(CONTENT_IGNORE);
} }
} block_placeholder; } block_placeholder;
/* /*
QueuedMeshUpdate QueuedMeshUpdate
*/ */
@ -225,12 +227,13 @@ void MeshUpdateWorkerThread::doUpdate()
while ((q = m_queue_in->pop())) { while ((q = m_queue_in->pop())) {
if (m_generation_interval) if (m_generation_interval)
sleep_ms(m_generation_interval); sleep_ms(m_generation_interval);
porting::TriggerMemoryTrim();
ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)"); ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)");
MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data, *m_camera_offset); MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data, *m_camera_offset);
MeshUpdateResult r; MeshUpdateResult r;
r.p = q->p; r.p = q->p;
r.mesh = mesh_new; r.mesh = mesh_new;

@ -662,6 +662,8 @@ void *EmergeThread::run()
EmergeAction action; EmergeAction action;
MapBlock *block = nullptr; MapBlock *block = nullptr;
porting::TriggerMemoryTrim();
if (!popBlockEmerge(&pos, &bedata)) { if (!popBlockEmerge(&pos, &bedata)) {
m_queue_event.wait(); m_queue_event.wait();
continue; continue;

@ -920,22 +920,29 @@ double perf_freq = get_perf_freq();
* *
* As a workaround we track freed memory coarsely and call malloc_trim() once a * As a workaround we track freed memory coarsely and call malloc_trim() once a
* certain amount is reached. * 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<size_t> memory_freed; static std::atomic<size_t> 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) void TrackFreedMemory(size_t amount)
{
memory_freed.fetch_add(amount, std::memory_order_relaxed);
}
void TriggerMemoryTrim()
{ {
constexpr auto MO = std::memory_order_relaxed; constexpr auto MO = std::memory_order_relaxed;
memory_freed.fetch_add(amount, MO);
if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) { if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) {
// Synchronize call // Synchronize call
if (memory_freed.exchange(0, MO) < MEMORY_TRIM_THRESHOLD) if (memory_freed.exchange(0, MO) < MEMORY_TRIM_THRESHOLD)
return; return;
// Leave some headroom for future allocations // Leave some headroom for future allocations
malloc_trim(1 * 1024 * 1024); malloc_trim(8 * 1024 * 1024);
} }
} }

@ -290,15 +290,22 @@ void osSpecificInit();
// This attaches to the parents process console, or creates a new one if it doesnt exist. // This attaches to the parents process console, or creates a new one if it doesnt exist.
void attachOrCreateConsole(); void attachOrCreateConsole();
#if HAVE_MALLOC_TRIM
/** /**
* Call this after freeing bigger blocks of memory. Used on some platforms to * Call this after freeing bigger blocks of memory. Used on some platforms to
* properly give memory back to the OS. * properly give memory back to the OS.
* @param amount Number of bytes freed * @param amount Number of bytes freed
*/ */
#if HAVE_MALLOC_TRIM
void TrackFreedMemory(size_t amount); void TrackFreedMemory(size_t amount);
/**
* Call this regularly from background threads. This performs the actual trimming
* and is potentially slow.
*/
void TriggerMemoryTrim();
#else #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 #endif
#ifdef _WIN32 #ifdef _WIN32