|
|
#!/usr/bin/env python3
|
|
|
#
|
|
|
# hgperf - measure performance of Mercurial commands
|
|
|
#
|
|
|
# Copyright 2014 Olivia Mackall <olivia@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)
|
|
|
|
|
|
from mercurial import (
|
|
|
dispatch,
|
|
|
util,
|
|
|
)
|
|
|
|
|
|
|
|
|
def timer(func, title=None):
|
|
|
results = []
|
|
|
begin = util.timer()
|
|
|
count = 0
|
|
|
while True:
|
|
|
ostart = os.times()
|
|
|
cstart = util.timer()
|
|
|
r = func()
|
|
|
cstop = 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 = 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()
|
|
|
|
|
|
|
|
|
dispatch.runcommand = runcommand
|
|
|
|
|
|
dispatch.run()
|
|
|
|