import time from collections import OrderedDict, deque import sys import os # check if is ui process will have IS_AI_TOOLKIT_UI in env is_ui = os.environ.get("IS_AI_TOOLKIT_UI", "0") == "1" class Timer: def __init__(self, name='Timer', max_buffer=10): self.name = name self.max_buffer = max_buffer self.timers = OrderedDict() self.active_timers = {} self.current_timer = None # Used for the context manager functionality self._after_print_hooks = [] def start(self, timer_name): if timer_name not in self.timers: self.timers[timer_name] = deque(maxlen=self.max_buffer) self.active_timers[timer_name] = time.time() def cancel(self, timer_name): """Cancel an active timer.""" if timer_name in self.active_timers: del self.active_timers[timer_name] def stop(self, timer_name): if timer_name not in self.active_timers: raise ValueError(f"Timer '{timer_name}' was not started!") elapsed_time = time.time() - self.active_timers[timer_name] self.timers[timer_name].append(elapsed_time) # Clean up active timers del self.active_timers[timer_name] # Check if this timer's buffer exceeds max_buffer and remove the oldest if it does if len(self.timers[timer_name]) > self.max_buffer: self.timers[timer_name].popleft() def add_after_print_hook(self, hook): self._after_print_hooks.append(hook) def print(self): if not is_ui: print(f"\nTimer '{self.name}':") timing_dict = {} # sort by longest at top for timer_name, timings in sorted(self.timers.items(), key=lambda x: sum(x[1]), reverse=True): avg_time = sum(timings) / len(timings) if not is_ui: print(f" - {avg_time:.4f}s avg - {timer_name}, num = {len(timings)}") timing_dict[timer_name] = avg_time for hook in self._after_print_hooks: hook(timing_dict) if not is_ui: print('') def reset(self): self.timers.clear() self.active_timers.clear() def __call__(self, timer_name): """Enable the use of the Timer class as a context manager.""" self.current_timer = timer_name self.start(timer_name) return self def __enter__(self): pass def __exit__(self, exc_type, exc_value, traceback): if exc_type is None: # No exceptions, stop the timer normally self.stop(self.current_timer) else: # There was an exception, cancel the timer self.cancel(self.current_timer)