Add an active object step time budget #6721

This can be set via the active_object_interval option.
This commit is contained in:
Lars Hofhansl 2017-12-06 12:21:46 -08:00
parent e049405fdc
commit 9c669016d1
7 changed files with 68 additions and 38 deletions

@ -1085,6 +1085,9 @@ active_block_mgmt_interval (Active Block Management interval) float 2.0
# Length of time between ABM execution cycles # Length of time between ABM execution cycles
abm_interval (Active Block Modifier interval) float 1.0 abm_interval (Active Block Modifier interval) float 1.0
# Length of time between active object step cycles
active_object_interval (Active Object interval) float 0.1
# Length of time between NodeTimer execution cycles # Length of time between NodeTimer execution cycles
nodetimer_interval (NodeTimer interval) float 0.2 nodetimer_interval (NodeTimer interval) float 0.2

@ -345,6 +345,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("dedicated_server_step", "0.09"); settings->setDefault("dedicated_server_step", "0.09");
settings->setDefault("active_block_mgmt_interval", "2.0"); settings->setDefault("active_block_mgmt_interval", "2.0");
settings->setDefault("abm_interval", "1.0"); settings->setDefault("abm_interval", "1.0");
settings->setDefault("active_object_interval", "0.1");
settings->setDefault("nodetimer_interval", "0.2"); settings->setDefault("nodetimer_interval", "0.2");
settings->setDefault("ignore_world_load_errors", "false"); settings->setDefault("ignore_world_load_errors", "false");
settings->setDefault("remote_media", ""); settings->setDefault("remote_media", "");

@ -36,6 +36,7 @@ Environment::Environment(IGameDef *gamedef):
m_cache_enable_shaders = g_settings->getBool("enable_shaders"); m_cache_enable_shaders = g_settings->getBool("enable_shaders");
m_cache_active_block_mgmt_interval = g_settings->getFloat("active_block_mgmt_interval"); m_cache_active_block_mgmt_interval = g_settings->getFloat("active_block_mgmt_interval");
m_cache_abm_interval = g_settings->getFloat("abm_interval"); m_cache_abm_interval = g_settings->getFloat("abm_interval");
m_cache_ao_interval = g_settings->getFloat("active_object_interval");
m_cache_nodetimer_interval = g_settings->getFloat("nodetimer_interval"); m_cache_nodetimer_interval = g_settings->getFloat("nodetimer_interval");
m_time_of_day = g_settings->getU32("world_start_time"); m_time_of_day = g_settings->getU32("world_start_time");

@ -136,6 +136,7 @@ protected:
bool m_cache_enable_shaders; bool m_cache_enable_shaders;
float m_cache_active_block_mgmt_interval; float m_cache_active_block_mgmt_interval;
float m_cache_abm_interval; float m_cache_abm_interval;
float m_cache_ao_interval;
float m_cache_nodetimer_interval; float m_cache_nodetimer_interval;
IGameDef *m_gamedef; IGameDef *m_gamedef;

