aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Hofhansl <larsh@apache.org>2018-07-21 03:07:43 -0700
committerLars Hofhansl <larsh@apache.org>2018-07-21 03:09:39 -0700
commit25cc5d1a3263aaca46f77f64b6cc20b1d2c32cac (patch)
tree87a63bc5bbee4e5908a5bf81ab2d28086957122b
parentc022ddce4bb0da68a842c6479ecd7d9660d7c2fe (diff)
downloadminetest-25cc5d1a3263aaca46f77f64b6cc20b1d2c32cac.tar.gz
minetest-25cc5d1a3263aaca46f77f64b6cc20b1d2c32cac.tar.bz2
minetest-25cc5d1a3263aaca46f77f64b6cc20b1d2c32cac.zip
Optimize ABM checks.
See #7555 Cache (up to 64) node types for each active block. Check this cache first to see whether any ABM needs to be triggered for a block.
-rw-r--r--src/mapblock.h10
-rw-r--r--src/serverenvironment.cpp42
2 files changed, 50 insertions, 2 deletions
diff --git a/src/mapblock.h b/src/mapblock.h
index 00695a94e..6b5015cab 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -114,6 +114,8 @@ public:
} else if (mod == m_modified) {
m_modified_reason |= reason;
}
+ if (mod == MOD_STATE_WRITE_NEEDED)
+ contents_cached = false;
}
inline u32 getModified()
@@ -529,6 +531,14 @@ public:
static const u32 nodecount = MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE;
+ //// ABM optimizations ////
+ // Cache of content types
+ std::unordered_set<content_t> contents;
+ // True if content types are cached
+ bool contents_cached = false;
+ // True if we never want to cache content types for this block
+ bool do_not_cache_contents = false;
+
private:
/*
Private member variables
diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp
index 79caa24ee..08870589e 100644
--- a/src/serverenvironment.cpp
+++ b/src/serverenvironment.cpp
@@ -800,11 +800,31 @@ public:
return active_object_count;
}
- void apply(MapBlock *block)
+ void apply(MapBlock *block, int &blocks_scanned, int &abms_run, int &blocks_cached)
{
if(m_aabms.empty() || block->isDummy())
return;
+ // Check the content type cache first
+ // to see whether there are any ABMs
+ // to be run at all for this block.
+ if (block->contents_cached) {
+ blocks_cached++;
+ bool run_abms = false;
+ for (content_t c : block->contents) {
+ if (c < m_aabms.size() && m_aabms[c]) {
+ run_abms = true;
+ break;
+ }
+ }
+ if (!run_abms)
+ return;
+ } else {
+ // Clear any caching
+ block->contents.clear();
+ }
+ blocks_scanned++;
+
ServerMap *map = &m_env->getServerMap();
u32 active_object_count_wider;
@@ -818,6 +838,15 @@ public:
{
const MapNode &n = block->getNodeUnsafe(p0);
content_t c = n.getContent();
+ // Cache content types as we go
+ if (!block->contents_cached && !block->do_not_cache_contents) {
+ block->contents.insert(c);
+ if (block->contents.size() > 64) {
+ // Too many different nodes... don't try to cache
+ block->do_not_cache_contents = true;
+ block->contents.clear();
+ }
+ }
if (c >= m_aabms.size() || !m_aabms[c])
continue;
@@ -855,6 +884,7 @@ public:
}
neighbor_found:
+ abms_run++;
// Call all the trigger variations
aabm.abm->trigger(m_env, p, n);
aabm.abm->trigger(m_env, p, n,
@@ -867,6 +897,7 @@ public:
}
}
}
+ block->contents_cached = !block->do_not_cache_contents;
}
};
@@ -1302,6 +1333,9 @@ void ServerEnvironment::step(float dtime)
// Initialize handling of ActiveBlockModifiers
ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
+ int blocks_scanned = 0;
+ int abms_run = 0;
+ int blocks_cached = 0;
for (const v3s16 &p : m_active_blocks.m_abm_list) {
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if (!block)
@@ -1311,8 +1345,12 @@ void ServerEnvironment::step(float dtime)
block->setTimestampNoChangedFlag(m_game_time);
/* Handle ActiveBlockModifiers */
- abmhandler.apply(block);
+ abmhandler.apply(block, blocks_scanned, abms_run, blocks_cached);
}
+ g_profiler->avg("SEnv: active blocks", m_active_blocks.m_abm_list.size());
+ g_profiler->avg("SEnv: active blocks cached", blocks_cached);
+ g_profiler->avg("SEnv: active blocks scanned for ABMs", blocks_scanned);
+ g_profiler->avg("SEnv: ABMs run", abms_run);
u32 time_ms = timer.stop(true);
u32 max_time_ms = 200;