Show More
@@ -0,0 +1,125 b'' | |||||
|
1 | #!/usr/bin/env python | |||
|
2 | # | |||
|
3 | # Copyright 2018 Paul Morelle <Paul.Morelle@octobus.net> | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms of the | |||
|
6 | # GNU General Public License version 2 or any later version. | |||
|
7 | # | |||
|
8 | # This script use the output of `hg perfrevlogwrite -T json --details` to draw | |||
|
9 | # various plot related to write performance in a revlog | |||
|
10 | # | |||
|
11 | # usage: perf-revlog-write-plot.py details.json | |||
|
12 | from __future__ import absolute_import, print_function | |||
|
13 | import json | |||
|
14 | import re | |||
|
15 | ||||
|
16 | import numpy as np | |||
|
17 | import scipy.signal | |||
|
18 | ||||
|
19 | from matplotlib import ( | |||
|
20 | pyplot as plt, | |||
|
21 | ticker as mticker, | |||
|
22 | ) | |||
|
23 | ||||
|
24 | ||||
|
25 | def plot(data): | |||
|
26 | items = {} | |||
|
27 | re_title = re.compile(r'^revisions #\d+ of \d+, rev (\d+)$') | |||
|
28 | for item in data: | |||
|
29 | m = re_title.match(item['title']) | |||
|
30 | if m is None: | |||
|
31 | continue | |||
|
32 | ||||
|
33 | rev = int(m.group(1)) | |||
|
34 | items[rev] = item | |||
|
35 | ||||
|
36 | min_rev = min(items.keys()) | |||
|
37 | max_rev = max(items.keys()) | |||
|
38 | ary = np.empty((2, max_rev - min_rev + 1)) | |||
|
39 | for rev, item in items.items(): | |||
|
40 | ary[0][rev - min_rev] = rev | |||
|
41 | ary[1][rev - min_rev] = item['wall'] | |||
|
42 | ||||
|
43 | fig = plt.figure() | |||
|
44 | comb_plt = fig.add_subplot(211) | |||
|
45 | other_plt = fig.add_subplot(212) | |||
|
46 | ||||
|
47 | comb_plt.plot(ary[0], | |||
|
48 | np.cumsum(ary[1]), | |||
|
49 | color='red', | |||
|
50 | linewidth=1, | |||
|
51 | label='comb') | |||
|
52 | ||||
|
53 | plots = [] | |||
|
54 | p = other_plt.plot(ary[0], | |||
|
55 | ary[1], | |||
|
56 | color='red', | |||
|
57 | linewidth=1, | |||
|
58 | label='wall') | |||
|
59 | plots.append(p) | |||
|
60 | ||||
|
61 | colors = { | |||
|
62 | 10: ('green', 'xkcd:grass green'), | |||
|
63 | 100: ('blue', 'xkcd:bright blue'), | |||
|
64 | 1000: ('purple', 'xkcd:dark pink'), | |||
|
65 | } | |||
|
66 | for n, color in colors.items(): | |||
|
67 | avg_n = np.convolve(ary[1], np.full(n, 1. / n), 'valid') | |||
|
68 | p = other_plt.plot(ary[0][n - 1:], | |||
|
69 | avg_n, | |||
|
70 | color=color[0], | |||
|
71 | linewidth=1, | |||
|
72 | label='avg time last %d' % n) | |||
|
73 | plots.append(p) | |||
|
74 | ||||
|
75 | med_n = scipy.signal.medfilt(ary[1], n + 1) | |||
|
76 | p = other_plt.plot(ary[0], | |||
|
77 | med_n, | |||
|
78 | color=color[1], | |||
|
79 | linewidth=1, | |||
|
80 | label='median time last %d' % n) | |||
|
81 | plots.append(p) | |||
|
82 | ||||
|
83 | formatter = mticker.ScalarFormatter() | |||
|
84 | formatter.set_scientific(False) | |||
|
85 | formatter.set_useOffset(False) | |||
|
86 | ||||
|
87 | comb_plt.grid() | |||
|
88 | comb_plt.xaxis.set_major_formatter(formatter) | |||
|
89 | comb_plt.legend() | |||
|
90 | ||||
|
91 | other_plt.grid() | |||
|
92 | other_plt.xaxis.set_major_formatter(formatter) | |||
|
93 | leg = other_plt.legend() | |||
|
94 | leg2plot = {} | |||
|
95 | for legline, plot in zip(leg.get_lines(), plots): | |||
|
96 | legline.set_picker(5) | |||
|
97 | leg2plot[legline] = plot | |||
|
98 | ||||
|
99 | def onpick(event): | |||
|
100 | legline = event.artist | |||
|
101 | plot = leg2plot[legline] | |||
|
102 | visible = not plot[0].get_visible() | |||
|
103 | for l in plot: | |||
|
104 | l.set_visible(visible) | |||
|
105 | ||||
|
106 | if visible: | |||
|
107 | legline.set_alpha(1.0) | |||
|
108 | else: | |||
|
109 | legline.set_alpha(0.2) | |||
|
110 | fig.canvas.draw() | |||
|
111 | fig.canvas.mpl_connect('pick_event', onpick) | |||
|
112 | ||||
|
113 | plt.show() | |||
|
114 | ||||
|
115 | ||||
|
116 | if __name__ == '__main__': | |||
|
117 | import sys | |||
|
118 | ||||
|
119 | if len(sys.argv) > 1: | |||
|
120 | print('reading from %r' % sys.argv[1]) | |||
|
121 | with open(sys.argv[1], 'r') as fp: | |||
|
122 | plot(json.load(fp)) | |||
|
123 | else: | |||
|
124 | print('reading from stdin') | |||
|
125 | plot(json.load(sys.stdin)) |
@@ -1,35 +1,36 b'' | |||||
1 | #require test-repo |
|
1 | #require test-repo | |
2 |
|
2 | |||
3 | $ . "$TESTDIR/helpers-testrepo.sh" |
|
3 | $ . "$TESTDIR/helpers-testrepo.sh" | |
4 | $ import_checker="$TESTDIR"/../contrib/import-checker.py |
|
4 | $ import_checker="$TESTDIR"/../contrib/import-checker.py | |
5 |
|
5 | |||
6 | $ cd "$TESTDIR"/.. |
|
6 | $ cd "$TESTDIR"/.. | |
7 |
|
7 | |||
8 | There are a handful of cases here that require renaming a module so it |
|
8 | There are a handful of cases here that require renaming a module so it | |
9 | doesn't overlap with a stdlib module name. There are also some cycles |
|
9 | doesn't overlap with a stdlib module name. There are also some cycles | |
10 | here that we should still endeavor to fix, and some cycles will be |
|
10 | here that we should still endeavor to fix, and some cycles will be | |
11 | hidden by deduplication algorithm in the cycle detector, so fixing |
|
11 | hidden by deduplication algorithm in the cycle detector, so fixing | |
12 | these may expose other cycles. |
|
12 | these may expose other cycles. | |
13 |
|
13 | |||
14 | Known-bad files are excluded by -X as some of them would produce unstable |
|
14 | Known-bad files are excluded by -X as some of them would produce unstable | |
15 | outputs, which should be fixed later. |
|
15 | outputs, which should be fixed later. | |
16 |
|
16 | |||
17 | $ testrepohg locate 'set:**.py or grep(r"^#!.*?python")' \ |
|
17 | $ testrepohg locate 'set:**.py or grep(r"^#!.*?python")' \ | |
18 | > 'tests/**.t' \ |
|
18 | > 'tests/**.t' \ | |
19 | > -X hgweb.cgi \ |
|
19 | > -X hgweb.cgi \ | |
20 | > -X setup.py \ |
|
20 | > -X setup.py \ | |
21 | > -X contrib/debugshell.py \ |
|
21 | > -X contrib/debugshell.py \ | |
22 | > -X contrib/hgweb.fcgi \ |
|
22 | > -X contrib/hgweb.fcgi \ | |
23 | > -X contrib/packaging/hg-docker \ |
|
23 | > -X contrib/packaging/hg-docker \ | |
24 | > -X contrib/python-zstandard/ \ |
|
24 | > -X contrib/python-zstandard/ \ | |
25 | > -X contrib/win32/hgwebdir_wsgi.py \ |
|
25 | > -X contrib/win32/hgwebdir_wsgi.py \ | |
|
26 | > -X contrib/perf-utils/perf-revlog-write-plot.py \ | |||
26 | > -X doc/gendoc.py \ |
|
27 | > -X doc/gendoc.py \ | |
27 | > -X doc/hgmanpage.py \ |
|
28 | > -X doc/hgmanpage.py \ | |
28 | > -X i18n/posplit \ |
|
29 | > -X i18n/posplit \ | |
29 | > -X mercurial/thirdparty \ |
|
30 | > -X mercurial/thirdparty \ | |
30 | > -X tests/hypothesishelpers.py \ |
|
31 | > -X tests/hypothesishelpers.py \ | |
31 | > -X tests/test-check-interfaces.py \ |
|
32 | > -X tests/test-check-interfaces.py \ | |
32 | > -X tests/test-demandimport.py \ |
|
33 | > -X tests/test-demandimport.py \ | |
33 | > -X tests/test-imports-checker.t \ |
|
34 | > -X tests/test-imports-checker.t \ | |
34 | > -X tests/test-verify-repo-operations.py \ |
|
35 | > -X tests/test-verify-repo-operations.py \ | |
35 | > | sed 's-\\-/-g' | "$PYTHON" "$import_checker" - |
|
36 | > | sed 's-\\-/-g' | "$PYTHON" "$import_checker" - |
General Comments 0
You need to be logged in to leave comments.
Login now