From 0d0ec78ef2002ea785b7c9e181e352260223182d Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 18 May 2024 03:17:14 +0200 Subject: [PATCH] [MIRROR] Micro-optimizes _SendSignal a bit (#27759) * Micro-optimizes _SendSignal a bit (#83244) ## About The Pull Request Instead of iterating over an assoc list and doing a list access, which has a complexity of O(nlog(n)), it is better to just store a 2 tuple and access that to get a complexity of O(n) Check code to see what I mean. ## Why It's Good For The Game ![image](https://github.com/tgstation/tgstation/assets/37270891/1e5d68fa-2e19-473c-a870-e1e0277cbacc) This is a very hot proc and it's worth micro-optimizing where we can. The speed increase in doing the following code can be seen here: ![image](https://github.com/tgstation/tgstation/assets/37270891/1b7f00a3-b3c2-4976-b2ab-97eefbbd2459) Higher is better. The code that was benchmarked: ```dm var/list/target = list() /proc/testa() var/list/queued_calls = list() for(var/i in 1 to length(target)) var/data = target[i] queued_calls.Add(data, 1) for(var/i in 1 to (length(queued_calls) / 2)) var/a = queued_calls[i*2-1] var/b = queued_calls[i*2] /proc/testb() var/list/queued_calls = list() for(var/data in target) queued_calls[data] = 1 for(var/data in queued_calls) var/a = data var/b = queued_calls[data] MAIN for(var/i in 1 to 100) target.Add("[i]") BEGIN_BENCH(2) BENCH_PHASE("New code", testa()) BENCH_PHASE("Old code", testb()) END_BENCH ``` ## Changelog --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@ users.noreply.gitlab.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@ users.noreply.github.com> * Micro-optimizes _SendSignal a bit --------- Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Co-authored-by: Watermelon914 <3052169-Watermelon914@ users.noreply.gitlab.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@ users.noreply.github.com> --- code/datums/signals.dm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/code/datums/signals.dm b/code/datums/signals.dm index ddb7dd9cc9e..01ca02e41c2 100644 --- a/code/datums/signals.dm +++ b/code/datums/signals.dm @@ -120,7 +120,9 @@ // all the objects that are receiving the signal get the signal this final time. // AKA: No you can't cancel the signal reception of another object by doing an unregister in the same signal. var/list/queued_calls = list() - for(var/datum/listening_datum as anything in target) - queued_calls[listening_datum] = listening_datum._signal_procs[src][sigtype] - for(var/datum/listening_datum as anything in queued_calls) - . |= call(listening_datum, queued_calls[listening_datum])(arglist(arguments)) + // This should be faster than doing `var/datum/listening_datum as anything in target` as it does not implicitly copy the list + for(var/i in 1 to length(target)) + var/datum/listening_datum = target[i] + queued_calls.Add(listening_datum, listening_datum._signal_procs[src][sigtype]) + for(var/i in 1 to length(queued_calls) step 2) + . |= call(queued_calls[i], queued_calls[i + 1])(arglist(arguments))