dispatch: add support for statprof as a profiler

This can be selected using the config variable profiling.type or
the environment variable HGPROF ("ls" for the default, "stat" for
statprof).  The only tuneable is the frequency, profiling.freq,
which defaults to 1000 Hz.

If statprof is not available, a warning is printed.
This commit is contained in:
Bryan O'Sullivan 2012-04-09 13:48:45 -07:00
parent af163e9811
commit af2413c514
2 changed files with 93 additions and 38 deletions

View File

@ -687,6 +687,59 @@ def _dispatch(req):
if repo and repo != req.repo:
repo.close()
def lsprofile(ui, func, fp):
format = ui.config('profiling', 'format', default='text')
field = ui.config('profiling', 'sort', default='inlinetime')
climit = ui.configint('profiling', 'nested', default=5)
if not format in ['text', 'kcachegrind']:
ui.warn(_("unrecognized profiling format '%s'"
" - Ignored\n") % format)
format = 'text'
try:
from mercurial import lsprof
except ImportError:
raise util.Abort(_(
'lsprof not available - install from '
'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
p = lsprof.Profiler()
p.enable(subcalls=True)
try:
return func()
finally:
p.disable()
if format == 'kcachegrind':
import lsprofcalltree
calltree = lsprofcalltree.KCacheGrind(p)
calltree.output(fp)
else:
# format == 'text'
stats = lsprof.Stats(p.getstats())
stats.sort(field)
stats.pprint(limit=30, file=fp, climit=climit)
def statprofile(ui, func, fp):
try:
import statprof
except ImportError:
raise util.Abort(_(
'statprof not available - install using "easy_install statprof"'))
freq = ui.configint('profiling', 'freq', default=1000)
if freq > 0:
statprof.reset(freq)
else:
ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
statprof.start()
try:
return func()
finally:
statprof.stop()
statprof.display(fp)
def _runcommand(ui, options, cmd, cmdfunc):
def checkargs():
try:
@ -695,47 +748,28 @@ def _runcommand(ui, options, cmd, cmdfunc):
raise error.CommandError(cmd, _("invalid arguments"))
if options['profile']:
format = ui.config('profiling', 'format', default='text')
field = ui.config('profiling', 'sort', default='inlinetime')
climit = ui.configint('profiling', 'nested', default=5)
if not format in ['text', 'kcachegrind']:
ui.warn(_("unrecognized profiling format '%s'"
" - Ignored\n") % format)
format = 'text'
profiler = os.getenv('HGPROF')
if profiler is None:
profiler = ui.config('profiling', 'type', default='ls')
if profiler not in ('ls', 'stat'):
ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
profiler = 'ls'
output = ui.config('profiling', 'output')
if output:
path = ui.expandpath(output)
ostream = open(path, 'wb')
fp = open(path, 'wb')
else:
ostream = sys.stderr
fp = sys.stderr
try:
from mercurial import lsprof
except ImportError:
raise util.Abort(_(
'lsprof not available - install from '
'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
p = lsprof.Profiler()
p.enable(subcalls=True)
try:
return checkargs()
finally:
p.disable()
if format == 'kcachegrind':
import lsprofcalltree
calltree = lsprofcalltree.KCacheGrind(p)
calltree.output(ostream)
if profiler == 'ls':
return lsprofile(ui, checkargs, fp)
else:
# format == 'text'
stats = lsprof.Stats(p.getstats())
stats.sort(field)
stats.pprint(limit=30, file=ostream, climit=climit)
return statprofile(ui, checkargs, fp)
finally:
if output:
ostream.close()
fp.close()
else:
return checkargs()

View File

@ -938,14 +938,31 @@ information about working with phases.
``profiling``
"""""""""""""
Specifies profiling format and file output. In this section
description, 'profiling data' stands for the raw data collected
during profiling, while 'profiling report' stands for a statistical
text report generated from the profiling data. The profiling is done
using lsprof.
Specifies profiling type, format, and file output. Two profilers are
supported: an instrumenting profiler (named ``ls``), and a sampling
profiler (named ``stat``).
In this section description, 'profiling data' stands for the raw data
collected during profiling, while 'profiling report' stands for a
statistical text report generated from the profiling data. The
profiling is done using lsprof.
``type``
The type of profiler to use.
Default: ls.
``ls``
Use Python's built-in instrumenting profiler. This profiler
works on all platforms, but each line number it reports is the
first line of a function. This restriction makes it difficult to
identify the expensive parts of a non-trivial function.
``stat``
Use a third-party statistical profiler, statprof. This profiler
currently runs only on Unix systems, and is most useful for
profiling commands that run for longer than about 0.1 seconds.
``format``
Profiling format.
Profiling format. Specific to the ``ls`` instrumenting profiler.
Default: text.
``text``
@ -957,6 +974,10 @@ using lsprof.
file, the generated file can directly be loaded into
kcachegrind.
``frequency``
Sampling frequency. Specific to the ``stat`` sampling profiler.
Default: 1000.
``output``
File path where profiling data or report should be saved. If the
file exists, it is replaced. Default: None, data is printed on