From 4773a8a6260d245b944bca3cd57114cbfd6908c7 Mon Sep 17 00:00:00 2001 From: Lohikar Date: Sat, 14 Oct 2017 11:31:14 -0500 Subject: [PATCH] MC Performance Tweaks (#3621) Ports some StonedMC performance tweaks from /tg/, should reduce the amount of fighting between BYOND sleeps and the MC. --- aurorastation.dme | 1 + code/__defines/master_controller.dm | 2 +- code/__defines/time.dm | 18 ++++++++++++++ code/_helpers/maths.dm | 4 +-- code/_helpers/time.dm | 12 --------- code/_helpers/unsorted.dm | 15 +++++++----- code/controllers/master/master.dm | 38 +++++++++++++++++------------ code/modules/client/client procs.dm | 3 +-- 8 files changed, 55 insertions(+), 38 deletions(-) create mode 100644 code/__defines/time.dm diff --git a/aurorastation.dme b/aurorastation.dme index caba9c3bcf7..50bdaaffd05 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -45,6 +45,7 @@ #include "code\__defines\subsystem-defines.dm" #include "code\__defines\subsystem-priority.dm" #include "code\__defines\targeting.dm" +#include "code\__defines\time.dm" #include "code\__defines\turfs.dm" #include "code\__defines\ZAS.dm" #include "code\_helpers\area_movement.dm" diff --git a/code/__defines/master_controller.dm b/code/__defines/master_controller.dm index 89a37a64c8e..c62390d5554 100644 --- a/code/__defines/master_controller.dm +++ b/code/__defines/master_controller.dm @@ -1,5 +1,5 @@ #define TICK_LIMIT_RUNNING 80 -#define TICK_LIMIT_TO_RUN 78 +#define TICK_LIMIT_TO_RUN 70 #define TICK_LIMIT_MC 70 #define TICK_LIMIT_MC_INIT config.mc_init_tick_limit #define TICK_LIMIT_MC_INIT_DEFAULT 98 diff --git a/code/__defines/time.dm b/code/__defines/time.dm new file mode 100644 index 00000000000..5ec3ac984a6 --- /dev/null +++ b/code/__defines/time.dm @@ -0,0 +1,18 @@ +#define SECOND *10 +#define SECONDS *10 + +#define MINUTE *600 +#define MINUTES *600 + +#define HOUR *36000 +#define HOURS *36000 + +#define DAY *864000 +#define DAYS *864000 + + +#define TICKS *world.tick_lag + +#define DS2TICKS(DS) (DS/world.tick_lag) + +#define TICKS2DS(T) (T TICKS) diff --git a/code/_helpers/maths.dm b/code/_helpers/maths.dm index e7571754ac2..f2e94d28884 100644 --- a/code/_helpers/maths.dm +++ b/code/_helpers/maths.dm @@ -28,8 +28,8 @@ /proc/Floor(x) return round(x) -/proc/Ceiling(x) - return -round(-x) +/proc/Ceiling(x, y=1) + return -round(-x / y) * y // Greatest Common Divisor: Euclid's algorithm. /proc/Gcd(a, b) diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm index 383dc93b504..020c21c3b81 100644 --- a/code/_helpers/time.dm +++ b/code/_helpers/time.dm @@ -1,15 +1,3 @@ -#define SECOND *10 -#define SECONDS *10 - -#define MINUTE *600 -#define MINUTES *600 - -#define HOUR *36000 -#define HOURS *36000 - -#define DAY *864000 -#define DAYS *864000 - var/roundstart_hour = 0 var/round_start_time diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index cc3cb8df6f6..a9435849e8d 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -664,7 +664,7 @@ proc/GaussRandRound(var/sigma,var/roundto) . = 1 while (world.time < endtime) - stoplag() + stoplag(1) if (progbar) progbar.update(world.time - starttime) @@ -704,7 +704,7 @@ proc/GaussRandRound(var/sigma,var/roundto) . = 1 while (world.time < endtime) - stoplag() + stoplag(1) if (progbar) progbar.update(world.time - starttime) @@ -1088,19 +1088,22 @@ var/list/wall_items = typecacheof(list( //Increases delay as the server gets more overloaded, //as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful -#define DELTA_CALC max(((max(world.tick_usage, world.cpu) / 100) * max(Master.sleep_delta,1)), 1) +#define DELTA_CALC max(((max(world.tick_usage, world.cpu) / 100) * max(Master.sleep_delta-1,1)), 1) -/proc/stoplag() +/proc/stoplag(initial_delay) // If we're initializing, our tick limit might be over 100 (testing config), but stoplag() penalizes procs that go over. // Unfortunately, this penalty slows down init a *lot*. So, we disable it during boot and lobby, when relatively few things should be calling this. if (!Master || Master.initializing || !Master.round_started) sleep(world.tick_lag) return 1 + if (!initial_delay) + initial_delay = world.tick_lag + . = 0 - var/i = 1 + var/i = DS2TICKS(initial_delay) do - . += round(i*DELTA_CALC) + . += Ceiling(i*DELTA_CALC) sleep(i*world.tick_lag*DELTA_CALC) i *= 2 while (world.tick_usage > min(TICK_LIMIT_TO_RUN, CURRENT_TICKLIMIT)) diff --git a/code/controllers/master/master.dm b/code/controllers/master/master.dm index 4d31c95721b..a2566a1414b 100644 --- a/code/controllers/master/master.dm +++ b/code/controllers/master/master.dm @@ -31,7 +31,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING var/init_time var/tickdrift = 0 - var/sleep_delta + var/sleep_delta = 1 var/make_runtime = 0 @@ -266,33 +266,40 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING iteration = 1 var/error_level = 0 - var/sleep_delta = 0 + var/sleep_delta = 1 var/list/subsystems_to_check //the actual loop. while (1) tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag))) + var/starting_tick_usage = world.tick_usage if (processing <= 0) CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING sleep(10) continue - //if there are mutiple sleeping procs running before us hogging the cpu, we have to run later - // because sleeps are processed in the order received, so longer sleeps are more likely to run first - if (world.tick_usage > TICK_LIMIT_MC) - sleep_delta += 2 - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5) - sleep(world.tick_lag * (processing + sleep_delta)) + //Anti-tick-contention heuristics: + //if there are mutiple sleeping procs running before us hogging the cpu, we have to run later. + // (because sleeps are processed in the order received, longer sleeps are more likely to run first) + if (starting_tick_usage > TICK_LIMIT_MC) + sleep_delta *= 2 + CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5 + sleep(world.tick_lag * (processing * sleep_delta)) continue - sleep_delta = MC_AVERAGE_FAST(sleep_delta, 0) - if (last_run + (world.tick_lag * processing) > world.time) - sleep_delta += 1 - if (world.tick_usage > (TICK_LIMIT_MC*0.5)) + //Byond resumed us late. assume it might have to do the same next tick + if (last_run + Ceiling(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time) sleep_delta += 1 + sleep_delta = MC_AVERAGE_FAST(sleep_delta, 1) //decay sleep_delta + + if (starting_tick_usage > (TICK_LIMIT_MC*0.75)) //we ran 3/4 of the way into the tick + sleep_delta += 1 + + // debug if (make_runtime) var/datum/controller/subsystem/SS SS.can_fire = 0 + if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time)) new/datum/controller/failsafe() // (re)Start the failsafe. if (!queue_head || !(iteration % 3)) @@ -332,10 +339,11 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING iteration++ last_run = world.time src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta) - CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc. - sleep(world.tick_lag * (processing + sleep_delta)) - + CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING + if (processing * sleep_delta <= world.tick_lag) + CURRENT_TICKLIMIT -= (TICK_LIMIT_RUNNING) + sleep(world.tick_lag * (processing * sleep_delta)) // This is what decides if something should run. diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 2f378566afe..08ee056de9b 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -660,5 +660,4 @@ if (holder) sleep(1) else - sleep(5) - stoplag() + stoplag(5)