import time from contextlib import contextmanager import torch class TemporalMemoryProfiler: def __init__(self, enabled=False, prefix='temporal_memory'): self.enabled = enabled self.prefix = prefix self.records = {} self.gpu_memory_allocated_mb = 0.0 self.gpu_memory_max_allocated_mb = 0.0 @contextmanager def measure(self, name): if not self.enabled: yield return self._sync() start = time.perf_counter() try: yield finally: self._sync() elapsed_ms = (time.perf_counter() - start) * 1000.0 self.records[name] = self.records.get(name, 0.0) + elapsed_ms self._capture_memory() def report(self): if not self.enabled: return {} report = { f'{name}_latency_ms': round(value, 3) for name, value in self.records.items() } report['gpu_memory_allocated_mb'] = round(self.gpu_memory_allocated_mb, 3) report['gpu_memory_max_allocated_mb'] = round(self.gpu_memory_max_allocated_mb, 3) return report def log(self): report = self.report() if not report: return fields = ' '.join(f'{key}={value:.3f}' for key, value in report.items()) print(f'[{self.prefix}] {fields}') def reset(self): self.records.clear() self.gpu_memory_allocated_mb = 0.0 self.gpu_memory_max_allocated_mb = 0.0 def _sync(self): if torch.cuda.is_available(): torch.cuda.synchronize() def _capture_memory(self): if not torch.cuda.is_available(): return mb = 1024.0 * 1024.0 self.gpu_memory_allocated_mb = torch.cuda.memory_allocated() / mb self.gpu_memory_max_allocated_mb = torch.cuda.max_memory_allocated() / mb