From d76b535a659bc64169ecff4dc09164519b77112e Mon Sep 17 00:00:00 2001 From: silicons <2003111+silicons@users.noreply.github.com> Date: Sun, 9 Apr 2023 18:35:20 -0700 Subject: [PATCH] subsystem changes (#5332) 1. de-tickers basically everything that doesn't need to be a ticker (so most of them) 2. makes SSdpc not awful (thanks @Lohikar) --------- Co-authored-by: silicons --- code/__DEFINES/controllers/_subsystems.dm | 16 +++--- code/controllers/subsystem/DPC.dm | 53 +++++++++++-------- code/controllers/subsystem/ai.dm | 2 +- code/controllers/subsystem/chat.dm | 4 +- code/controllers/subsystem/icon_smooth.dm | 4 +- code/controllers/subsystem/input.dm | 4 +- .../subsystem/processing/projectiles.dm | 4 +- code/controllers/subsystem/throwing.dm | 4 +- code/controllers/subsystem/timer.dm | 5 ++ code/game/machinery/holopad.dm | 2 +- 10 files changed, 59 insertions(+), 39 deletions(-) diff --git a/code/__DEFINES/controllers/_subsystems.dm b/code/__DEFINES/controllers/_subsystems.dm index 0f3baa4f9b5..5399b5a3326 100644 --- a/code/__DEFINES/controllers/_subsystems.dm +++ b/code/__DEFINES/controllers/_subsystems.dm @@ -52,7 +52,10 @@ /// When round completes but before reboot. #define RUNLEVEL_POSTGAME 8 +/// default runlevels for most subsystems #define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME) +/// all valid runlevels - subsystems with this will run all the time after their MC init stage. +#define RUNLEVELS_ALL (RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME) var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME) /// Convert from the runlevel bitfield constants to index in runlevel_flags list. @@ -161,9 +164,15 @@ DEFINE_BITFIELD(runlevels, list( #define FIRE_PRIORITY_ASSET_LOADING 100 #define FIRE_PRIORITY_MACHINES 100 #define FIRE_PRIORITY_NANO 150 +#define FIRE_PRIORITY_AI 200 #define FIRE_PRIORITY_TGUI 200 +#define FIRE_PRIORITY_PROJECTILES 200 +#define FIRE_PRIORITY_THROWING 200 #define FIRE_PRIORITY_STATPANELS 400 #define FIRE_PRIORITY_OVERLAYS 500 +#define FIRE_PRIORITY_SMOOTHING 500 +#define FIRE_PRIORITY_CHAT 500 +#define FIRE_PRIORITY_INPUT 1000 //? Ticker Subsystems - Highest priority // Any subsystem flagged with SS_TICKER is here! @@ -171,14 +180,9 @@ DEFINE_BITFIELD(runlevels, list( // Is your feature as important as movement, chat, or timers? // Probably not! Go to normal bracket instead! -#define FIRE_PRIORITY_AI 10 //! WHY IS THIS SSTICKER??? // DEFAULT PRIORITY IS HERE -#define FIRE_PRIORITY_PROJECTILES 150 //! this probably shouldn't be ssticker -#define FIRE_PRIORITY_THROWING 150 //! this probably shouldn't be ssticker -#define FIRE_PRIORITY_CHAT 400 -#define FIRE_PRIORITY_SMOOTHING 500 //! this probably shouldn't be ssticker +#define FIRE_PRIORITY_DPC 700 #define FIRE_PRIORITY_TIMER 700 -#define FIRE_PRIORITY_INPUT 1000 //! Never drop input. //? Special diff --git a/code/controllers/subsystem/DPC.dm b/code/controllers/subsystem/DPC.dm index c052482770e..d8d70c0d3b4 100644 --- a/code/controllers/subsystem/DPC.dm +++ b/code/controllers/subsystem/DPC.dm @@ -1,26 +1,37 @@ -/** - * delayed procedure call, equivalent to addtimer 0 - */ +/* +This is pretty much just an optimization for wait=0 timers. They're relatively common, but generally don't actually need the more + complex features of SStimer. SSdpc can handle these timers instead (and it's a lot simpler than SStimer is), but it can't handle + complex timers with flags. This doesn't need to be explicitly used, eligible timers are automatically converted. +*/ + SUBSYSTEM_DEF(dpc) - subsystem_flags = SS_NO_FIRE | SS_NO_INIT + name = "Delayed Procedure Call" + wait = 1 + runlevels = RUNLEVELS_ALL + priority = FIRE_PRIORITY_DPC + subsystem_flags = SS_TICKER | SS_NO_INIT - /// are we queued? - var/primed = FALSE - /// targets - we do not check for qdels! - var/list/targets = list() + var/list/queued_calls = list() + var/list/avg = 0 -/datum/controller/subsystem/dpc/proc/queue_invoke(datum/target, procpath/callpath, ...) - targets[++targets.len] = args.Copy() - if(!primed) - prime() +/datum/controller/subsystem/dpc/stat_entry() + return ..() + " Q: [queued_calls.len], AQ: ~[round(avg)]" -/datum/controller/subsystem/dpc/proc/prime() - ASSERT(!primed) - primed = TRUE - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/dpc, invoke_calls)), 0) +/datum/controller/subsystem/dpc/fire(resumed = FALSE) + var/list/qc = queued_calls + if (!resumed) + avg = MC_AVERAGE_FAST(avg, qc.len) -/datum/controller/subsystem/dpc/proc/invoke_calls() - primed = FALSE - for(var/list/targlist as anything in targets) - call(targlist[1], targlist[2])(arglist(targlist.Copy(3))) - targets.len = 0 + var/q_idex = 1 + + while (q_idex <= qc.len) + var/datum/callback/CB = qc[q_idex] + q_idex += 1 + + CB.InvokeAsync() + + if (MC_TICK_CHECK) + break + + if (q_idex > 1) + queued_calls.Cut(1, q_idex) diff --git a/code/controllers/subsystem/ai.dm b/code/controllers/subsystem/ai.dm index e89bbd6ac3d..beb49a90937 100644 --- a/code/controllers/subsystem/ai.dm +++ b/code/controllers/subsystem/ai.dm @@ -3,7 +3,7 @@ SUBSYSTEM_DEF(ai) init_order = INIT_ORDER_AI priority = FIRE_PRIORITY_AI wait = 5 // This gets run twice a second, however this is technically two loops in one, with the second loop being run every four iterations. - subsystem_flags = SS_NO_INIT|SS_TICKER + subsystem_flags = SS_NO_INIT runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/processing = list() diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index 1dc6bc435d2..5b97a712578 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -5,8 +5,8 @@ SUBSYSTEM_DEF(chat) name = "Chat" - subsystem_flags = SS_TICKER - wait = 1 + subsystem_flags = NONE + wait = 0.25 // scale up to 40 fps priority = FIRE_PRIORITY_CHAT init_order = INIT_ORDER_CHAT diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm index 2e56abca70a..c16b22d0c56 100644 --- a/code/controllers/subsystem/icon_smooth.dm +++ b/code/controllers/subsystem/icon_smooth.dm @@ -1,9 +1,9 @@ SUBSYSTEM_DEF(icon_smooth) name = "Icon Smoothing" init_order = INIT_ORDER_ICON_SMOOTHING - wait = 1 + wait = 0.25 // scale up to 40 fps priority = FIRE_PRIORITY_SMOOTHING - subsystem_flags = SS_TICKER + subsystem_flags = NONE ///Blueprints assemble an image of what pipes/manifolds/wires look like on initialization, and thus should be taken after everything's been smoothed // var/list/blueprint_queue = list() diff --git a/code/controllers/subsystem/input.dm b/code/controllers/subsystem/input.dm index da9d4b06f66..ceb8f26dea4 100644 --- a/code/controllers/subsystem/input.dm +++ b/code/controllers/subsystem/input.dm @@ -1,8 +1,8 @@ SUBSYSTEM_DEF(input) name = "Input" - wait = 1 //SS_TICKER means this runs every tick + wait = 0.25 // scale to 40 fps init_order = INIT_ORDER_INPUT - subsystem_flags = SS_TICKER + subsystem_flags = NONE priority = FIRE_PRIORITY_INPUT runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY diff --git a/code/controllers/subsystem/processing/projectiles.dm b/code/controllers/subsystem/processing/projectiles.dm index 6ce4b967320..08771ed6a15 100644 --- a/code/controllers/subsystem/processing/projectiles.dm +++ b/code/controllers/subsystem/processing/projectiles.dm @@ -1,9 +1,9 @@ PROCESSING_SUBSYSTEM_DEF(projectiles) name = "Projectiles" - wait = 1 + wait = 0.25 // scale up to 40 fps stat_tag = "PP" priority = FIRE_PRIORITY_PROJECTILES - subsystem_flags = SS_NO_INIT|SS_TICKER + subsystem_flags = SS_NO_INIT var/global_max_tick_moves = 10 var/global_pixel_speed = 2 var/global_iterations_per_move = 16 diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 3f7e7a28290..a5e2821e684 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -1,8 +1,8 @@ SUBSYSTEM_DEF(throwing) name = "Throwing" priority = FIRE_PRIORITY_THROWING - wait = 1 - subsystem_flags = SS_NO_INIT | SS_KEEP_TIMING | SS_TICKER + wait = 0.25 // scale up to 40 fps + subsystem_flags = SS_NO_INIT runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/currentrun diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 72c33d0fe13..54a840094ec 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -29,6 +29,7 @@ SUBSYSTEM_DEF(timer) name = "Timer" wait = 1 // SS_TICKER subsystem, so wait is in ticks init_order = INIT_ORDER_TIMER + runlevels = RUNLEVELS_ALL priority = FIRE_PRIORITY_TIMER subsystem_flags = SS_TICKER|SS_NO_INIT @@ -664,6 +665,10 @@ SUBSYSTEM_DEF(timer) stack_trace("addtimer called with a callback assigned to a qdeleted object. In the future such timers will not \ be supported and may refuse to run or run with a 0 wait") + if (wait == 0 && !flags) + SSdpc.queued_calls += callback + return + wait = max(CEILING(wait, world.tick_lag), world.tick_lag) if(wait >= INFINITY) diff --git a/code/game/machinery/holopad.dm b/code/game/machinery/holopad.dm index 208b9dfd35b..d90dbca3b56 100644 --- a/code/game/machinery/holopad.dm +++ b/code/game/machinery/holopad.dm @@ -397,7 +397,7 @@ GLOBAL_VAR_INIT(holopad_connectivity_rebuild_queued, FALSE) * get hung up by a call */ /obj/machinery/holopad/proc/hung_up(datum/holocall/disconnecting, we_hung_up) - SSdpc.queue_invoke(src, TYPE_PROC_REF(/atom, update_icon)) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 0) //? UI