Show More
@@ -1,125 +1,127 b'' | |||||
1 | #!/usr/bin/env python |
|
1 | #!/usr/bin/env python | |
2 | # |
|
2 | # | |
3 | # Copyright 2018 Paul Morelle <Paul.Morelle@octobus.net> |
|
3 | # Copyright 2018 Paul Morelle <Paul.Morelle@octobus.net> | |
4 | # |
|
4 | # | |
5 | # This software may be used and distributed according to the terms of the |
|
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. |
|
6 | # GNU General Public License version 2 or any later version. | |
7 | # |
|
7 | # | |
8 | # This script use the output of `hg perfrevlogwrite -T json --details` to draw |
|
8 | # This script use the output of `hg perfrevlogwrite -T json --details` to draw | |
9 | # various plot related to write performance in a revlog |
|
9 | # various plot related to write performance in a revlog | |
10 | # |
|
10 | # | |
11 | # usage: perf-revlog-write-plot.py details.json |
|
11 | # usage: perf-revlog-write-plot.py details.json | |
12 | from __future__ import absolute_import, print_function |
|
12 | from __future__ import absolute_import, print_function | |
13 | import json |
|
13 | import json | |
14 | import re |
|
14 | import re | |
15 |
|
15 | |||
16 | import numpy as np |
|
16 | import numpy as np | |
17 | import scipy.signal |
|
17 | import scipy.signal | |
18 |
|
18 | |||
19 | from matplotlib import ( |
|
19 | from matplotlib import ( | |
20 | pyplot as plt, |
|
20 | pyplot as plt, | |
21 | ticker as mticker, |
|
21 | ticker as mticker, | |
22 | ) |
|
22 | ) | |
23 |
|
23 | |||
24 |
|
24 | |||
25 | def plot(data): |
|
25 | def plot(data, title=None): | |
26 | items = {} |
|
26 | items = {} | |
27 | re_title = re.compile(r'^revisions #\d+ of \d+, rev (\d+)$') |
|
27 | re_title = re.compile(r'^revisions #\d+ of \d+, rev (\d+)$') | |
28 | for item in data: |
|
28 | for item in data: | |
29 | m = re_title.match(item['title']) |
|
29 | m = re_title.match(item['title']) | |
30 | if m is None: |
|
30 | if m is None: | |
31 | continue |
|
31 | continue | |
32 |
|
32 | |||
33 | rev = int(m.group(1)) |
|
33 | rev = int(m.group(1)) | |
34 | items[rev] = item |
|
34 | items[rev] = item | |
35 |
|
35 | |||
36 | min_rev = min(items.keys()) |
|
36 | min_rev = min(items.keys()) | |
37 | max_rev = max(items.keys()) |
|
37 | max_rev = max(items.keys()) | |
38 | ary = np.empty((2, max_rev - min_rev + 1)) |
|
38 | ary = np.empty((2, max_rev - min_rev + 1)) | |
39 | for rev, item in items.items(): |
|
39 | for rev, item in items.items(): | |
40 | ary[0][rev - min_rev] = rev |
|
40 | ary[0][rev - min_rev] = rev | |
41 | ary[1][rev - min_rev] = item['wall'] |
|
41 | ary[1][rev - min_rev] = item['wall'] | |
42 |
|
42 | |||
43 | fig = plt.figure() |
|
43 | fig = plt.figure() | |
44 | comb_plt = fig.add_subplot(211) |
|
44 | comb_plt = fig.add_subplot(211) | |
45 | other_plt = fig.add_subplot(212) |
|
45 | other_plt = fig.add_subplot(212) | |
46 |
|
46 | |||
47 | comb_plt.plot(ary[0], |
|
47 | comb_plt.plot(ary[0], | |
48 | np.cumsum(ary[1]), |
|
48 | np.cumsum(ary[1]), | |
49 | color='red', |
|
49 | color='red', | |
50 | linewidth=1, |
|
50 | linewidth=1, | |
51 | label='comb') |
|
51 | label='comb') | |
52 |
|
52 | |||
53 | plots = [] |
|
53 | plots = [] | |
54 | p = other_plt.plot(ary[0], |
|
54 | p = other_plt.plot(ary[0], | |
55 | ary[1], |
|
55 | ary[1], | |
56 | color='red', |
|
56 | color='red', | |
57 | linewidth=1, |
|
57 | linewidth=1, | |
58 | label='wall') |
|
58 | label='wall') | |
59 | plots.append(p) |
|
59 | plots.append(p) | |
60 |
|
60 | |||
61 | colors = { |
|
61 | colors = { | |
62 | 10: ('green', 'xkcd:grass green'), |
|
62 | 10: ('green', 'xkcd:grass green'), | |
63 | 100: ('blue', 'xkcd:bright blue'), |
|
63 | 100: ('blue', 'xkcd:bright blue'), | |
64 | 1000: ('purple', 'xkcd:dark pink'), |
|
64 | 1000: ('purple', 'xkcd:dark pink'), | |
65 | } |
|
65 | } | |
66 | for n, color in colors.items(): |
|
66 | for n, color in colors.items(): | |
67 | avg_n = np.convolve(ary[1], np.full(n, 1. / n), 'valid') |
|
67 | avg_n = np.convolve(ary[1], np.full(n, 1. / n), 'valid') | |
68 | p = other_plt.plot(ary[0][n - 1:], |
|
68 | p = other_plt.plot(ary[0][n - 1:], | |
69 | avg_n, |
|
69 | avg_n, | |
70 | color=color[0], |
|
70 | color=color[0], | |
71 | linewidth=1, |
|
71 | linewidth=1, | |
72 | label='avg time last %d' % n) |
|
72 | label='avg time last %d' % n) | |
73 | plots.append(p) |
|
73 | plots.append(p) | |
74 |
|
74 | |||
75 | med_n = scipy.signal.medfilt(ary[1], n + 1) |
|
75 | med_n = scipy.signal.medfilt(ary[1], n + 1) | |
76 | p = other_plt.plot(ary[0], |
|
76 | p = other_plt.plot(ary[0], | |
77 | med_n, |
|
77 | med_n, | |
78 | color=color[1], |
|
78 | color=color[1], | |
79 | linewidth=1, |
|
79 | linewidth=1, | |
80 | label='median time last %d' % n) |
|
80 | label='median time last %d' % n) | |
81 | plots.append(p) |
|
81 | plots.append(p) | |
82 |
|
82 | |||
83 | formatter = mticker.ScalarFormatter() |
|
83 | formatter = mticker.ScalarFormatter() | |
84 | formatter.set_scientific(False) |
|
84 | formatter.set_scientific(False) | |
85 | formatter.set_useOffset(False) |
|
85 | formatter.set_useOffset(False) | |
86 |
|
86 | |||
87 | comb_plt.grid() |
|
87 | comb_plt.grid() | |
88 | comb_plt.xaxis.set_major_formatter(formatter) |
|
88 | comb_plt.xaxis.set_major_formatter(formatter) | |
89 | comb_plt.legend() |
|
89 | comb_plt.legend() | |
90 |
|
90 | |||
91 | other_plt.grid() |
|
91 | other_plt.grid() | |
92 | other_plt.xaxis.set_major_formatter(formatter) |
|
92 | other_plt.xaxis.set_major_formatter(formatter) | |
93 | leg = other_plt.legend() |
|
93 | leg = other_plt.legend() | |
94 | leg2plot = {} |
|
94 | leg2plot = {} | |
95 | for legline, plot in zip(leg.get_lines(), plots): |
|
95 | for legline, plot in zip(leg.get_lines(), plots): | |
96 | legline.set_picker(5) |
|
96 | legline.set_picker(5) | |
97 | leg2plot[legline] = plot |
|
97 | leg2plot[legline] = plot | |
98 |
|
98 | |||
99 | def onpick(event): |
|
99 | def onpick(event): | |
100 | legline = event.artist |
|
100 | legline = event.artist | |
101 | plot = leg2plot[legline] |
|
101 | plot = leg2plot[legline] | |
102 | visible = not plot[0].get_visible() |
|
102 | visible = not plot[0].get_visible() | |
103 | for l in plot: |
|
103 | for l in plot: | |
104 | l.set_visible(visible) |
|
104 | l.set_visible(visible) | |
105 |
|
105 | |||
106 | if visible: |
|
106 | if visible: | |
107 | legline.set_alpha(1.0) |
|
107 | legline.set_alpha(1.0) | |
108 | else: |
|
108 | else: | |
109 | legline.set_alpha(0.2) |
|
109 | legline.set_alpha(0.2) | |
110 | fig.canvas.draw() |
|
110 | fig.canvas.draw() | |
|
111 | if title is not None: | |||
|
112 | fig.canvas.set_window_title(title) | |||
111 | fig.canvas.mpl_connect('pick_event', onpick) |
|
113 | fig.canvas.mpl_connect('pick_event', onpick) | |
112 |
|
114 | |||
113 | plt.show() |
|
115 | plt.show() | |
114 |
|
116 | |||
115 |
|
117 | |||
116 | if __name__ == '__main__': |
|
118 | if __name__ == '__main__': | |
117 | import sys |
|
119 | import sys | |
118 |
|
120 | |||
119 | if len(sys.argv) > 1: |
|
121 | if len(sys.argv) > 1: | |
120 | print('reading from %r' % sys.argv[1]) |
|
122 | print('reading from %r' % sys.argv[1]) | |
121 | with open(sys.argv[1], 'r') as fp: |
|
123 | with open(sys.argv[1], 'r') as fp: | |
122 | plot(json.load(fp)) |
|
124 | plot(json.load(fp), title=sys.argv[1]) | |
123 | else: |
|
125 | else: | |
124 | print('reading from stdin') |
|
126 | print('reading from stdin') | |
125 | plot(json.load(sys.stdin)) |
|
127 | plot(json.load(sys.stdin)) |
General Comments 0
You need to be logged in to leave comments.
Login now