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