Source code for dubfi.profile_util
# Copyright 2025 DWD
# SPDX-License-Identifier: BSD-3-Clause
"""Profiling and performance monitoring utilities.
.. codeauthor:: Valentin Bruch, DWD <valentin.bruch@dwd.de>
.. versionadded:: 0.1.0 (initial release)
"""
import functools
from time import time_ns
from . import log
[docs]
def timer(f, log=log):
"""Log duration of wall clock time of function call."""
@functools.wraps(f)
def wrap(*args, **kwargs):
t1 = time_ns()
res = f(*args, **kwargs)
t2 = time_ns()
if t2 - t1 >= 1e9:
log.info(f"{f.__name__:s} took {1e-9 * (t2 - t1):.2f} s")
else:
log.info(f"{f.__name__:s} took {1e-6 * (t2 - t1):.2f} ms")
return res
return wrap
[docs]
def profile_fnc(fnc, target=None):
"""Profile function and save result to file (decorator)."""
import cProfile
if target is None:
import multiprocessing as mp
target = f"pstat_{fnc.__name__}_{mp.current_process().ident}.dat"
@functools.wraps(fnc)
def wrapper(*args, **kwargs):
log.info(f"Start profiling, output will be written to {target}")
with cProfile.Profile() as pr:
try:
result = fnc(*args, **kwargs)
finally:
pr.dump_stats(target)
log.info(f"Completed profiling, output written to {target}")
return result
return wrapper
[docs]
def monitor_memory(interval: float = 10, log_fn=log.info) -> None:
"""Create daemon thread that logs memory usage.
Parameters
----------
interval: float
logging interval in seconds
log_fn: callable
output function, can be print or log.info or similar. This
function should take one string as argument.
"""
from threading import Thread
Thread(target=_monitor_memory_thread, args=(interval, log_fn), daemon=True).start()
[docs]
def _monitor_memory_thread(interval: float, log_fn) -> None:
"""Log memory usage to log_fn in infinite loop."""
from time import sleep
from psutil import Process
p = Process()
scale = 2**-30
while True:
rss, vms, shared, text, lib, data, dirty = p.memory_info()
log_fn(
f"{p.pid: 6d}: res={rss * scale:5.2f}GiB, virt={vms * scale:5.2f}GiB, data={data * scale:5.2f}GiB, shared={shared * scale:5.2f}GiB, dirty:{dirty: 2d}"
)
sleep(interval)