MC Performance Tweaks (#3621)

Ports some StonedMC performance tweaks from /tg/, should reduce the amount of fighting between BYOND sleeps and the MC.
This commit is contained in:
Lohikar
2017-10-14 19:31:14 +03:00
committed by Erki
parent 37908e5c4b
commit 4773a8a626
8 changed files with 55 additions and 38 deletions
+1
View File
@@ -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"
+1 -1
View File
@@ -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
+18
View File
@@ -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)
+2 -2
View File
@@ -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)
-12
View File
@@ -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
+9 -6
View File
@@ -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))
+23 -15
View File
@@ -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.
+1 -2
View File
@@ -660,5 +660,4 @@
if (holder)
sleep(1)
else
sleep(5)
stoplag()
stoplag(5)