Source code for pathsim.utils.analysis
########################################################################################
##
## DEBUGGING AND EVALUATION TOOLS
## (utils/analysis.py)
##
## Milan Rother 2024
##
########################################################################################
# IMPORTS ==============================================================================
from time import perf_counter
from functools import wraps
from contextlib import ContextDecorator
from .logger import LoggerManager
try:
import cProfile, pstats
PROFILE_AVAILABLE = True
except ImportError:
PROFILE_AVAILABLE = False
# CLASSES ==============================================================================
[docs]
class Timer(ContextDecorator):
"""Context manager that times the execution time
of the code inside of the context in 'ms' for
debugging purposes.
Example
-------
.. code-block:: python
#time the code within the context
with Timer() as T:
complicated_function()
#print the runtime in ms
print(T)
Parameters
----------
verbose : bool
flag for verbose output (uses logging at DEBUG level)
"""
def __init__(self, verbose=True):
self.verbose = verbose
self.time = None
self.logger = LoggerManager().get_logger("analysis.timer")
def __float__(self):
return self.time
def __repr__(self):
if self.time is None: return None
return f"{self.time*1e3:.3f}ms"
def __enter__(self):
self._start = perf_counter()
return self
def __exit__(self, type, value, traceback):
self.time = perf_counter() - self._start
if self.verbose:
self.logger.debug(str(self))
[docs]
def timer(func):
"""Shows the execution time in milliseconds of the
function object passed for debugging purposes (uses
logging at DEBUG level).
Parameters
----------
func : callable
function to track execution time of
"""
@wraps(func)
def wrap_func(*args, **kwargs):
logger = LoggerManager().get_logger("analysis.profiler")
with Timer(verbose=False) as T:
result = func(*args, **kwargs)
logger.debug(f"Function '{func.__name__!r}' executed in {T}")
return result
return wrap_func
[docs]
class Profiler(ContextDecorator):
"""Context manager for easy code profiling
Example
-------
.. code-block:: python
#profile the code within the context
with Profiler():
complicated_function()
Parameters
----------
top_n : int
track top n function calls
sort_by : str
method to sort function cally by
"""
def __init__(self, top_n=50, sort_by="cumulative"):
self.top_n = top_n
self.sort_by = sort_by
if not PROFILE_AVAILABLE:
_msg = "'Profiler' not available, make sure 'cProfile' and 'pstats' is installed!"
raise ImportError(_msg)
self.profiler = cProfile.Profile()
def __enter__(self):
self.profiler.enable()
return self
def __exit__(self, *exc):
self.profiler.disable()
stats = pstats.Stats(self.profiler)
stats.strip_dirs()
stats.sort_stats(self.sort_by)
stats.print_stats(self.top_n)
return False