Skip to content

Commit

Permalink
Implement a CodeTimer stack
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kwvanderlinde committed Dec 3, 2023
1 parent b06cc0c commit ca9753e
Showing 1 changed file with 41 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/main/java/net/rptools/lib/CodeTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<CodeTimer> ROOT_TIMER =
ThreadLocal.withInitial(() -> new CodeTimer(""));
private static final ThreadLocal<List<CodeTimer>> timerStack =
ThreadLocal.withInitial(ArrayList::new);

@FunctionalInterface
public interface TimedSection<Ex extends Throwable> {
void call(CodeTimer timer) throws Ex;
}

public static <Ex extends Exception> void using(String name, TimedSection<Ex> 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<String, Timer> timeMap = new LinkedHashMap<>();
private final String name;
private boolean enabled;
Expand Down

0 comments on commit ca9753e

Please sign in to comment.