Mercurial > hg
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() |