From ca9753eb814842d80ef7e1c810ceb34db5ca0101 Mon Sep 17 00:00:00 2001 From: Kenneth VanderLinde Date: Thu, 30 Nov 2023 14:52:23 -0800 Subject: [PATCH] Implement a CodeTimer stack Each thread has a stack of `CodeTimer`, with the top of the stack being available anywhere via a call to `CodeTimer.get()`. When a different timer is needed for a section of code, `CodeTimer.using()` will push a new timer onto the stack, and pop it off the stack when the timed code completes, restoring the previous timer. `CodeTimer.using()` also takes care of enabling the new timer based on `AppState.isCollectProfilingData()`, and reporting the results at the end if the timer is enabled. This saves some repeated logic and adds a bit of consistency in how timers are used. --- src/main/java/net/rptools/lib/CodeTimer.java | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/main/java/net/rptools/lib/CodeTimer.java b/src/main/java/net/rptools/lib/CodeTimer.java index f49eac0a04..00cfe35cd7 100644 --- a/src/main/java/net/rptools/lib/CodeTimer.java +++ b/src/main/java/net/rptools/lib/CodeTimer.java @@ -14,10 +14,51 @@ */ package net.rptools.lib; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; +import net.rptools.maptool.client.AppState; +import net.rptools.maptool.client.MapTool; public class CodeTimer { + private static final ThreadLocal ROOT_TIMER = + ThreadLocal.withInitial(() -> new CodeTimer("")); + private static final ThreadLocal> timerStack = + ThreadLocal.withInitial(ArrayList::new); + + @FunctionalInterface + public interface TimedSection { + void call(CodeTimer timer) throws Ex; + } + + public static void using(String name, TimedSection callback) + throws Ex { + var stack = timerStack.get(); + + var timer = new CodeTimer(name); + timer.setEnabled(AppState.isCollectProfilingData()); + + stack.addLast(timer); + try { + callback.call(timer); + } finally { + final var lastTimer = stack.removeLast(); + assert lastTimer == timer : "Timer stack is corrupted"; + + if (timer.isEnabled()) { + String results = timer.toString(); + MapTool.getProfilingNoteFrame().addText(results); + } + timer.clear(); + } + } + + public static CodeTimer get() { + final var stack = timerStack.get(); + return stack.isEmpty() ? ROOT_TIMER.get() : stack.getLast(); + } + private final Map timeMap = new LinkedHashMap<>(); private final String name; private boolean enabled;