diff --git a/code/_compile_options.dm b/code/_compile_options.dm index aa511c6e155..9ce72621b59 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -55,6 +55,9 @@ /// Prefer the autowiki build target instead. // #define AUTOWIKI +/// If this is uncommented, will profile mapload atom initializations +// #define PROFILE_MAPLOAD_INIT_ATOM + #ifndef PRELOAD_RSC //set to: #define PRELOAD_RSC 2 // 0 to allow using external resources or on-demand behaviour; #endif // 1 to use the default behaviour; diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index e453360df06..525500ea15f 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -20,6 +20,10 @@ SUBSYSTEM_DEF(atoms) /// Atoms that will be deleted once the subsystem is initialized var/list/queued_deletions = list() + #ifdef PROFILE_MAPLOAD_INIT_ATOM + var/list/mapload_init_times = list() + #endif + initialized = INITIALIZATION_INSSATOMS /datum/controller/subsystem/atoms/Initialize(timeofday) @@ -29,8 +33,17 @@ SUBSYSTEM_DEF(atoms) initialized = INITIALIZATION_INNEW_MAPLOAD InitializeAtoms() initialized = INITIALIZATION_INNEW_REGULAR + return ..() +#ifdef PROFILE_MAPLOAD_INIT_ATOM +#define PROFILE_INIT_ATOM_BEGIN(...) var/__profile_stat_time = TICK_USAGE +#define PROFILE_INIT_ATOM_END(atom) mapload_init_times[##atom.type] += TICK_USAGE_TO_MS(__profile_stat_time) +#else +#define PROFILE_INIT_ATOM_BEGIN(...) +#define PROFILE_INIT_ATOM_END(...) +#endif + /datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms, list/atoms_to_return = null) if(initialized == INITIALIZATION_INSSATOMS) return @@ -50,12 +63,16 @@ SUBSYSTEM_DEF(atoms) var/atom/A = atoms[I] if(!(A.flags_1 & INITIALIZED_1)) CHECK_TICK + PROFILE_INIT_ATOM_BEGIN() InitAtom(A, TRUE, mapload_arg) + PROFILE_INIT_ATOM_END(A) else count = 0 for(var/atom/A in world) if(!(A.flags_1 & INITIALIZED_1)) + PROFILE_INIT_ATOM_BEGIN() InitAtom(A, FALSE, mapload_arg) + PROFILE_INIT_ATOM_END(A) ++count CHECK_TICK @@ -84,6 +101,10 @@ SUBSYSTEM_DEF(atoms) testing("[queued_deletions.len] atoms were queued for deletion.") queued_deletions.Cut() + #ifdef PROFILE_MAPLOAD_INIT_ATOM + rustg_file_write(json_encode(mapload_init_times), "[GLOB.log_directory]/init_times.json") + #endif + /// Init this specific atom /datum/controller/subsystem/atoms/proc/InitAtom(atom/A, from_template = FALSE, list/arguments) var/the_type = A.type diff --git a/tools/read_init_times.py b/tools/read_init_times.py new file mode 100644 index 00000000000..4dca61c40f7 --- /dev/null +++ b/tools/read_init_times.py @@ -0,0 +1,22 @@ +# When passed an `init_times.json` file (received from enabling `PROFILE_MAPLOAD_INIT_ATOM`), +# and an optional max-depth level, this will output init times from worst to best. +import json +import sys + +if len(sys.argv) < 2: + print("Usage: read_init_times.py [max_depth]") + sys.exit(1) + +max_depth = int(sys.argv[2]) if len(sys.argv) > 2 else 1000 + +with open(sys.argv[1], "r") as file: + init_times = json.load(file) + +init_times_per_type = {} + +for (type, time) in init_times.items(): + type = '/'.join(type.split('/')[0:max_depth+1]) + init_times_per_type[type] = init_times_per_type.get(type, 0) + time + +for (type, time) in sorted(init_times_per_type.items(), key = lambda x: x[1], reverse = True): + print(type, time)