diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index ac9cfd3e12d2..e2db8e0b8544 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -109,6 +109,7 @@ // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. +#define SS_INIT_PROFILER 86 #define SS_INIT_INPUT 85 #define SS_INIT_TOPIC 83 #define SS_INIT_LOBBYART 82 diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index cc3d00fd951b..385cbcb8d446 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -627,3 +627,5 @@ This maintains a list of ip addresses that are able to bypass topic filtering. protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED /datum/config_entry/flag/guest_ban + +/datum/config_entry/flag/auto_profile diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm new file mode 100644 index 000000000000..f9ba79046c2c --- /dev/null +++ b/code/controllers/subsystem/profiler.dm @@ -0,0 +1,74 @@ +#define PROFILER_FILENAME "profiler.json" +#define SENDMAPS_FILENAME "sendmaps.json" + +SUBSYSTEM_DEF(profiler) + name = "Profiler" + init_order = SS_INIT_PROFILER + runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY + wait = 300 SECONDS + var/fetch_cost = 0 + var/write_cost = 0 + +/datum/controller/subsystem/profiler/stat_entry(msg) + msg += "F:[round(fetch_cost,1)]ms" + msg += "|W:[round(write_cost,1)]ms" + return msg + +/datum/controller/subsystem/profiler/Initialize() + if(CONFIG_GET(flag/auto_profile)) + StartProfiling() + else + StopProfiling() //Stop the early start profiler + return SS_INIT_SUCCESS + +/datum/controller/subsystem/profiler/OnConfigLoad() + if(CONFIG_GET(flag/auto_profile)) + StartProfiling() + can_fire = TRUE + else + StopProfiling() + can_fire = FALSE + +/datum/controller/subsystem/profiler/fire() + DumpFile() + +/datum/controller/subsystem/profiler/Shutdown() + if(CONFIG_GET(flag/auto_profile)) + DumpFile(allow_yield = FALSE) + world.Profile(PROFILE_CLEAR, type = "sendmaps") + return ..() + +/datum/controller/subsystem/profiler/proc/StartProfiling() + world.Profile(PROFILE_START) + world.Profile(PROFILE_START, type = "sendmaps") + +/datum/controller/subsystem/profiler/proc/StopProfiling() + world.Profile(PROFILE_STOP) + world.Profile(PROFILE_STOP, type = "sendmaps") + +/datum/controller/subsystem/profiler/proc/DumpFile(allow_yield = TRUE) + var/timer = TICK_USAGE_REAL + var/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json") + var/current_sendmaps_data = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json") + fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + if(allow_yield) + CHECK_TICK + + if(!length(current_profile_data)) //Would be nice to have explicit proc to check this + stack_trace("Warning, profiling stopped manually before dump.") + var/prof_file = file("[GLOB.log_directory]/[PROFILER_FILENAME]") + if(fexists(prof_file)) + fdel(prof_file) + if(!length(current_sendmaps_data)) //Would be nice to have explicit proc to check this + stack_trace("Warning, sendmaps profiling stopped manually before dump.") + var/sendmaps_file = file("[GLOB.log_directory]/[SENDMAPS_FILENAME]") + if(fexists(sendmaps_file)) + fdel(sendmaps_file) + + timer = TICK_USAGE_REAL + WRITE_FILE(prof_file, current_profile_data) + WRITE_FILE(sendmaps_file, current_sendmaps_data) + write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + +#undef PROFILER_FILENAME +#undef SENDMAPS_FILENAME diff --git a/colonialmarines.dme b/colonialmarines.dme index 25aa4df30a09..e4b7d360f9bc 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -263,6 +263,7 @@ #include "code\controllers\subsystem\police_clues.dm" #include "code\controllers\subsystem\power.dm" #include "code\controllers\subsystem\predships.dm" +#include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\projectiles.dm" #include "code\controllers\subsystem\quadtrees.dm" #include "code\controllers\subsystem\reagents.dm"