Nir Soffer has uploaded a new change for review.
Change subject: profiling: Add generic Profiler class ......................................................................
profiling: Add generic Profiler class
Current profiling solution is usable only by vdsm, writing the profile to /run/vdsm/vdsmd.prof, and assuming vdsm configuration.
This patch adds a generic Profiler class which can be used by any application, for example supervdsm or ovirt-ha-agent.
Example usage:
from vdsm.profiling import cpu ... profiler = cpu.Profiler("/run/myapp/profile.pstat") profiler.start() ... profiler.stop()
Change-Id: I66b7e872959ac2c26c003d26f1fcde2926f47969 Signed-off-by: Nir Soffer nsoffer@redhat.com --- M lib/vdsm/profiling/cpu.py 1 file changed, 65 insertions(+), 32 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/52/65252/1
diff --git a/lib/vdsm/profiling/cpu.py b/lib/vdsm/profiling/cpu.py index 47f0ecd..286fcdd 100644 --- a/lib/vdsm/profiling/cpu.py +++ b/lib/vdsm/profiling/cpu.py @@ -45,18 +45,78 @@ _THREADS = True
_lock = threading.Lock() +_profiler = None + + +class Profiler(object): + + def __init__(self, filename, format='pstat', clock='cpu', builtins=True, + threads=True): + self.filename = filename + self.format = format + self.clock = clock + self.builtins = builtins + self.threads = threads + + def start(self): + # Lazy import so we do not effect runtime environment if profiling is + # not used. + global yappi + import yappi + + # yappi start semantics are a bit too liberal, returning success if + # yappi is already started, happily having too different code paths + # that thinks they own the single process profiler. + if yappi.is_running(): + raise UsageError('CPU profiler is already running') + + logging.info("Starting CPU profiling") + yappi.set_clock_type(self.clock) + yappi.start(builtins=self.builtins, profile_threads=self.threads) + + def stop(self): + if not yappi.is_running(): + raise UsageError("CPU profiler is not running") + + logging.info("Stopping CPU profiling") + yappi.stop() + stats = yappi.get_func_stats() + stats.save(self.filename, self.format) + yappi.clear_stats() + + def __enter__(self): + self.start() + return self + + def __exit__(self, t, v, tb): + try: + self.stop() + except Exception: + if t is None: + raise + # Do not hide original exception + logging.exception("Error stopping profiler")
def start(): """ Starts application wide CPU profiling """ + global _profiler if is_enabled(): - _start_profiling(_CLOCK, _BUILTINS, _THREADS) + with _lock: + if _profiler: + raise UsageError('CPU profiler is already running') + _profiler = Profiler(_FILENAME, format=_FORMAT, clock=_CLOCK, + builtins=_BUILTINS, threads=_THREADS) + _profiler.start()
def stop(): """ Stops application wide CPU profiling """ + global _profiler if is_enabled(): - _stop_profiling(_FILENAME, _FORMAT) + with _lock: + _profiler.stop() + _profiler = None
def is_enabled(): @@ -79,36 +139,9 @@ def decorator(f): @wraps(f) def wrapper(*a, **kw): - _start_profiling(clock, builtins, threads) - try: + profiler = Profiler(filename, format=format, clock=clock, + builtins=builtins, threads=threads) + with profiler: return f(*a, **kw) - finally: - _stop_profiling(filename, format) return wrapper return decorator - - -def _start_profiling(clock, builtins, threads): - global yappi - logging.debug("Starting CPU profiling") - - import yappi - - with _lock: - # yappi start semantics are a bit too liberal, returning success if - # yappi is already started, happily having too different code paths - # that thinks they own the single process profiler. - if yappi.is_running(): - raise UsageError('CPU profiler is already running') - yappi.set_clock_type(clock) - yappi.start(builtins=builtins, profile_threads=threads) - - -def _stop_profiling(filename, format): - logging.debug("Stopping CPU profiling") - with _lock: - if yappi.is_running(): - yappi.stop() - stats = yappi.get_func_stats() - stats.save(filename, format) - yappi.clear_stats()
gerrit-hooks has posted comments on this change.
Change subject: profiling: Add generic Profiler class ......................................................................
Patch Set 1:
* Update tracker: IGNORE, no Bug-Url found * Check Bug-Url::WARN, no bug url found, make sure header matches 'Bug-Url: ' and is a valid url. * Check merged to previous::IGNORE, Not in stable branch (['ovirt-3.6', 'ovirt-4.0'])
Nir Soffer has posted comments on this change.
Change subject: profiling: Add generic Profiler class ......................................................................
Patch Set 1: Verified+1
vdsm-patches@lists.fedorahosted.org