Francesco Romani has uploaded a new change for review. Change subject: profile: port profiling support from VDSM ......................................................................
profile: port profiling support from VDSM Change-Id: I5244ddcf83dc551b7139080017306e0395bcf382 Signed-off-by: Francesco Romani <[email protected]> --- M mom/Makefile.am A mom/Profile.py M mom/__init__.py M momd 4 files changed, 140 insertions(+), 1 deletion(-) git pull ssh://gerrit.ovirt.org:29418/mom refs/changes/80/37780/1 diff --git a/mom/Makefile.am b/mom/Makefile.am index c825b3f..d4d931b 100644 --- a/mom/Makefile.am +++ b/mom/Makefile.am @@ -32,6 +32,7 @@ Monitor.py \ Plotter.py \ PolicyEngine.py \ + Profile.py \ RPCServer.py \ __init__.py \ $(NULL) diff --git a/mom/Profile.py b/mom/Profile.py new file mode 100644 index 0000000..b232ba0 --- /dev/null +++ b/mom/Profile.py @@ -0,0 +1,124 @@ +# +# Copyright 2014-2015 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# + +""" +This module provides cpu profiling. +""" + +from functools import wraps +import logging +import os +import threading + +# Import yappi lazily when profile is started +yappi = None + +# Defaults + +_ENABLED = False +_FILENAME = '/var/run/momd.prof' +_FORMAT = 'pstat' +_BUILTINS = True +_CLOCK = 'cpu' +_THREADS = True + +_lock = threading.Lock() + + +class Error(Exception): + """ Raised when profiler is used incorrectly """ + + +def setup(config): + global _ENABLED + global _FILENAME + global _FORMAT + global _BUILTINS + global _CLOCK + _ENABLED = config.getboolean('devel', 'profile-enable') + _FILENAME = config.get('devel', 'profile-path') + _FORMAT = config.get('devel', 'profile-format') + _BUILTINS = config.getboolean('devel', 'profile-builtins') + _CLOCK = config.get('devel', 'profile-clock') + + +def start(): + """ Starts application wide profiling """ + if is_enabled(): + _start_profiling(_CLOCK, _BUILTINS, _THREADS) + + +def stop(): + """ Stops application wide profiling """ + if is_enabled(): + _stop_profiling(_FILENAME, _FORMAT) + + +def is_enabled(): + return _ENABLED + + +def is_running(): + with _lock: + return yappi and yappi.is_running() + + +def profile(filename, format=_FORMAT, clock=_CLOCK, builtins=_BUILTINS, + threads=_THREADS): + """ + Profile decorated function, saving profile to filename using format. + + Note: you cannot use this when the application wide profile is enabled, or + profile multiple functions in the same code path. + """ + def decorator(f): + @wraps(f) + def wrapper(*a, **kw): + _start_profiling(clock, builtins, threads) + try: + return f(*a, **kw) + finally: + _stop_profiling(filename, format) + return wrapper + return decorator + + +def _start_profiling(clock, builtins, threads): + global yappi + logging.debug("Starting profiling") + with _lock: + 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 Error('Profiler is already running') + yappi.set_clock_type(clock) + yappi.start(builtins=builtins, profile_threads=threads) + + +def _stop_profiling(filename, format): + logging.debug("Stopping profiling") + with _lock: + if yappi.is_running(): + yappi.stop() + stats = yappi.get_func_stats() + stats.save(filename, format) + yappi.clear_stats() diff --git a/mom/__init__.py b/mom/__init__.py index dbb0c68..46672df 100644 --- a/mom/__init__.py +++ b/mom/__init__.py @@ -10,6 +10,7 @@ from mom.PolicyEngine import PolicyEngine from mom.RPCServer import RPCServer from mom.MOMFuncs import MOMFuncs, EXPORTED_ATTRIBUTE +from . import Profile def load_config(fname, overrides=None): @@ -39,6 +40,12 @@ config.set('host', 'collectors', 'HostMemory') config.add_section('guest') config.set('guest', 'collectors', 'GuestQemuProc, GuestMemory') + config.add_section('devel') + config.set('devel', 'profile-enable', 'false') + config.set('devel', 'profile-path', '/var/run/momd.prof') + config.set('devel', 'profile-format', 'pstat') + config.set('devel', 'profile-builtins', 'true') + config.set('devel', 'profile-clock', 'cpu') # Override defaults from the config file config.read(fname) diff --git a/momd b/momd index aaa5a89..efb7f77 100755 --- a/momd +++ b/momd @@ -129,7 +129,14 @@ conf_data = mom.load_config(options.config_file, config_overrides) mom_instance = mom.MOM.from_config(conf_data) - mom_instance.run() + mom.Profile.setup(conf_data) + mom.Profile.start() + try: + mom_instance.run() + except Exception: + raise + finally: + mom.Profile.stop() sys.exit(0) if __name__ == "__main__": -- To view, visit http://gerrit.ovirt.org/37780 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I5244ddcf83dc551b7139080017306e0395bcf382 Gerrit-PatchSet: 1 Gerrit-Project: mom Gerrit-Branch: master Gerrit-Owner: Francesco Romani <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
