[UI] Add --profile to GTKUI and console and allow custom filename

Add --profile to commonoptions making the option now available for
daemon and all UIs. --profile option now prints to stdout unless an
optional filename is specified.
This commit is contained in:
bendikro 2016-01-15 18:24:00 +01:00
parent 7b54a2a1ee
commit c90af1ce6c
7 changed files with 77 additions and 49 deletions

View file

@ -726,7 +726,6 @@ class VersionSplit(object):
"""
def __init__(self, ver):
import re
version_re = re.compile(r'''
^
(?P<version>\d+\.\d+) # minimum 'N.N'
@ -993,3 +992,40 @@ def unicode_argv():
encoding = encoding or "utf-8"
return [arg.decode(encoding) for arg in sys.argv]
def run_profiled(func, *args, **kwargs):
"""
Profile a function with cProfile
Args:
func (func): The function to profile
*args (tuple): The arguments to pass to the function
do_profile (bool, optional): If profiling should be performed. Defaults to True.
output_file (str, optional): Filename to save profile results. If None, print to stdout.
Defaults to None.
"""
if kwargs.get("do_profile", True) is not False:
import cProfile
profiler = cProfile.Profile()
def on_shutdown():
output_file = kwargs.get("output_file", None)
if output_file:
profiler.dump_stats(output_file)
log.info("Profile stats saved to %s", output_file)
print "Profile stats saved to %s" % output_file
else:
import pstats
import StringIO
strio = StringIO.StringIO()
ps = pstats.Stats(profiler, stream=strio).sort_stats('cumulative')
ps.print_stats()
print strio.getvalue()
try:
return profiler.runcall(func, *args)
finally:
on_shutdown()
else:
return func(*args)

View file

@ -214,19 +214,5 @@ def start_daemon(skip_start=False):
if options.pidfile:
os.remove(options.pidfile)
if options.profile:
import cProfile
profiler = cProfile.Profile()
profile_output = deluge.configmanager.get_config_dir("deluged.profile")
# Twisted catches signals to terminate
def save_profile_stats():
profiler.dump_stats(profile_output)
print("Profile stats saved to %s" % profile_output)
from twisted.internet import reactor
reactor.addSystemEventTrigger("before", "shutdown", save_profile_stats)
print("Running with profiler...")
profiler.runcall(run_daemon, options)
else:
return run_daemon(options)
return deluge.common.run_profiled(run_daemon, options, output_file=options.profile,
do_profile=options.profile)

View file

@ -106,6 +106,9 @@ class BaseArgParser(argparse.ArgumentParser):
help="Sets the log level to 'none', this is the same as `-L none`")
self.group.add_argument("-r", "--rotate-logs", action="store_true", default=False,
help="Rotate logfiles.")
self.group.add_argument("--profile", metavar="<results file>", action="store", nargs="?", default=False,
help="Profile %(prog)s with cProfile. Prints results to stdout"
"unless a filename is specififed.")
self.group.add_argument("-h", "--help", action=HelpAction, help='Show this help message and exit')
def parse_args(self, *args):

View file

@ -8,12 +8,15 @@
# See LICENSE for more details.
#
import logging
import os
import deluge.common
from deluge.ui.baseargparser import DelugeTextHelpFormatter
from deluge.ui.console import UI_PATH
from deluge.ui.ui import UI
log = logging.getLogger(__name__)
#
# Note: Cannot import from console.main here because it imports the twisted reactor.
@ -76,4 +79,13 @@ class Console(UI):
def start(self, args=None):
super(Console, self).start(args)
from deluge.ui.console.main import ConsoleUI # import here because (see top)
ConsoleUI(self.options, self.console_cmds)
def run(options):
try:
ConsoleUI(self.options, self.console_cmds)
except Exception as ex:
log.exception(ex)
raise
deluge.common.run_profiled(run, self.options, output_file=self.options.profile,
do_profile=self.options.profile)

View file

@ -184,7 +184,7 @@ class ConsoleUI(component.Component):
curses.wrapper(self.run)
elif self.interactive and deluge.common.windows_check():
print("""\nDeluge-console does not run in interactive mode on Windows. \n
Please use commands from the command line, eg:\n
Please use commands from the command line, e.g.:\n
deluge-console.exe help
deluge-console.exe info
deluge-console.exe "add --help"

View file

@ -146,9 +146,17 @@ class Gtk(UI):
" to a currently running Deluge GTK instance")
def start(self, args=None):
from gtkui import GtkUI
super(Gtk, self).start(args)
GtkUI(self.options)
def run(options):
try:
GtkUI(options)
except Exception as ex:
log.exception(ex)
raise
deluge.common.run_profiled(run, self.options, output_file=self.options.profile,
do_profile=self.options.profile)
class GtkUI(object):

View file

@ -9,17 +9,14 @@
from __future__ import print_function
import logging
import os
from deluge.common import osx_check, windows_check
from deluge.common import osx_check, run_profiled, windows_check
from deluge.configmanager import get_config_dir
from deluge.ui.ui import UI
#
# Note: Cannot import twisted.internet.reactor because Web is imported from
# from web/__init__.py loaded by the script entry points defined in setup.py
#
log = logging.getLogger(__name__)
class WebUI(object):
@ -56,8 +53,6 @@ class Web(UI):
help="Binds the webserver to a specific IP address")
group.add_argument("-p", "--port", metavar="<port>", type=int, action="store", default=None,
help="Sets the port to be used for the webserver")
group.add_argument("--profile", action="store_true", default=False,
help="Profile the web server code")
try:
import OpenSSL
assert OpenSSL.__version__
@ -123,26 +118,14 @@ class Web(UI):
self.server.https = self.options.ssl
def run_server():
self.server.install_signal_handlers()
self.server.start()
if self.options.profile:
import cProfile
profiler = cProfile.Profile()
profile_output = get_config_dir("delugeweb.profile")
# Twisted catches signals to terminate
def save_profile_stats():
profiler.dump_stats(profile_output)
print("Profile stats saved to %s" % profile_output)
from twisted.internet import reactor # import here because (see top)
reactor.addSystemEventTrigger("before", "shutdown", save_profile_stats)
print("Running with profiler...")
profiler.runcall(run_server)
else:
run_server()
def run():
try:
self.server.install_signal_handlers()
self.server.start()
except Exception as ex:
log.exception(ex)
raise
run_profiled(run, output_file=self.options.profile, do_profile=self.options.profile)
def start():