mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
Ports /tg controller optimizations
https://github.com/tgstation/tgstation/pull/31092 - Fixes subsystems not returning a qdel hint https://github.com/tgstation/tgstation/pull/31494 - In which the stoner one gets stoned and tries to address tick contention... again https://github.com/tgstation/tgstation/pull/31950 - Removes an empty New() https://github.com/tgstation/tgstation/pull/31951 - Logs subsystem shutdowns
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
#define TICK_LIMIT_RUNNING 80
|
#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 70
|
||||||
#define TICK_LIMIT_MC_INIT_DEFAULT 98
|
#define TICK_LIMIT_MC_INIT_DEFAULT 98
|
||||||
|
|
||||||
|
|||||||
@@ -8,3 +8,7 @@
|
|||||||
//for when you need a reliable time number that doesn't depend on byond time.
|
//for when you need a reliable time number that doesn't depend on byond time.
|
||||||
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
|
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
|
||||||
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
|
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
|
||||||
|
|
||||||
|
#define CEILING(x, y) ( -round(-(x) / (y)) * (y) )
|
||||||
|
// round() acts like floor(x, 1) by default but can't handle other values
|
||||||
|
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ Proc for attack log creation, because really why not
|
|||||||
var/starttime = world.time
|
var/starttime = world.time
|
||||||
. = 1
|
. = 1
|
||||||
while (world.time < endtime)
|
while (world.time < endtime)
|
||||||
sleep(1)
|
stoplag(1)
|
||||||
if (progress)
|
if (progress)
|
||||||
progbar.update(world.time - starttime)
|
progbar.update(world.time - starttime)
|
||||||
if(!user || !target)
|
if(!user || !target)
|
||||||
@@ -229,7 +229,7 @@ Proc for attack log creation, because really why not
|
|||||||
var/starttime = world.time
|
var/starttime = world.time
|
||||||
. = 1
|
. = 1
|
||||||
while (world.time < endtime)
|
while (world.time < endtime)
|
||||||
sleep(1)
|
stoplag(1)
|
||||||
if (progress)
|
if (progress)
|
||||||
progbar.update(world.time - starttime)
|
progbar.update(world.time - starttime)
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
#define TimeOfGame (get_game_time())
|
#define TimeOfGame (get_game_time())
|
||||||
#define TimeOfTick (TICK_USAGE*0.01*world.tick_lag)
|
#define TimeOfTick (TICK_USAGE*0.01*world.tick_lag)
|
||||||
|
|
||||||
|
#define TICK *world.tick_lag
|
||||||
|
#define TICKS *world.tick_lag
|
||||||
|
|
||||||
|
#define DS2TICKS(DS) (DS/world.tick_lag) // Convert deciseconds to ticks
|
||||||
|
#define TICKS2DS(T) (T TICKS) // Convert ticks to deciseconds
|
||||||
|
|
||||||
/proc/get_game_time()
|
/proc/get_game_time()
|
||||||
var/global/time_offset = 0
|
var/global/time_offset = 0
|
||||||
var/global/last_time = 0
|
var/global/last_time = 0
|
||||||
@@ -111,13 +117,21 @@ var/round_start_time = 0
|
|||||||
|
|
||||||
//Increases delay as the server gets more overloaded,
|
//Increases delay as the server gets more overloaded,
|
||||||
//as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful
|
//as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful
|
||||||
#define DELTA_CALC max(((max(TICK_USAGE, world.cpu) / 100) * max(Master.sleep_delta,1)), 1)
|
#define DELTA_CALC max(((max(TICK_USAGE, world.cpu) / 100) * max(Master.sleep_delta-1,1)), 1)
|
||||||
|
|
||||||
/proc/stoplag()
|
//returns the number of ticks slept
|
||||||
|
/proc/stoplag(initial_delay)
|
||||||
|
if (!Master || !(Master.current_runlevel & RUNLEVELS_DEFAULT))
|
||||||
|
sleep(world.tick_lag)
|
||||||
|
return 1
|
||||||
|
if (!initial_delay)
|
||||||
|
initial_delay = world.tick_lag
|
||||||
. = 0
|
. = 0
|
||||||
var/i = 1
|
var/i = DS2TICKS(initial_delay)
|
||||||
do
|
do
|
||||||
. += round(i*DELTA_CALC)
|
. += CEILING(i*DELTA_CALC, 1)
|
||||||
sleep(i*world.tick_lag*DELTA_CALC)
|
sleep(i*world.tick_lag*DELTA_CALC)
|
||||||
i *= 2
|
i *= 2
|
||||||
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
|
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
|
||||||
|
|
||||||
|
#undef DELTA_CALC
|
||||||
@@ -12,7 +12,7 @@ var/datum/controller/master/Master = new()
|
|||||||
name = "Master"
|
name = "Master"
|
||||||
|
|
||||||
// Are we processing (higher values increase the processing delay by n ticks)
|
// Are we processing (higher values increase the processing delay by n ticks)
|
||||||
var/processing = 1
|
var/processing = TRUE
|
||||||
// How many times have we ran
|
// How many times have we ran
|
||||||
var/iteration = 0
|
var/iteration = 0
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ var/datum/controller/master/Master = new()
|
|||||||
var/init_time
|
var/init_time
|
||||||
var/tickdrift = 0
|
var/tickdrift = 0
|
||||||
|
|
||||||
var/sleep_delta
|
var/sleep_delta = 1
|
||||||
|
|
||||||
var/make_runtime = 0
|
var/make_runtime = 0
|
||||||
|
|
||||||
@@ -77,7 +77,9 @@ var/datum/controller/master/Master = new()
|
|||||||
sortTim(subsystems, /proc/cmp_subsystem_init)
|
sortTim(subsystems, /proc/cmp_subsystem_init)
|
||||||
reverseRange(subsystems)
|
reverseRange(subsystems)
|
||||||
for(var/datum/controller/subsystem/ss in subsystems)
|
for(var/datum/controller/subsystem/ss in subsystems)
|
||||||
|
log_world("Shutting down [ss.name] subsystem...")
|
||||||
ss.Shutdown()
|
ss.Shutdown()
|
||||||
|
log_world("Shutdown complete")
|
||||||
|
|
||||||
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
// Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart,
|
||||||
// -1 if we encountered a runtime trying to recreate it
|
// -1 if we encountered a runtime trying to recreate it
|
||||||
@@ -91,7 +93,7 @@ var/datum/controller/master/Master = new()
|
|||||||
var/delay = 50 * ++Master.restart_count
|
var/delay = 50 * ++Master.restart_count
|
||||||
Master.restart_timeout = world.time + delay
|
Master.restart_timeout = world.time + delay
|
||||||
Master.restart_clear = world.time + (delay * 2)
|
Master.restart_clear = world.time + (delay * 2)
|
||||||
Master.processing = 0 //stop ticking this one
|
Master.processing = FALSE //stop ticking this one
|
||||||
try
|
try
|
||||||
new/datum/controller/master()
|
new/datum/controller/master()
|
||||||
catch
|
catch
|
||||||
@@ -267,35 +269,45 @@ var/datum/controller/master/Master = new()
|
|||||||
|
|
||||||
iteration = 1
|
iteration = 1
|
||||||
var/error_level = 0
|
var/error_level = 0
|
||||||
var/sleep_delta = 0
|
var/sleep_delta = 1
|
||||||
var/list/subsystems_to_check
|
var/list/subsystems_to_check
|
||||||
//the actual loop.
|
//the actual loop.
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
|
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
|
||||||
|
var/starting_tick_usage = TICK_USAGE
|
||||||
if (processing <= 0)
|
if (processing <= 0)
|
||||||
current_ticklimit = TICK_LIMIT_RUNNING
|
current_ticklimit = TICK_LIMIT_RUNNING
|
||||||
sleep(10)
|
sleep(10)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
//if there are mutiple sleeping procs running before us hogging the cpu, we have to run later
|
//Anti-tick-contention heuristics:
|
||||||
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
|
//if there are mutiple sleeping procs running before us hogging the cpu, we have to run later.
|
||||||
if (TICK_USAGE > TICK_LIMIT_MC)
|
// (because sleeps are processed in the order received, longer sleeps are more likely to run first)
|
||||||
sleep_delta += 2
|
if (starting_tick_usage > TICK_LIMIT_MC) //if there isn't enough time to bother doing anything this tick, sleep a bit.
|
||||||
|
sleep_delta *= 2
|
||||||
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
|
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
|
||||||
sleep(world.tick_lag * (processing + sleep_delta))
|
sleep(world.tick_lag * (processing * sleep_delta))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
sleep_delta = MC_AVERAGE_FAST(sleep_delta, 0)
|
//Byond resumed us late. assume it might have to do the same next tick
|
||||||
if (last_run + (world.tick_lag * processing) > world.time)
|
if (last_run + CEILING(world.tick_lag * (processing * sleep_delta), world.tick_lag) < world.time)
|
||||||
sleep_delta += 1
|
|
||||||
if (TICK_USAGE > (TICK_LIMIT_MC*0.5))
|
|
||||||
sleep_delta += 1
|
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)
|
if (make_runtime)
|
||||||
var/datum/controller/subsystem/SS
|
var/datum/controller/subsystem/SS
|
||||||
SS.can_fire = 0
|
SS.can_fire = 0
|
||||||
|
|
||||||
if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time))
|
if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time))
|
||||||
new/datum/controller/failsafe() // (re)Start the failsafe.
|
new/datum/controller/failsafe() // (re)Start the failsafe.
|
||||||
|
|
||||||
|
//now do the actual stuff
|
||||||
if (!queue_head || !(iteration % 3))
|
if (!queue_head || !(iteration % 3))
|
||||||
var/checking_runlevel = current_runlevel
|
var/checking_runlevel = current_runlevel
|
||||||
if(cached_runlevel != checking_runlevel)
|
if(cached_runlevel != checking_runlevel)
|
||||||
@@ -312,6 +324,7 @@ var/datum/controller/master/Master = new()
|
|||||||
subsystems_to_check = current_runlevel_subsystems
|
subsystems_to_check = current_runlevel_subsystems
|
||||||
else
|
else
|
||||||
subsystems_to_check = tickersubsystems
|
subsystems_to_check = tickersubsystems
|
||||||
|
|
||||||
if (CheckQueue(subsystems_to_check) <= 0)
|
if (CheckQueue(subsystems_to_check) <= 0)
|
||||||
if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
|
if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
|
||||||
log_world("MC: SoftReset() failed, crashing")
|
log_world("MC: SoftReset() failed, crashing")
|
||||||
@@ -342,8 +355,10 @@ var/datum/controller/master/Master = new()
|
|||||||
iteration++
|
iteration++
|
||||||
last_run = world.time
|
last_run = world.time
|
||||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
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.
|
current_ticklimit = TICK_LIMIT_RUNNING
|
||||||
sleep(world.tick_lag * (processing + sleep_delta))
|
if (processing * sleep_delta <= world.tick_lag)
|
||||||
|
current_ticklimit -= (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc if we plan on running next tick
|
||||||
|
sleep(world.tick_lag * (processing * sleep_delta))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,7 @@
|
|||||||
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
|
var/static/list/failure_strikes //How many times we suspect a subsystem type has crashed the MC, 3 strikes and you're out!
|
||||||
|
|
||||||
//Do not override
|
//Do not override
|
||||||
/datum/controller/subsystem/New()
|
///datum/controller/subsystem/New()
|
||||||
return
|
|
||||||
|
|
||||||
// Used to initialize the subsystem BEFORE the map has loaded
|
// Used to initialize the subsystem BEFORE the map has loaded
|
||||||
// Called AFTER Recover if that is called
|
// Called AFTER Recover if that is called
|
||||||
@@ -66,7 +65,7 @@
|
|||||||
can_fire = 0
|
can_fire = 0
|
||||||
flags |= SS_NO_FIRE
|
flags |= SS_NO_FIRE
|
||||||
Master.subsystems -= src
|
Master.subsystems -= src
|
||||||
|
return ..()
|
||||||
|
|
||||||
//Queue it to run.
|
//Queue it to run.
|
||||||
// (we loop thru a linked list until we get to the end or find the right point)
|
// (we loop thru a linked list until we get to the end or find the right point)
|
||||||
|
|||||||
@@ -296,8 +296,7 @@
|
|||||||
if (holder)
|
if (holder)
|
||||||
sleep(1)
|
sleep(1)
|
||||||
else
|
else
|
||||||
sleep(5)
|
stoplag(5)
|
||||||
stoplag()
|
|
||||||
|
|
||||||
/client/proc/last_activity_seconds()
|
/client/proc/last_activity_seconds()
|
||||||
return inactivity / 10
|
return inactivity / 10
|
||||||
|
|||||||
@@ -1165,7 +1165,7 @@
|
|||||||
//They ran away!
|
//They ran away!
|
||||||
else
|
else
|
||||||
ai_log("AttackTarget() out of range!",3)
|
ai_log("AttackTarget() out of range!",3)
|
||||||
sleep(1) // Unfortunately this is needed to protect from ClosestDistance() sometimes not updating fast enough to prevent an infinite loop.
|
stoplag(1) // Unfortunately this is needed to protect from ClosestDistance() sometimes not updating fast enough to prevent an infinite loop.
|
||||||
handle_stance(STANCE_ATTACK)
|
handle_stance(STANCE_ATTACK)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user