From 0094c74b649d92dc36d0896f0ea3138209b3e154 Mon Sep 17 00:00:00 2001 From: Leshana Date: Fri, 20 Apr 2018 16:19:29 -0400 Subject: [PATCH] Ports "The punisher!" * From tgstation/tgstation#27196 * The mc will now punish subsystems that overrun their tick allotment with less allotment in later fires. * The punisher also delays the next fire of subsystems that overrun. Because of how this is ends up being calculated, this will almost never actually kick in, but sometimes subsystems like garbage will overrun into multiple ticks, so delaying their next fire is needed. * The punisher does not delay the next fire of SS_TICKER subsystems (tgstation/tgstation#34964) Note: SS_KEEP_TIMING subsystems do not get their next fire delayed. --- code/__defines/MC.dm | 4 ++++ code/controllers/master.dm | 20 +++++++++++++------- code/controllers/subsystem.dm | 3 ++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm index 5620f51b3b..1d41a31209 100644 --- a/code/__defines/MC.dm +++ b/code/__defines/MC.dm @@ -27,6 +27,10 @@ if(current_step == this_step || (initial_step && !resumed)) /* So we start at st #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)) + +#define MC_AVG_FAST_UP_SLOW_DOWN(average, current) (average > current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) +#define MC_AVG_SLOW_UP_FAST_DOWN(average, current) (average < current ? MC_AVERAGE_SLOW(average, current) : MC_AVERAGE_FAST(average, current)) + #define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} #define START_PROCESSING(Processor, Datum) if (!Datum.isprocessing) {Datum.isprocessing = 1;Processor.processing += Datum} diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 961f657b2d..6cfd051727 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -428,7 +428,7 @@ var/datum/controller/master/Master = new() // in those cases, so we just let them run) if (queue_node_flags & SS_NO_TICK_CHECK) if (queue_node.tick_usage > TICK_LIMIT_RUNNING - TICK_USAGE && ran_non_ticker) - queue_node.queued_priority += queue_priority_count * 0.10 + queue_node.queued_priority += queue_priority_count * 0.1 queue_priority_count -= queue_node_priority queue_priority_count += queue_node.queued_priority current_tick_budget -= queue_node_priority @@ -446,26 +446,32 @@ var/datum/controller/master/Master = new() else tick_precentage = tick_remaining - current_ticklimit = TICK_USAGE + tick_precentage + // Reduce tick allocation for subsystems that overran on their last tick. + tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun) + + current_ticklimit = round(TICK_USAGE + tick_precentage) if (!(queue_node_flags & SS_TICKER)) ran_non_ticker = TRUE ran = TRUE - tick_usage = TICK_USAGE + queue_node_paused = (queue_node.state == SS_PAUSED || queue_node.state == SS_PAUSING) last_type_processed = queue_node queue_node.state = SS_RUNNING + tick_usage = TICK_USAGE var/state = queue_node.ignite(queue_node_paused) + tick_usage = TICK_USAGE - tick_usage + if (state == SS_RUNNING) state = SS_IDLE current_tick_budget -= queue_node_priority - tick_usage = TICK_USAGE - tick_usage + if (tick_usage < 0) tick_usage = 0 - + queue_node.tick_overrun = max(0, MC_AVG_FAST_UP_SLOW_DOWN(queue_node.tick_overrun, tick_usage-tick_precentage)) queue_node.state = state if (state == SS_PAUSED) @@ -494,11 +500,11 @@ var/datum/controller/master/Master = new() if (queue_node_flags & SS_TICKER) queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait) else if (queue_node_flags & SS_POST_FIRE_TIMING) - queue_node.next_fire = world.time + queue_node.wait + queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100)) else if (queue_node_flags & SS_KEEP_TIMING) queue_node.next_fire += queue_node.wait else - queue_node.next_fire = queue_node.queued_time + queue_node.wait + queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun/100)) queue_node.queued_time = 0 diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 437c10424b..3d37e9ba7d 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -17,6 +17,7 @@ var/next_fire = 0 //scheduled world.time for next fire() var/cost = 0 //average time to execute var/tick_usage = 0 //average tick usage + var/tick_overrun = 0 //average tick overrun var/state = SS_IDLE //tracks the current state of the ss, running, paused, etc. var/paused_ticks = 0 //ticks this ss is taking to run right now. var/paused_tick_usage //total tick_usage of all of our runs while pausing this run @@ -167,7 +168,7 @@ if(can_fire && !(SS_NO_FIRE & flags)) - msg = "[round(cost,1)]ms|[round(tick_usage,1)]%|[round(ticks,0.1)]\t[msg]" + msg = "[round(cost,1)]ms|[round(tick_usage,1)]%([round(tick_overrun,1)]%)|[round(ticks,0.1)]\t[msg]" else msg = "OFFLINE\t[msg]"