Improve ABM time budget handling. #8645
authorLars Hofhansl <larsh@apache.org>
Mon, 8 Jul 2019 06:23:00 +0000 (23:23 -0700)
committerLars Hofhansl <larsh@apache.org>
Mon, 8 Jul 2019 06:23:00 +0000 (23:23 -0700)
src/serverenvironment.cpp
src/serverenvironment.h

index 0a83c4a38e421db8efd9531fe501c4067d990464..3c473313049fcb930cb35375395d1f15b8ef826b 100644 (file)
@@ -384,6 +384,9 @@ void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players,
        ServerEnvironment
 */
 
+// Random device to seed pseudo random generators.
+static std::random_device seed;
+
 ServerEnvironment::ServerEnvironment(ServerMap *map,
        ServerScripting *scriptIface, Server *server,
        const std::string &path_world):
@@ -391,7 +394,8 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
        m_map(map),
        m_script(scriptIface),
        m_server(server),
-       m_path_world(path_world)
+       m_path_world(path_world),
+       m_rgen(seed())
 {
        // Determine which database backend to use
        std::string conf_path = path_world + DIR_DELIM + "world.mt";
@@ -1338,47 +1342,56 @@ void ServerEnvironment::step(float dtime)
                }
        }
 
-       if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval))
-               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);
-                       TimeTaker timer("modify in active blocks per interval");
-
-                       // 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)
-                                       continue;
+       if (m_active_block_modifier_interval.step(dtime, m_cache_abm_interval)) {
+               ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg per interval", SPT_AVG);
+               TimeTaker timer("modify in active blocks per interval");
 
-                               // Set current time as timestamp
-                               block->setTimestampNoChangedFlag(m_game_time);
+               // Initialize handling of ActiveBlockModifiers
+               ABMHandler abmhandler(m_abms, m_cache_abm_interval, this, true);
 
-                               /* Handle ActiveBlockModifiers */
-                               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);
+               int blocks_scanned = 0;
+               int abms_run = 0;
+               int blocks_cached = 0;
+
+               std::vector<v3s16> output(m_active_blocks.m_abm_list.size());
+
+               // Shuffle the active blocks so that each block gets an equal chance
+               // of having its ABMs run.
+               std::copy(m_active_blocks.m_abm_list.begin(), m_active_blocks.m_abm_list.end(), output.begin());
+               std::shuffle(output.begin(), output.end(), m_rgen);
+
+               int i = 0;
+               // The time budget for ABMs is 20%.
+               u32 max_time_ms = m_cache_abm_interval * 1000 / 5;
+               for (const v3s16 &p : output) {
+                       MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+                       if (!block)
+                               continue;
+
+                       i++;
+
+                       // Set current time as timestamp
+                       block->setTimestampNoChangedFlag(m_game_time);
+
+                       /* Handle ActiveBlockModifiers */
+                       abmhandler.apply(block, blocks_scanned, abms_run, blocks_cached);
+
+                       u32 time_ms = timer.getTimerTime();
 
-                       u32 time_ms = timer.stop(true);
-                       u32 max_time_ms = 200;
                        if (time_ms > max_time_ms) {
-                               warningstream<<"active block modifiers took "
-                                       <<time_ms<<"ms (longer than "
-                                       <<max_time_ms<<"ms)"<<std::endl;
-                               m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
+                               warningstream << "active block modifiers took "
+                                         << time_ms << "ms (processed " << i << " of "
+                                         << output.size() << " active blocks)" << std::endl;
+                               break;
                        }
-               }while(0);
+               }
+               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);
+
+               timer.stop(true);
+       }
 
        /*
                Step script environment (run global on_step())
index 77adcf6274538641baedeb464c7188de04406014..cc4ecd797eae3f829d90f63dd12ffa3da15d41d8 100644 (file)
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "server/activeobjectmgr.h"
 #include "util/numeric.h"
 #include <set>
+#include <random>
 
 class IGameDef;
 class ServerMap;
@@ -446,7 +447,6 @@ private:
        IntervalLimiter m_active_blocks_management_interval;
        IntervalLimiter m_active_block_modifier_interval;
        IntervalLimiter m_active_blocks_nodemetadata_interval;
-       int m_active_block_interval_overload_skip = 0;
        // Time from the beginning of the game in seconds.
        // Incremented in step().
        u32 m_game_time = 0;
@@ -470,6 +470,9 @@ private:
        PlayerDatabase *m_player_database = nullptr;
        AuthDatabase *m_auth_database = nullptr;
 
+       // Pseudo random generator for shuffling, etc.
+       std::mt19937 m_rgen;
+
        // Particles
        IntervalLimiter m_particle_management_interval;
        std::unordered_map<u32, float> m_particle_spawners;