mirror of
https://github.com/minetest/minetest.git
synced 2025-02-17 10:23:47 +01:00
Move malloc_trim invocations to background thread (#14744)
This commit is contained in:
@ -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
|
||||||
|
Reference in New Issue
Block a user