Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/main/java/cod/ast/ASTVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,8 @@ private static String startPerfTimer(DebugSystem.Level level, String operation)
if (!isTimerEnabled(level)) {
return null;
}
String timerName = operation + "#" + Thread.currentThread().getId() + ":" + System.nanoTime();
DebugSystem.startTimer(level, timerName);
return timerName;
DebugSystem.startTimer(level, operation);
return operation;
}

private static void stopPerfTimer(String timerName) {
Expand Down
59 changes: 45 additions & 14 deletions src/main/java/cod/debug/DebugSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ public int getLevel() {
private static SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS");
private static final boolean BENCHMARK_MODE = parseBenchmarkMode();

// Level-based timers (new)
private static Map<String, Long> levelTimers = new HashMap<String, Long>();
private static Map<String, Level> timerLevels = new HashMap<String, Level>();
// Level-based timers (support nested same-name timers per thread)
private static final ThreadLocal<Map<String, Deque<Long>>> levelTimerStacks =
ThreadLocal.withInitial(HashMap::new);
private static final ThreadLocal<Map<String, Deque<Level>>> timerLevelStacks =
ThreadLocal.withInitial(HashMap::new);

private static boolean parseBenchmarkMode() {
String raw = System.getProperty("cod.benchmark.mode");
Expand All @@ -50,6 +52,9 @@ public static boolean isBenchmarkMode() {

public static void setLevel(Level level) {
currentLevel = level;
if (level == Level.OFF) {
clearTimerStateForCurrentThread();
}
}

public static void setShowTimestamp(boolean show) {
Expand Down Expand Up @@ -112,20 +117,40 @@ public static void startTimer(String name) {
// New level-based timer
public static void startTimer(Level level, String name) {
if (shouldLog(level)) {
levelTimers.put(name, System.nanoTime());
timerLevels.put(name, level);
Map<String, Deque<Long>> startsByName = levelTimerStacks.get();
Deque<Long> starts = startsByName.computeIfAbsent(name, k -> new ArrayDeque<>());
starts.push(System.nanoTime());

Map<String, Deque<Level>> levelsByName = timerLevelStacks.get();
Deque<Level> levels = levelsByName.computeIfAbsent(name, k -> new ArrayDeque<>());
levels.push(level);
}
}

// Unified stopTimer - works for both original and level-based timers
public static double stopTimer(String name) {
// Check level-based timers first
Long levelStart = levelTimers.remove(name);
if (levelStart != null) {
Level originalLevel = timerLevels.remove(name);
// Check level-based timers first (LIFO for nested same-name timers)
Map<String, Deque<Long>> startsByName = levelTimerStacks.get();
Deque<Long> starts = startsByName.get(name);
if (starts != null && !starts.isEmpty()) {
long levelStart = starts.pop();
if (starts.isEmpty()) {
startsByName.remove(name);
}

Map<String, Deque<Level>> levelsByName = timerLevelStacks.get();
Deque<Level> levels = levelsByName.get(name);
Level originalLevel = null;
if (levels != null && !levels.isEmpty()) {
originalLevel = levels.pop();
if (levels.isEmpty()) {
levelsByName.remove(name);
}
}

long durationNs = System.nanoTime() - levelStart;
double durationMs = durationNs / 1_000_000.0;

if (originalLevel != null && shouldLog(originalLevel)) {
log(originalLevel, "PERF", String.format("%s took %.3f ms", name, durationMs));
}
Expand All @@ -148,9 +173,10 @@ public static double stopTimer(String name) {

public static double getTimerDuration(String name) {
// Check level-based timers first
Long levelStart = levelTimers.get(name);
if (levelStart != null) {
long durationNs = System.nanoTime() - levelStart;
Map<String, Deque<Long>> startsByName = levelTimerStacks.get();
Deque<Long> starts = startsByName.get(name);
if (starts != null && !starts.isEmpty()) {
long durationNs = System.nanoTime() - starts.peek();
return durationNs / 1_000_000.0;
}

Expand Down Expand Up @@ -207,4 +233,9 @@ private static boolean shouldLog(Level level) {
public static Level getLevel() {
return currentLevel;
}
}

public static void clearTimerStateForCurrentThread() {
levelTimerStacks.remove();
timerLevelStacks.remove();
}
}
5 changes: 2 additions & 3 deletions src/main/java/cod/interpreter/context/ExecutionContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -657,9 +657,8 @@ private static String startPerfTimer(DebugSystem.Level level, String operation)
if (!isTimerEnabled(level)) {
return null;
}
String timerName = operation + "#" + Thread.currentThread().getId() + ":" + System.nanoTime();
DebugSystem.startTimer(level, timerName);
return timerName;
DebugSystem.startTimer(level, operation);
return operation;
}

private static void stopPerfTimer(String timerName) {
Expand Down
7 changes: 3 additions & 4 deletions src/main/java/cod/interpreter/handler/ExpressionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public ExpressionHandler(TypeHandler typeSystem, InterpreterVisitor dispatcher)
// === Core Expression Evaluation ===

public Object handleBinaryOp(BinaryOp node, ExecutionContext ctx) {
String timer = startPerfTimer(DebugSystem.Level.DEBUG, "expression.handleBinaryOp");
String timer = startPerfTimer(DebugSystem.Level.TRACE, "expression.handleBinaryOp");
try {
if (node == null) {
throw new InternalError("handleBinaryOp called with null node");
Expand Down Expand Up @@ -640,9 +640,8 @@ private static String startPerfTimer(DebugSystem.Level level, String operation)
if (!isTimerEnabled(level)) {
return null;
}
String timerName = operation + "#" + Thread.currentThread().getId() + ":" + System.nanoTime();
DebugSystem.startTimer(level, timerName);
return timerName;
DebugSystem.startTimer(level, operation);
return operation;
}

private static void stopPerfTimer(String timerName) {
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/cod/range/NaturalArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -1785,9 +1785,8 @@ private static String startPerfTimer(DebugSystem.Level level, String operation)
if (!isTimerEnabled(level)) {
return null;
}
String timerName = operation + "#" + Thread.currentThread().getId() + ":" + System.nanoTime();
DebugSystem.startTimer(level, timerName);
return timerName;
DebugSystem.startTimer(level, operation);
return operation;
}

private static void stopPerfTimer(String timerName) {
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/cod/semantic/ImportResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -1797,9 +1797,8 @@ private static String startPerfTimer(DebugSystem.Level level, String operation)
if (!isTimerEnabled(level)) {
return null;
}
String timerName = operation + "#" + Thread.currentThread().getId() + ":" + System.nanoTime();
DebugSystem.startTimer(level, timerName);
return timerName;
DebugSystem.startTimer(level, operation);
return operation;
}

private static void stopPerfTimer(String timerName) {
Expand Down