@ -279,17 +279,17 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, u32 stamp)
void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list) void fillRadiusBlock(v3s16 p0, s16 r, std::set<v3s16> &list)
{ {
const s16 r2 = r * r;
v3s16 p; v3s16 p;
for(p.X=p0.X-r; p.X<=p0.X+r; p.X++) for (p.X = p0.X - r; p.X <= p0.X + r; p.X++)
for(p.Y=p0.Y-r; p.Y<=p0.Y+r; p.Y++) for (p.Y = p0.Y - r; p.Y <= p0.Y + r; p.Y++)
for(p.Z=p0.Z-r; p.Z<=p0.Z+r; p.Z++) for (p.Z = p0.Z - r; p.Z <= p0.Z + r; p.Z++) {
{ // limit to a sphere
// limit to a sphere if (p.getDistanceFromSQ(p0) <= r2) {
if (p.getDistanceFrom(p0) <= r) { // Set in list
// Set in list list.insert(p);
list.insert(p); }
} }
}
} }
void fillViewConeBlock(v3s16 p0, void fillViewConeBlock(v3s16 p0,
@ -364,10 +364,7 @@ void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players,
/* /*
Update m_list Update m_list
*/ */
m_list.clear(); m_list = newlist;
for (v3s16 p : newlist) {
m_list.insert(p);
}
} }
/* /*
@ -1230,14 +1227,16 @@ void ServerEnvironment::step(float dtime)
} }
} }
// placeholder for the "real" time passed
float elapsed_time;
/* /*
Mess around in active blocks Mess around in active blocks
*/ */
if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval)) { if (m_active_blocks_nodemetadata_interval.step(dtime, m_cache_nodetimer_interval,
&elapsed_time)) {
ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG); ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg per interval", SPT_AVG);
float dtime = m_cache_nodetimer_interval;
for (const v3s16 &p: m_active_blocks.m_list) { for (const v3s16 &p: m_active_blocks.m_list) {
MapBlock *block = m_map->getBlockNoCreateNoEx(p); MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if (!block) if (!block)
@ -1255,7 +1254,7 @@ void ServerEnvironment::step(float dtime)
MOD_REASON_BLOCK_EXPIRED); MOD_REASON_BLOCK_EXPIRED);
// Run node timers // Run node timers
std::vector<NodeTimer> elapsed_timers = block->m_node_timers.step(dtime); std::vector<NodeTimer> elapsed_timers = block->m_node_timers.step(elapsed_time);
if (!elapsed_timers.empty()) { if (!elapsed_timers.empty()) {
MapNode n; MapNode n;
v3s16 p2; v3s16 p2;
@ -1271,18 +1270,14 @@ void ServerEnvironment::step(float dtime)
} }
} }
if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval)) if (m_active_block_modifier_interval.step(dtime,
m_cache_abm_interval * m_active_block_interval_overload_skip, &elapsed_time))
do { // breakable do { // breakable
if (m_active_block_interval_overload_skip > 0) {
ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
m_active_block_interval_overload_skip--;
break;
}
ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG); ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
TimeTaker timer("modify in active blocks per interval"); TimeTaker timer("modify in active blocks per interval");
// Initialize handling of ActiveBlockModifiers // Initialize handling of ActiveBlockModifiers
ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true); ABMHandler abmhandler(m_abms, elapsed_time, this, true);
for (const v3s16 &p : m_active_blocks.m_abm_list) { for (const v3s16 &p : m_active_blocks.m_abm_list) {
MapBlock *block = m_map->getBlockNoCreateNoEx(p); MapBlock *block = m_map->getBlockNoCreateNoEx(p);
@ -1296,13 +1291,16 @@ void ServerEnvironment::step(float dtime)
abmhandler.apply(block); abmhandler.apply(block);
} }
u32 time_ms = timer.stop(true); const u32 time_ms = timer.stop(true);
u32 max_time_ms = 200; // allow up to 10% of the budget interval
const u32 max_time_ms = m_cache_abm_interval * 1000.0f * 0.1f;
if (time_ms > max_time_ms) { if (time_ms > max_time_ms) {
warningstream<<"active block modifiers took " warningstream << "active block modifiers took "
<<time_ms<<"ms (longer than " << time_ms << "ms (longer than "
<<max_time_ms<<"ms)"<<std::endl; << max_time_ms << "ms)" << std::endl;
m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1; m_active_block_interval_overload_skip = ((float)time_ms / max_time_ms);
} else {
m_active_block_interval_overload_skip = 1.0f;
} }
}while(0); }while(0);
@ -1314,15 +1312,17 @@ void ServerEnvironment::step(float dtime)
/* /*
Step active objects Step active objects
*/ */
{ if (m_active_object_interval.step(dtime,
m_cache_ao_interval * m_active_object_interval_overload_skip, &elapsed_time)) {
ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG); ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
//TimeTaker timer("Step active objects"); TimeTaker timer("Step active objects");
g_profiler->avg("SEnv: num of objects", m_active_objects.size()); g_profiler->avg("SEnv: num of objects", m_active_objects.size());
// This helps the objects to send data at the same time // This helps the objects to send data at the same time
bool send_recommended = false; bool send_recommended = false;
m_send_recommended_timer += dtime; m_send_recommended_timer += elapsed_time;
if(m_send_recommended_timer > getSendRecommendedInterval()) if(m_send_recommended_timer > getSendRecommendedInterval())
{ {
m_send_recommended_timer -= getSendRecommendedInterval(); m_send_recommended_timer -= getSendRecommendedInterval();
@ -1335,13 +1335,28 @@ void ServerEnvironment::step(float dtime)
continue; continue;
// Step object // Step object
obj->step(dtime, send_recommended); obj->step(elapsed_time, send_recommended);
// Read messages from object // Read messages from object
while (!obj->m_messages_out.empty()) { while (!obj->m_messages_out.empty()) {
m_active_object_messages.push(obj->m_messages_out.front()); m_active_object_messages.push(obj->m_messages_out.front());
obj->m_messages_out.pop(); obj->m_messages_out.pop();
} }
} }
// calculate a simple moving average
m_avg_ao_time = m_avg_ao_time * 0.9f + timer.stop(true) * 0.1f;
// allow up to 20% of the budget interval
const float max_time_ms = m_cache_ao_interval * 1000.0f * 0.2f;
if (m_avg_ao_time > max_time_ms) {
warningstream << "active objects took "
<< m_avg_ao_time << "ms (longer than "
<< max_time_ms << "ms)" << std::endl;
// skip a few steps
m_active_object_interval_overload_skip = m_avg_ao_time / max_time_ms;
} else {
m_active_object_interval_overload_skip = 1.0f;
}
} }
/* /*

@ -422,8 +422,11 @@ private:
ActiveBlockList m_active_blocks; ActiveBlockList m_active_blocks;
IntervalLimiter m_active_blocks_management_interval; IntervalLimiter m_active_blocks_management_interval;
IntervalLimiter m_active_block_modifier_interval; IntervalLimiter m_active_block_modifier_interval;
IntervalLimiter m_active_object_interval;
IntervalLimiter m_active_blocks_nodemetadata_interval; IntervalLimiter m_active_blocks_nodemetadata_interval;
int m_active_block_interval_overload_skip = 0; float m_active_block_interval_overload_skip = 1.0f;
float m_active_object_interval_overload_skip = 1.0f;
float m_avg_ao_time = 0.0f;
// Time from the beginning of the game in seconds. // Time from the beginning of the game in seconds.
// Incremented in step(). // Incremented in step().
u32 m_game_time = 0; u32 m_game_time = 0;

@ -230,7 +230,7 @@ inline u32 calc_parity(u32 v)
u64 murmur_hash_64_ua(const void *key, int len, unsigned int seed); u64 murmur_hash_64_ua(const void *key, int len, unsigned int seed);
bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
f32 camera_fov, f32 range, f32 *distance_ptr=NULL); f32 camera_fov, f32 range, f32 *distance_ptr = NULL);
s16 adjustDist(s16 dist, float zoom_fov); s16 adjustDist(s16 dist, float zoom_fov);
@ -291,18 +291,24 @@ public:
return value: return value:
true: action should be skipped true: action should be skipped
false: action should be done false: action should be done
if passed, the elapsed time since this method last returned true
is written to elapsed_ptr
*/ */
bool step(float dtime, float wanted_interval) bool step(float dtime, float wanted_interval, float *elapsed_ptr = NULL)
{ {
m_accumulator += dtime; m_accumulator += dtime;
if (elapsed_ptr)
*elapsed_ptr = m_accumulator - m_last_accumulator;
if (m_accumulator < wanted_interval) if (m_accumulator < wanted_interval)
return false; return false;
m_accumulator -= wanted_interval; m_accumulator -= wanted_interval;
m_last_accumulator = m_accumulator;
return true; return true;
} }
private: private:
float m_accumulator = 0.0f; float m_accumulator = 0.0f;
float m_last_accumulator = 0.0f;
}; };