mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 13:38:41 +01:00
MC: tweaks, midnight rollover fix, and some 510 work
Fixes the mc getting all fucked up during midnight rollover Mc now tracks the tick_usage of every subsystem, and will skip running an expensive subsystem if we are too close to overrunning in a tick, waiting until next tick, unless that subsystem is excessively past due (because we kept skipping it). It now assumes that 20% of a tick should be saved for byond to do it's things, and stops running all subsystems once we get to 80% tick usage. Dynamic wait will only smooth out wait changes over 8 fires if the new wait is lower than the old wait, before it would smooth out wait increases as well as decreases. The fps throttle system is now 509 only. The mc will now run every 1ds, no GCD bullshit, as we want to spread things out more. Offline subsystems will still show their stat message DS is now rounded to 2 digits, not 3, to make room for the tick percentage bit, and because the 3rd digit was useless and all MoE
This commit is contained in:
+31
-33
@@ -21,8 +21,10 @@ var/global/datum/controller/master/Master = new()
|
||||
var/iteration = 0
|
||||
// The cost (in deciseconds) of the MC loop.
|
||||
var/cost = 0
|
||||
#if DM_VERSION < 510
|
||||
// The old fps when we slow it down to prevent lag.
|
||||
var/old_fps
|
||||
#endif
|
||||
// A list of subsystems to process().
|
||||
var/list/subsystems = list()
|
||||
// The cost of running the subsystems (in deciseconds).
|
||||
@@ -39,7 +41,6 @@ var/global/datum/controller/master/Master = new()
|
||||
else
|
||||
init_subtypes(/datum/subsystem, subsystems)
|
||||
Master = src
|
||||
processing_interval = calculate_gcd()
|
||||
|
||||
/datum/controller/master/Destroy()
|
||||
..()
|
||||
@@ -109,7 +110,9 @@ var/global/datum/controller/master/Master = new()
|
||||
SS.next_fire = world.time + rand(0, SS.wait) // Stagger subsystems.
|
||||
|
||||
// Used to smooth out costs to try and avoid oscillation.
|
||||
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
|
||||
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
|
||||
#define MC_AVERAGE_SLOW(average, current) (0.9 * (average) + 0.1 * (current))
|
||||
/datum/controller/master/process()
|
||||
if(!Failsafe)
|
||||
new/datum/controller/failsafe() // (re)Start the failsafe.
|
||||
@@ -129,29 +132,44 @@ var/global/datum/controller/master/Master = new()
|
||||
|
||||
var/ran_subsystems = 0
|
||||
for(var/datum/subsystem/SS in subsystems)
|
||||
#if DM_VERSION >= 510
|
||||
if (world.tick_usage > 80)
|
||||
#else
|
||||
if(world.cpu >= 100)
|
||||
//if world.cpu gets above 120,
|
||||
//byond will pause most client updates for (about) 1.6 seconds.
|
||||
//(1.6 seconds worth of ticks)
|
||||
//We just stop running subsystems to avoid that.
|
||||
#endif
|
||||
break
|
||||
|
||||
if(SS.can_fire > 0)
|
||||
if(SS.next_fire <= world.time && SS.last_fire + (SS.wait * 0.75) <= world.time) // Check if it's time.
|
||||
#if DM_VERSION >= 510
|
||||
if (world.tick_usage + SS.tick_usage > 80 && SS.last_fire + (SS.wait*1.25) > world.time)
|
||||
continue
|
||||
#endif
|
||||
ran_subsystems = 1
|
||||
timer = world.timeofday
|
||||
last_type_processed = SS.type
|
||||
SS.last_fire = world.time
|
||||
#if DM_VERSION >= 510
|
||||
var/tick_usage = world.tick_usage
|
||||
#endif
|
||||
SS.fire() // Fire the subsystem and record the cost.
|
||||
SS.cost = MC_AVERAGE(SS.cost, world.timeofday - timer)
|
||||
#if DM_VERSION >= 510
|
||||
var/newusage = max(world.tick_usage - tick_usage, 0)
|
||||
if (newusage < SS.tick_usage)
|
||||
SS.tick_usage = MC_AVERAGE_SLOW(SS.tick_usage,world.tick_usage - tick_usage)
|
||||
else
|
||||
SS.tick_usage = MC_AVERAGE_FAST(SS.tick_usage,world.tick_usage - tick_usage)
|
||||
#endif
|
||||
SS.cost = max(MC_AVERAGE(SS.cost, world.timeofday - timer), 0)
|
||||
if(SS.dynamic_wait) // Adjust wait depending on lag.
|
||||
var/oldwait = SS.wait
|
||||
var/global_delta = (subsystem_cost - (SS.cost / (SS.wait / 10))) - 1
|
||||
var/newwait = (SS.cost - SS.dwait_buffer + global_delta) * SS.dwait_delta
|
||||
newwait = newwait * (world.cpu / 100 + 1)
|
||||
newwait = MC_AVERAGE(oldwait, newwait)
|
||||
//smooth out wait changes, but only if going down
|
||||
if(newwait < oldwait)
|
||||
newwait = MC_AVERAGE(oldwait, newwait)
|
||||
SS.wait = Clamp(newwait, SS.dwait_lower, SS.dwait_upper)
|
||||
if(oldwait != SS.wait)
|
||||
processing_interval = calculate_gcd()
|
||||
SS.next_fire = world.time + SS.wait
|
||||
else
|
||||
SS.next_fire += SS.wait
|
||||
@@ -161,7 +179,7 @@ var/global/datum/controller/master/Master = new()
|
||||
break
|
||||
sleep(0)
|
||||
|
||||
cost = MC_AVERAGE(cost, world.timeofday - start_time)
|
||||
cost = max(MC_AVERAGE(cost, world.timeofday - start_time), 0)
|
||||
if(ran_subsystems)
|
||||
var/oldcost = subsystem_cost
|
||||
var/newcost = 0
|
||||
@@ -172,13 +190,10 @@ var/global/datum/controller/master/Master = new()
|
||||
subsystem_cost = MC_AVERAGE(oldcost, newcost)
|
||||
|
||||
var/extrasleep = 0
|
||||
// If we caused BYOND to miss a tick, sleep a bit extra...
|
||||
if(startingtick < world.time || start_time + 1 < world.timeofday)
|
||||
extrasleep += world.tick_lag * 2
|
||||
// If we are loading the server too much, sleep a bit extra...
|
||||
if(world.cpu >= 75)
|
||||
extrasleep += (extrasleep + processing_interval) * ((world.cpu-50)/10)
|
||||
|
||||
#if DM_VERSION < 510
|
||||
if(world.cpu >= 100)
|
||||
if(!old_fps)
|
||||
old_fps = world.fps
|
||||
@@ -187,33 +202,16 @@ var/global/datum/controller/master/Master = new()
|
||||
else if(old_fps && world.cpu < 50)
|
||||
world.fps = old_fps
|
||||
old_fps = null
|
||||
|
||||
#endif
|
||||
sleep(processing_interval + extrasleep)
|
||||
|
||||
else
|
||||
sleep(50)
|
||||
#undef MC_AVERAGE
|
||||
|
||||
// Determine the GCD of subsystem waits: the longest the MC can wait while still staying on schedule.
|
||||
/datum/controller/master/proc/calculate_gcd()
|
||||
var/GCD
|
||||
// The shortest possible fire rate is the lowest of two ticks or 1 decisecond.
|
||||
var/minimumInterval = min(world.tick_lag * 2, 1)
|
||||
|
||||
// Loop over each subsystem and determine the GCD based on its wait value.
|
||||
for(var/datum/subsystem/SS in subsystems)
|
||||
if(SS.wait)
|
||||
GCD = Gcd(round(SS.wait * 10), GCD)
|
||||
GCD = round(GCD)
|
||||
// If the GCD is less than the minimum, just use the minimum.
|
||||
if(GCD < minimumInterval * 10)
|
||||
GCD = minimumInterval * 10
|
||||
// Return GCD.
|
||||
return GCD / 10
|
||||
|
||||
/datum/controller/master/proc/stat_entry()
|
||||
if(!statclick)
|
||||
statclick = new/obj/effect/statclick/debug("Initializing...", src)
|
||||
|
||||
stat("Master Controller:", statclick.update("[round(Master.cost, 0.001)]ds (Interval: [Master.processing_interval] | Iteration:[Master.iteration])"))
|
||||
stat("Master Controller:", statclick.update("[round(Master.cost, 0.01)]ds (Interval: [Master.processing_interval] | Iteration:[Master.iteration])"))
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
var/last_fire = 0 //last world.time we called fire()
|
||||
var/next_fire = 0 //scheduled world.time for next fire()
|
||||
var/cost = 0 //average time to execute
|
||||
#if DM_VERSION >= 510
|
||||
var/tick_usage = 0 //average tick usage
|
||||
#endif
|
||||
var/times_fired = 0 //number of times we have called fire()
|
||||
|
||||
// The object used for the clickable stat() button.
|
||||
@@ -59,9 +62,13 @@
|
||||
dwait = "DWait:[round(wait,0.1)]ds "
|
||||
|
||||
if(can_fire)
|
||||
msg = "[round(cost,0.001)]ds\t[dwait][msg]"
|
||||
#if DM_VERSION >= 510
|
||||
msg = "[round(cost,0.01)]ds|[round(tick_usage,1)]%\t[dwait][msg]"
|
||||
#else
|
||||
msg = "[round(cost,0.01)]ds\t[dwait][msg]"
|
||||
#endif
|
||||
else
|
||||
msg = "OFFLINE"
|
||||
msg = "OFFLINE\t[msg]"
|
||||
|
||||
stat(name, statclick.update(msg))
|
||||
|
||||
@@ -79,4 +86,4 @@
|
||||
/datum/subsystem/on_varedit(edited_var)
|
||||
if (edited_var == "can_fire" && can_fire)
|
||||
next_fire = world.time + wait
|
||||
|
||||
|
||||
|
||||
@@ -600,7 +600,7 @@ var/next_mob_id = 0
|
||||
else
|
||||
stat("Failsafe Controller:", "ERROR")
|
||||
if(Master)
|
||||
stat("Subsystems:", "[round(Master.subsystem_cost, 0.001)]ds")
|
||||
stat("Subsystems:", "[round(Master.subsystem_cost, 0.01)]ds")
|
||||
stat(null)
|
||||
for(var/datum/subsystem/SS in Master.subsystems)
|
||||
SS.stat_entry()
|
||||
|
||||
Reference in New Issue
Block a user