Files
Bubberstation/code/controllers/subsystem/time_track.dm
Watermelon914 79b00baad2 Refactors subsystems to use dependency-ordering to determine init order. Subsystems can now declare their own dependencies. (#90268)
## About The Pull Request
As the title says.
`init_order` is no more, subsystems ordering now depends on their
declared dependencies.
Subsystems can now declare which other subsystems need to init before
them using a list and the subsystem's typepath
I.e.
```dm
dependencies = list(
    /datum/controller/subsystem/atoms,
    /datum/controller/subsystem/mapping
)
```
The reverse can also be done, if a subsystem must initialize after your
own:
```dm
dependents = list(
    /datum/controller/subsystem/atoms
)
```
Cyclical dependencies are not allowed and will throw an error on
initialization if one is found.
There's also a debug tool to visualize the dependency graph, although
it's a bit basic:

![image](https://github.com/user-attachments/assets/80c854d9-c2a5-4f2f-92db-a031e9a8e257)

Subsystem load ordering can still be controlled using `init_stage`, some
subsystems use this in cases where they must initialize first or last
regardless of dependencies. An error will be thrown if a subsystem has
an `init_stage` before one of their dependencies.

## Why It's Good For The Game
Makes dealing with subsystem dependencies easier, and reduces the chance
of making a dependency error when needing to shift around subsystem
inits.

## Changelog
🆑
refactor: Refactored subsystem initialization
/🆑
2025-04-29 17:11:39 -06:00

156 lines
5.7 KiB
Plaintext

SUBSYSTEM_DEF(time_track)
name = "Time Tracking"
wait = 100
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
var/time_dilation_current = 0
var/time_dilation_avg_fast = 0
var/time_dilation_avg = 0
var/time_dilation_avg_slow = 0
var/first_run = TRUE
var/last_tick_realtime = 0
var/last_tick_byond_time = 0
var/last_tick_tickcount = 0
var/list/sendmaps_names_map = list(
"SendMaps" = "send_maps",
"SendMaps: Initial housekeeping" = "initial_house",
"SendMaps: Cleanup" = "cleanup",
"SendMaps: Client loop" = "client_loop",
"SendMaps: Per client" = "per_client",
"SendMaps: Per client: Deleted images" = "deleted_images",
"SendMaps: Per client: HUD update" = "hud_update",
"SendMaps: Per client: Statpanel update" = "statpanel_update",
"SendMaps: Per client: Map data" = "map_data",
"SendMaps: Per client: Map data: Check eye position" = "check_eye_pos",
"SendMaps: Per client: Map data: Update chunks" = "update_chunks",
"SendMaps: Per client: Map data: Send turfmap updates" = "turfmap_updates",
"SendMaps: Per client: Map data: Send changed turfs" = "changed_turfs",
"SendMaps: Per client: Map data: Send turf chunk info" = "turf_chunk_info",
"SendMaps: Per client: Map data: Send obj changes" = "obj_changes",
"SendMaps: Per client: Map data: Send mob changes" = "mob_changes",
"SendMaps: Per client: Map data: Send notable turf visual contents" = "send_turf_vis_conts",
"SendMaps: Per client: Map data: Send pending animations" = "pending_animations",
"SendMaps: Per client: Map data: Look for movable changes" = "look_for_movable_changes",
"SendMaps: Per client: Map data: Look for movable changes: Check notable turf visual contents" = "check_turf_vis_conts",
"SendMaps: Per client: Map data: Look for movable changes: Check HUD/image visual contents" = "check_hud/image_vis_contents",
"SendMaps: Per client: Map data: Look for movable changes: Loop through turfs in range" = "turfs_in_range",
"SendMaps: Per client: Map data: Look for movable changes: Movables examined" = "movables_examined",
)
/datum/controller/subsystem/time_track/Initialize()
GLOB.perf_log = "[GLOB.log_directory]/perf-[GLOB.round_id ? GLOB.round_id : "NULL"]-[SSmapping.current_map.map_name].csv"
world.Profile(PROFILE_RESTART, type = "sendmaps")
//Need to do the sendmaps stuff in its own file, since it works different then everything else
var/list/sendmaps_headers = list()
for(var/proper_name in sendmaps_names_map)
sendmaps_headers += sendmaps_names_map[proper_name]
sendmaps_headers += "[sendmaps_names_map[proper_name]]_count"
log_perf(
list(
"time",
"players",
"tidi",
"tidi_fastavg",
"tidi_avg",
"tidi_slowavg",
"maptick",
"num_timers",
"air_turf_cost",
"air_eg_cost",
"air_highpressure_cost",
"air_hotspots_cost",
"air_superconductivity_cost",
"air_pipenets_cost",
"air_rebuilds_cost",
"air_turf_count",
"air_eg_count",
"air_hotspot_count",
"air_network_count",
"air_delta_count",
"air_superconductive_count",
"all_queries",
"queries_active",
"queries_standby"
) + sendmaps_headers
)
return SS_INIT_SUCCESS
/datum/controller/subsystem/time_track/fire()
var/current_realtime = REALTIMEOFDAY
var/current_byondtime = world.time
var/current_tickcount = world.time/world.tick_lag
if (!first_run)
var/tick_drift = max(0, (((current_realtime - last_tick_realtime) - (current_byondtime - last_tick_byond_time)) / world.tick_lag))
time_dilation_current = tick_drift / (current_tickcount - last_tick_tickcount) * 100
time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current)
time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast)
time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg)
GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime)
else
first_run = FALSE
last_tick_realtime = current_realtime
last_tick_byond_time = current_byondtime
last_tick_tickcount = current_tickcount
var/sendmaps_json = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json")
var/list/send_maps_data = null
try
send_maps_data = json_decode(sendmaps_json)
catch
text2file(sendmaps_json,"bad_sendmaps.json")
can_fire = FALSE
return
var/send_maps_sort = send_maps_data.Copy() //Doing it like this guarantees us a properly sorted list
for(var/list/packet in send_maps_data)
send_maps_sort[packet["name"]] = packet
var/list/send_maps_values = list()
for(var/entry_name in sendmaps_names_map)
var/list/packet = send_maps_sort[entry_name]
if(!packet) //If the entry does not have a value for us, just put in 0 for both
send_maps_values += 0
send_maps_values += 0
continue
send_maps_values += packet["value"]
send_maps_values += packet["calls"]
SSblackbox.record_feedback("associative", "time_dilation_current", 1, list("[ISOtime()]" = list("current" = "[time_dilation_current]", "avg_fast" = "[time_dilation_avg_fast]", "avg" = "[time_dilation_avg]", "avg_slow" = "[time_dilation_avg_slow]")))
log_perf(
list(
world.time,
length(GLOB.clients),
time_dilation_current,
time_dilation_avg_fast,
time_dilation_avg,
time_dilation_avg_slow,
MAPTICK_LAST_INTERNAL_TICK_USAGE,
length(SStimer.timer_id_dict),
SSair.cost_turfs,
SSair.cost_groups,
SSair.cost_highpressure,
SSair.cost_hotspots,
SSair.cost_superconductivity,
SSair.cost_pipenets,
SSair.cost_rebuilds,
length(SSair.active_turfs),
length(SSair.excited_groups),
length(SSair.hotspots),
length(SSair.networks),
length(SSair.high_pressure_delta),
length(SSair.active_super_conductivity),
SSdbcore.all_queries_num,
SSdbcore.queries_active_num,
SSdbcore.queries_standby_num
) + send_maps_values
)
SSdbcore.reset_tracking()