# HG changeset patch # User FUJIWARA Katsunori # Date 1392461480 -32400 # Node ID 377a111d1cd22e7521136dbd913f36d7bfc5365c # Parent fe849868fc5a6978fc69192f5e8c6fb35ff355eb contrib: add "hgperf" command to measure performance of commands easily Newly added "hgperf" command repeats "dispatch.runcommand()" for specified Mercurial command and measure performance of it in the same manner of "contrib/perf.py" extension. Users (mainly developers) can examine performance of the target command easily, without adding new entry for it to "contrib/perf.py" extension. diff -r fe849868fc5a -r 377a111d1cd2 contrib/hgperf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/hgperf Sat Feb 15 19:51:20 2014 +0900 @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# +# hgperf - measure performance of Mercurial commands +# +# Copyright 2014 Matt Mackall +# +# 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 + +import time + +def timer(func, title=None): + results = [] + begin = time.time() + count = 0 + while True: + ostart = os.times() + cstart = time.time() + r = func() + cstop = time.time() + 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()