import time import inspect import csv import logging from functools import wraps from collections import defaultdict from typing import Dict, Any, Tuple # Storage for timing statistics # Key: (function_name, defined_in, called_from) function_stats: Dict[Tuple[str, str, str], Dict[str, Any]] = defaultdict( lambda: {"calls": 0, "total_time": 0.0} ) def monitor_execution(func): """ Decorator to measure execution time and track caller modules. """ @wraps(func) def wrapper(*args, **kwargs): # Identify source and caller module_defined = inspect.getmodule(func).__name__ caller_frame = inspect.stack()[1] module_called = caller_frame.frame.f_globals.get("__name__", "unknown") start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() duration = end_time - start_time key = (func.__name__, module_defined, module_called) stats = function_stats[key] stats["calls"] += 1 stats["total_time"] += duration return result return wrapper def save_stats_to_csv(file_path: str) -> None: """ Exports performance data to a CSV file. """ try: with open(file_path, mode='w', newline='', encoding='utf-8') as file: writer = csv.writer(file) header = ["Function", "Calls", "Total Time", "Avg Time", "Defined In", "Called From"] writer.writerow(header) for (name, defined, called), data in function_stats.items(): avg = data["total_time"] / data["calls"] if data["calls"] > 0 else 0 row = [name, data["calls"], f"{data['total_time']:.6f}", f"{avg:.6f}", defined, called] writer.writerow(row) except Exception as e: logging.error(f"Failed to save profiler CSV: {e}") def print_stats() -> None: """ Prints a summary table of statistics to the console. """ header = f"{'Function':<30} {'Calls':<8} {'Avg Time (s)':<12} {'Defined In':<25}" print("\n" + "=" * 80) print(header) print("-" * 80) for (name, defined, _), data in function_stats.items(): avg = data["total_time"] / data["calls"] if data["calls"] > 0 else 0 line = f"{name:<30} {data['calls']:<8} {avg:<12.6f} {defined:<25}" print(line) print("=" * 80 + "\n")