mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
Move malloc_trim invocations to background thread (#14744)
This commit is contained in:
parent
d7f4ce6cff
commit
fac9aac821
@ -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;
|
||||
|
@ -662,6 +662,8 @@ void *EmergeThread::run()
|
||||
EmergeAction action;
|
||||
MapBlock *block = nullptr;
|
||||
|
||||
porting::TriggerMemoryTrim();
|
||||
|
||||
if (!popBlockEmerge(&pos, &bedata)) {
|
||||
m_queue_event.wait();
|
||||
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
|
||||
* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user