|
|
#!/usr/bin/env python
|
|
|
#
|
|
|
# hgperf - measure performance of Mercurial commands
|
|
|
#
|
|
|
# Copyright 2014 Matt Mackall <mpm@selenic.com>
|
|
|
#
|
|
|
# This software may be used and distributed according to the terms of the
|
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
|
|
'''measure performance of Mercurial commands
|
|
|
|
|
|
Using ``hgperf`` instead of ``hg`` measures performance of the target
|
|
|
Mercurial command. For example, the execution below measures
|
|
|
performance of :hg:`heads --topo`::
|
|
|
|
|
|
$ hgperf heads --topo
|
|
|
|
|
|
All command output via ``ui`` is suppressed, and just measurement
|
|
|
result is displayed: see also "perf" extension in "contrib".
|
|
|
|
|
|
Costs of processing before dispatching to the command function like
|
|
|
below are not measured::
|
|
|
|
|
|
- parsing command line (e.g. option validity check)
|
|
|
- reading configuration files in
|
|
|
|
|
|
But ``pre-`` and ``post-`` hook invocation for the target command is
|
|
|
measured, even though these are invoked before or after dispatching to
|
|
|
the command function, because these may be required to repeat
|
|
|
execution of the target command correctly.
|
|
|
'''
|
|
|
|
|
|
import os
|
|
|
import sys
|
|
|
|
|
|
libdir = '@LIBDIR@'
|
|
|
|
|
|
if libdir != '@' 'LIBDIR' '@':
|
|
|
if not os.path.isabs(libdir):
|
|
|
libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
|
|
libdir)
|
|
|
libdir = os.path.abspath(libdir)
|
|
|
sys.path.insert(0, libdir)
|
|
|
|
|
|
# enable importing on demand to reduce startup time
|
|
|
try:
|
|
|
from mercurial import demandimport; demandimport.enable()
|
|
|
except ImportError:
|
|
|
import sys
|
|
|
sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
|
|
|
' '.join(sys.path))
|
|
|
sys.stderr.write("(check your install and PYTHONPATH)\n")
|
|
|
sys.exit(-1)
|
|
|
|
|
|
import mercurial.util
|
|
|
import mercurial.dispatch
|
|
|
|
|
|
def timer(func, title=None):
|
|
|
results = []
|
|
|
begin = mercurial.util.timer()
|
|
|
count = 0
|
|
|
while True:
|
|
|
ostart = os.times()
|
|
|
cstart = mercurial.util.timer()
|
|
|
r = func()
|
|
|
cstop = mercurial.util.timer()
|
|
|
ostop = os.times()
|
|
|
count += 1
|
|
|
a, b = ostart, ostop
|
|
|
results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
|
|
|
if cstop - begin > 3 and count >= 100:
|
|
|
break
|
|
|
if cstop - begin > 10 and count >= 3:
|
|
|
break
|
|
|
if title:
|
|
|
sys.stderr.write("! %s\n" % title)
|
|
|
if r:
|
|
|
sys.stderr.write("! result: %s\n" % r)
|
|
|
m = min(results)
|
|
|
sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
|
|
|
% (m[0], m[1] + m[2], m[1], m[2], count))
|
|
|
|
|
|
orgruncommand = mercurial.dispatch.runcommand
|
|
|
|
|
|
def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
|
|
|
ui.pushbuffer()
|
|
|
lui.pushbuffer()
|
|
|
timer(lambda : orgruncommand(lui, repo, cmd, fullargs, ui,
|
|
|
options, d, cmdpats, cmdoptions))
|
|
|
ui.popbuffer()
|
|
|
lui.popbuffer()
|
|
|
|
|
|
mercurial.dispatch.runcommand = runcommand
|
|
|
|
|
|
for fp in (sys.stdin, sys.stdout, sys.stderr):
|
|
|
mercurial.util.setbinary(fp)
|
|
|
|
|
|
mercurial.dispatch.run()
|
|
|
|