diff --git a/code/__DEFINES/stat_tracking.dm b/code/__DEFINES/stat_tracking.dm
new file mode 100644
index 0000000000..d7d207469d
--- /dev/null
+++ b/code/__DEFINES/stat_tracking.dm
@@ -0,0 +1,17 @@
+#define STAT_ENTRY_TIME 1
+#define STAT_ENTRY_COUNT 2
+#define STAT_ENTRY_LENGTH 2
+
+
+#define STAT_START_STOPWATCH var/STAT_STOP_WATCH = TICK_USAGE
+#define STAT_STOP_STOPWATCH var/STAT_TIME = TICK_USAGE_TO_MS(STAT_STOP_WATCH)
+#define STAT_LOG_ENTRY(entrylist, entryname) \
+ var/list/STAT_ENTRY = entrylist[entryname] || (entrylist[entryname] = new /list(STAT_ENTRY_LENGTH));\
+ STAT_ENTRY[STAT_ENTRY_TIME] += STAT_TIME;\
+ var/STAT_INCR_AMOUNT = min(1, 2**round((STAT_ENTRY[STAT_ENTRY_COUNT] || 0)/SHORT_REAL_LIMIT));\
+ if (STAT_INCR_AMOUNT == 1 || prob(100/STAT_INCR_AMOUNT)) {\
+ STAT_ENTRY[STAT_ENTRY_COUNT] += STAT_INCR_AMOUNT;\
+ };\
+
+
+
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 247e1109f8..b8579e7dbe 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -76,3 +76,27 @@
#define RUNLEVEL_POSTGAME 8
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
+
+
+
+
+#define COMPILE_OVERLAYS(A)\
+ if (TRUE) {\
+ var/list/oo = A.our_overlays;\
+ var/list/po = A.priority_overlays;\
+ if(LAZYLEN(po)){\
+ if(LAZYLEN(oo)){\
+ A.overlays = oo + po;\
+ }\
+ else{\
+ A.overlays = po;\
+ }\
+ }\
+ else if(LAZYLEN(oo)){\
+ A.overlays = oo;\
+ }\
+ else{\
+ A.overlays.Cut();\
+ }\
+ A.flags_1 &= ~OVERLAY_QUEUED_1;\
+ }
\ No newline at end of file
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index a939ab7e90..3831349536 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -58,7 +58,12 @@ GLOBAL_VAR_INIT(cmp_field, "name")
. = B.failures - A.failures
if (!.)
. = B.qdels - A.qdels
-
+
+/proc/cmp_generic_stat_item_time(list/A, list/B)
+ . = B[STAT_ENTRY_TIME] - A[STAT_ENTRY_TIME]
+ if (!.)
+ . = B[STAT_ENTRY_COUNT] - A[STAT_ENTRY_COUNT]
+
/proc/cmp_profile_avg_time_dsc(list/A, list/B)
return (B[PROFILE_ITEM_TIME]/(B[PROFILE_ITEM_COUNT] || 1)) - (A[PROFILE_ITEM_TIME]/(A[PROFILE_ITEM_COUNT] || 1))
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index b55ec948b8..6b014efd6a 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -1006,23 +1006,26 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
if(J)
J.equip(body, TRUE, FALSE)
- SSoverlays.Flush()
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
body.setDir(NORTH)
+ COMPILE_OVERLAYS(body)
var/icon/partial = getFlatIcon(body)
out_icon.Insert(partial,dir=NORTH)
body.setDir(SOUTH)
+ COMPILE_OVERLAYS(body)
partial = getFlatIcon(body)
out_icon.Insert(partial,dir=SOUTH)
body.setDir(WEST)
+ COMPILE_OVERLAYS(body)
partial = getFlatIcon(body)
out_icon.Insert(partial,dir=WEST)
body.setDir(EAST)
+ COMPILE_OVERLAYS(body)
partial = getFlatIcon(body)
out_icon.Insert(partial,dir=EAST)
diff --git a/code/__HELPERS/stat_tracking.dm b/code/__HELPERS/stat_tracking.dm
new file mode 100644
index 0000000000..007cd2695d
--- /dev/null
+++ b/code/__HELPERS/stat_tracking.dm
@@ -0,0 +1,13 @@
+/proc/render_stats(list/stats, user, sort = /proc/cmp_generic_stat_item_time)
+ sortTim(stats, sort, TRUE)
+
+ var/list/lines = list()
+
+ for (var/entry in stats)
+ var/list/data = stats[entry]
+ lines += "[entry] => [num2text(data[STAT_ENTRY_TIME], 10)]ms ([data[STAT_ENTRY_COUNT]]) (avg:[num2text(data[STAT_ENTRY_TIME]/(data[STAT_ENTRY_COUNT] || 1), 99)])"
+
+ if (user)
+ user << browse("
- [lines.Join("
- ")]
", "window=[url_encode("stats:[REF(stats)]")]")
+
+ . = lines.Join("\n")
diff --git a/code/controllers/subsystem/processing/overlays.dm b/code/controllers/subsystem/overlays.dm
similarity index 80%
rename from code/controllers/subsystem/processing/overlays.dm
rename to code/controllers/subsystem/overlays.dm
index d7f260be0e..498890d430 100644
--- a/code/controllers/subsystem/processing/overlays.dm
+++ b/code/controllers/subsystem/overlays.dm
@@ -1,4 +1,4 @@
-PROCESSING_SUBSYSTEM_DEF(overlays)
+SUBSYSTEM_DEF(overlays)
name = "Overlay"
flags = SS_TICKER
wait = 1
@@ -6,62 +6,63 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
init_order = INIT_ORDER_OVERLAY
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_SETUP
- stat_tag = "Ov"
- currentrun = null
+ var/list/queue
+ var/list/stats
var/list/overlay_icon_state_caches
var/list/overlay_icon_cache
var/initialized = FALSE
-/datum/controller/subsystem/processing/overlays/PreInit()
- LAZYINITLIST(overlay_icon_state_caches)
- LAZYINITLIST(overlay_icon_cache)
+/datum/controller/subsystem/overlays/PreInit()
+ overlay_icon_state_caches = list()
+ overlay_icon_cache = list()
+ queue = list()
+ stats = list()
-/datum/controller/subsystem/processing/overlays/Initialize()
+/datum/controller/subsystem/overlays/Initialize()
initialized = TRUE
- Flush()
+ fire(mc_check = FALSE)
..()
-/datum/controller/subsystem/processing/overlays/Recover()
+
+/datum/controller/subsystem/overlays/stat_entry()
+ ..("Ov:[length(queue)]")
+
+
+/datum/controller/subsystem/overlays/Shutdown()
+ text2file("[GLOB.log_directory]/overlay.log", render_stats(stats))
+
+
+/datum/controller/subsystem/overlays/Recover()
overlay_icon_state_caches = SSoverlays.overlay_icon_state_caches
overlay_icon_cache = SSoverlays.overlay_icon_cache
- processing = SSoverlays.processing
+ queue = SSoverlays.queue
-#define COMPILE_OVERLAYS(A)\
- var/list/oo = A.our_overlays;\
- var/list/po = A.priority_overlays;\
- if(LAZYLEN(po)){\
- if(LAZYLEN(oo)){\
- A.overlays = oo + po;\
- }\
- else{\
- A.overlays = po;\
- }\
- }\
- else if(LAZYLEN(oo)){\
- A.overlays = oo;\
- }\
- else{\
- A.overlays.Cut();\
- }\
- A.flags_1 &= ~OVERLAY_QUEUED_1
-/datum/controller/subsystem/processing/overlays/fire(resumed = FALSE, mc_check = TRUE)
- var/list/processing = src.processing
- while(processing.len)
- var/atom/thing = processing[processing.len]
- processing.len--
+/datum/controller/subsystem/overlays/fire(resumed = FALSE, mc_check = TRUE)
+ var/list/queue = src.queue
+ var/static/count = 0
+ if (count)
+ var/c = count
+ count = 0 //so if we runtime on the Cut, we don't try again.
+ queue.Cut(1,c+1)
+
+ for (var/thing in queue)
+ count++
if(thing)
- COMPILE_OVERLAYS(thing)
+ STAT_START_STOPWATCH
+ var/atom/A = thing
+ COMPILE_OVERLAYS(A)
+ STAT_STOP_STOPWATCH
+ STAT_LOG_ENTRY(stats, A.type)
if(mc_check)
if(MC_TICK_CHECK)
break
else
CHECK_TICK
-/datum/controller/subsystem/processing/overlays/proc/Flush()
- if(processing.len)
- testing("Flushing [processing.len] overlays")
- fire(mc_check = FALSE) //pair this thread up with the MC to get extra compile time
+ if (count)
+ queue.Cut(1,count+1)
+ count = 0
/proc/iconstate2appearance(icon, iconstate)
var/static/image/stringbro = new()
@@ -102,6 +103,10 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
else if(isicon(overlay))
new_overlays += icon2appearance(overlay)
else
+ if(isloc(overlay))
+ var/atom/A = overlay
+ if (A.flags_1 & OVERLAY_QUEUED_1)
+ COMPILE_OVERLAYS(A)
appearance_bro.appearance = overlay //this works for images and atoms too!
if(!ispath(overlay))
var/image/I = overlay
@@ -110,7 +115,7 @@ PROCESSING_SUBSYSTEM_DEF(overlays)
return new_overlays
#define NOT_QUEUED_ALREADY (!(flags_1 & OVERLAY_QUEUED_1))
-#define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.processing += src;
+#define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src;
/atom/proc/cut_overlays(priority = FALSE)
var/list/cached_overlays = our_overlays
var/list/cached_priority = priority_overlays
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index ae7f73be8f..200443b1fa 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -281,8 +281,6 @@ SUBSYSTEM_DEF(ticker)
collect_minds()
equip_characters()
- SSoverlays.Flush() //Flush the majority of the shit
-
GLOB.data_core.manifest()
transfer_characters() //transfer keys to the new mobs
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index f17905b5be..e450c54c1b 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -99,7 +99,6 @@
LAZYCLEARLIST(overlays)
LAZYCLEARLIST(priority_overlays)
- //SSoverlays.processing -= src //we COULD do this, but it's better to just let it fall out of the processing queue
QDEL_NULL(light)
diff --git a/code/game/world.dm b/code/game/world.dm
index 026d7324e4..9132f3cd6d 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -124,7 +124,7 @@ GLOBAL_PROTECT(security_mode)
if(I in input)
handler = topic_handlers[I]
break
-
+
if((!handler || initial(handler.log)) && config && CONFIG_GET(flag/log_world_topic))
WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]")
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 01f825492f..56ae734044 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -156,7 +156,8 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
/client/proc/toggle_medal_disable,
/client/proc/view_runtimes,
/client/proc/pump_random_event,
- /client/proc/cmd_display_init_log
+ /client/proc/cmd_display_init_log,
+ /client/proc/cmd_display_overlay_log
)
GLOBAL_PROTECT(admin_verbs_possess)
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 9371792683..73965d52ad 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -778,6 +778,13 @@ GLOBAL_PROTECT(LastAdminCalledProc)
usr << browse(dellog.Join(), "window=dellog")
+/client/proc/cmd_display_overlay_log()
+ set category = "Debug"
+ set name = "Display overlay Log"
+ set desc = "Display SSoverlays log of everything that's passed through it."
+
+ render_stats(SSoverlays.stats, src)
+
/client/proc/cmd_display_init_log()
set category = "Debug"
set name = "Display Initialize() Log"
diff --git a/tgstation.dme b/tgstation.dme
index 7c14107f36..33de1cae2b 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -75,6 +75,7 @@
#include "code\__DEFINES\sight.dm"
#include "code\__DEFINES\sound.dm"
#include "code\__DEFINES\stat.dm"
+#include "code\__DEFINES\stat_tracking.dm"
#include "code\__DEFINES\status_effects.dm"
#include "code\__DEFINES\subsystems.dm"
#include "code\__DEFINES\tgui.dm"
@@ -105,6 +106,7 @@
#include "code\__HELPERS\radio.dm"
#include "code\__HELPERS\sanitize_values.dm"
#include "code\__HELPERS\shell.dm"
+#include "code\__HELPERS\stat_tracking.dm"
#include "code\__HELPERS\text.dm"
#include "code\__HELPERS\text_vr.dm"
#include "code\__HELPERS\time.dm"
@@ -245,6 +247,7 @@
#include "code\controllers\subsystem\mobs.dm"
#include "code\controllers\subsystem\npcpool.dm"
#include "code\controllers\subsystem\orbit.dm"
+#include "code\controllers\subsystem\overlays.dm"
#include "code\controllers\subsystem\pai.dm"
#include "code\controllers\subsystem\parallax.dm"
#include "code\controllers\subsystem\persistence.dm"
@@ -269,7 +272,6 @@
#include "code\controllers\subsystem\processing\fields.dm"
#include "code\controllers\subsystem\processing\flightpacks.dm"
#include "code\controllers\subsystem\processing\obj.dm"
-#include "code\controllers\subsystem\processing\overlays.dm"
#include "code\controllers\subsystem\processing\processing.dm"
#include "code\controllers\subsystem\processing\projectiles.dm"
#include "code\datums\action.dm"