Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lhofhansl committed Jul 21, 2018
1 parent c022ddc commit 25cc5d1
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/mapblock.h
Expand Up @@ -114,6 +114,8 @@ class MapBlock
} else if (mod == m_modified) {
m_modified_reason |= reason;
}
if (mod == MOD_STATE_WRITE_NEEDED)
contents_cached = false;
}

inline u32 getModified()
Expand Down Expand Up @@ -529,6 +531,14 @@ class MapBlock

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
Expand Down
42 changes: 40 additions & 2 deletions src/serverenvironment.cpp
Expand Up @@ -800,11 +800,31 @@ class ABMHandler
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;
Expand All @@ -818,6 +838,15 @@ class ABMHandler
{
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;
Expand Down Expand Up @@ -855,6 +884,7 @@ class ABMHandler
}
neighbor_found:

abms_run++;
// Call all the trigger variations
aabm.abm->trigger(m_env, p, n);
aabm.abm->trigger(m_env, p, n,
Expand All @@ -867,6 +897,7 @@ class ABMHandler
}
}
}
block->contents_cached = !block->do_not_cache_contents;
}
};

Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down

0 comments on commit 25cc5d1

Please sign in to comment.