comparison contrib/hgperf @ 20839:377a111d1cd2

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.
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Sat, 15 Feb 2014 19:51:20 +0900
parents
children 22fbca1d11ed
comparison
equal deleted inserted replaced
20838:fe849868fc5a 20839:377a111d1cd2
1 #!/usr/bin/env python
2 #
3 # hgperf - measure performance of Mercurial commands
4 #
5 # Copyright 2014 Matt Mackall <mpm@selenic.com>
6 #
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
9
10 '''measure performance of Mercurial commands
11
12 Using ``hgperf`` instead of ``hg`` measures performance of the target
13 Mercurial command. For example, the execution below measures
14 performance of :hg:`heads --topo`::
15
16 $ hgperf heads --topo
17
18 All command output via ``ui`` is suppressed, and just measurement
19 result is displayed: see also "perf" extension in "contrib".
20
21 Costs of processing before dispatching to the command function like
22 below are not measured::
23
24 - parsing command line (e.g. option validity check)
25 - reading configuration files in
26
27 But ``pre-`` and ``post-`` hook invocation for the target command is
28 measured, even though these are invoked before or after dispatching to
29 the command function, because these may be required to repeat
30 execution of the target command correctly.
31 '''
32
33 import os
34 import sys
35
36 libdir = '@LIBDIR@'
37
38 if libdir != '@' 'LIBDIR' '@':
39 if not os.path.isabs(libdir):
40 libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
41 libdir)
42 libdir = os.path.abspath(libdir)
43 sys.path.insert(0, libdir)
44
45 # enable importing on demand to reduce startup time
46 try:
47 from mercurial import demandimport; demandimport.enable()
48 except ImportError:
49 import sys
50 sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
51 ' '.join(sys.path))
52 sys.stderr.write("(check your install and PYTHONPATH)\n")
53 sys.exit(-1)
54
55 import mercurial.util
56 import mercurial.dispatch
57
58 import time
59
60 def timer(func, title=None):
61 results = []
62 begin = time.time()
63 count = 0
64 while True:
65 ostart = os.times()
66 cstart = time.time()
67 r = func()
68 cstop = time.time()
69 ostop = os.times()
70 count += 1
71 a, b = ostart, ostop
72 results.append((cstop - cstart, b[0] - a[0], b[1]-a[1]))
73 if cstop - begin > 3 and count >= 100:
74 break
75 if cstop - begin > 10 and count >= 3:
76 break
77 if title:
78 sys.stderr.write("! %s\n" % title)
79 if r:
80 sys.stderr.write("! result: %s\n" % r)
81 m = min(results)
82 sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n"
83 % (m[0], m[1] + m[2], m[1], m[2], count))
84
85 orgruncommand = mercurial.dispatch.runcommand
86
87 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
88 ui.pushbuffer()
89 lui.pushbuffer()
90 timer(lambda : orgruncommand(lui, repo, cmd, fullargs, ui,
91 options, d, cmdpats, cmdoptions))
92 ui.popbuffer()
93 lui.popbuffer()
94
95 mercurial.dispatch.runcommand = runcommand
96
97 for fp in (sys.stdin, sys.stdout, sys.stderr):
98 mercurial.util.setbinary(fp)
99
100 mercurial.dispatch.run()