Skip to content

Commit 208c2d6

Browse files
committed
Merge pull request #313 from pv/continuous-bug
Refactor asv continuous to use asv compare table printing
2 parents 8819998 + 33c86b0 commit 208c2d6

File tree

5 files changed

+130
-103
lines changed

5 files changed

+130
-103
lines changed

asv/commands/compare.py

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from __future__ import (absolute_import, division, print_function,
55
unicode_literals)
66

7+
import six
78
import itertools
89

910
from . import Command
@@ -116,24 +117,39 @@ def run(cls, conf, hash_1, hash_2, factor=2, split=False, machine=None):
116117
raise util.UserError(
117118
"Results for machine '{0} not found".format(machine))
118119

120+
cls.print_table(conf, hash_1, hash_2, factor=factor, machine=machine,
121+
split=split)
122+
123+
@classmethod
124+
def print_table(cls, conf, hash_1, hash_2, factor, split,
125+
resultset_1=None, resultset_2=None, machine=None,
126+
sort_by_ratio=False, only_changed=False):
119127
results_1 = {}
120128
results_2 = {}
121129

122-
for result in iter_results_for_machine_and_hash(
123-
conf.results_dir, machine, hash_1):
124-
for key in result.results:
125-
for name, value in unroll_result(key, result.results[key]):
126-
if name not in results_1:
127-
results_1[name] = []
128-
results_1[name].append(value)
129-
130-
for result in iter_results_for_machine_and_hash(
131-
conf.results_dir, machine, hash_2):
132-
for key in result.results:
133-
for name, value in unroll_result(key, result.results[key]):
134-
if name not in results_2:
135-
results_2[name] = []
136-
results_2[name].append(value)
130+
def results_default_iter(commit_hash):
131+
for result in iter_results_for_machine_and_hash(
132+
conf.results_dir, machine, commit_hash):
133+
for key, value in six.iteritems(result.results):
134+
yield key, value
135+
136+
if resultset_1 is None:
137+
resultset_1 = results_default_iter(hash_1)
138+
139+
if resultset_2 is None:
140+
resultset_2 = results_default_iter(hash_2)
141+
142+
for key, result in resultset_1:
143+
for name, value in unroll_result(key, result):
144+
if name not in results_1:
145+
results_1[name] = []
146+
results_1[name].append(value)
147+
148+
for key, result in resultset_2:
149+
for name, value in unroll_result(key, result):
150+
if name not in results_2:
151+
results_2[name] = []
152+
results_2[name].append(value)
137153

138154
if len(results_1) == 0:
139155
raise util.UserError(
@@ -146,7 +162,7 @@ def run(cls, conf, hash_1, hash_2, factor=2, split=False, machine=None):
146162
benchmarks_1 = set(results_1.keys())
147163
benchmarks_2 = set(results_2.keys())
148164

149-
common_benchmarks = sorted(list(benchmarks_1 & benchmarks_2))
165+
joint_benchmarks = sorted(list(benchmarks_1 | benchmarks_2))
150166

151167
bench = {}
152168

@@ -157,44 +173,74 @@ def run(cls, conf, hash_1, hash_2, factor=2, split=False, machine=None):
157173
else:
158174
bench['all'] = []
159175

160-
for benchmark in common_benchmarks:
176+
worsened = False
177+
improved = False
161178

162-
time_1 = mean(results_1[benchmark])
163-
time_2 = mean(results_2[benchmark])
179+
for benchmark in joint_benchmarks:
180+
if benchmark in results_1:
181+
time_1 = mean(results_1[benchmark])
182+
else:
183+
time_1 = float("nan")
184+
185+
if benchmark in results_2:
186+
time_2 = mean(results_2[benchmark])
187+
else:
188+
time_2 = float("nan")
164189

165190
if _isna(time_1) or _isna(time_2):
166191
ratio = 'n/a'
192+
ratio_num = 1e9
167193
else:
168-
ratio = "{0:6.2f}".format(time_2 / time_1)
169-
170-
if _isna(time_1) and _isna(time_2):
194+
try:
195+
ratio_num = time_2 / time_1
196+
ratio = "{0:6.2f}".format(ratio_num)
197+
except ZeroDivisionError:
198+
ratio_num = 1e9
199+
ratio = "n/a"
200+
201+
if time_1 is not None and time_2 is None:
202+
# introduced a failure
171203
color = 'red'
172-
mark = ' '
173-
elif _isna(time_1) and not _isna(time_2):
204+
mark = '!'
205+
worsened = True
206+
elif time_1 is None and time_2 is not None:
207+
# fixed a failure
174208
color = 'green'
175-
mark = '-'
176-
elif not _isna(time_1) and _isna(time_2):
209+
mark = ' '
210+
improved = True
211+
elif time_1 is None and time_2 is None:
212+
# both failed
177213
color = 'red'
178-
mark = '!'
214+
mark = ' '
215+
elif _isna(time_1) or _isna(time_2):
216+
# either one was skipped
217+
color = 'default'
218+
mark = ' '
179219
elif time_2 < time_1 / factor:
180220
color = 'green'
181221
mark = '-'
222+
improved = True
182223
elif time_2 > time_1 * factor:
183224
color = 'red'
184225
mark = '+'
226+
worsened = True
185227
else:
186228
color = 'default'
187229
mark = ' '
230+
231+
if only_changed and mark == ' ':
232+
continue
233+
188234
details = "{0:1s} {1:>9s} {2:>9s} {3:>9s} ".format(
189235
mark,
190236
human_value(time_1, "seconds"),
191237
human_value(time_2, "seconds"),
192238
ratio)
193239

194240
if split:
195-
bench[color].append((color, details, benchmark))
241+
bench[color].append((color, details, benchmark, ratio_num))
196242
else:
197-
bench['all'].append((color, details, benchmark))
243+
bench['all'].append((color, details, benchmark, ratio_num))
198244

199245
if split:
200246
keys = ['green', 'default', 'red']
@@ -212,12 +258,18 @@ def run(cls, conf, hash_1, hash_2, factor=2, split=False, machine=None):
212258
if len(bench[key]) == 0:
213259
continue
214260

215-
print("")
216-
print(titles[key])
217-
print("")
261+
if not only_changed:
262+
print("")
263+
print(titles[key])
264+
print("")
218265
print(" before after ratio")
219266
print(" [{0:8s}] [{1:8s}]".format(hash_1[:8], hash_2[:8]))
220267

221-
for color, details, benchmark in bench[key]:
268+
if sort_by_ratio:
269+
bench[key].sort(key=lambda v: v[3], reverse=True)
270+
271+
for color, details, benchmark, ratio in bench[key]:
222272
color_print(details, color, end='')
223273
print(benchmark)
274+
275+
return worsened, improved

asv/commands/continuous.py

Lines changed: 19 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,15 @@
55
unicode_literals)
66

77
import os
8-
98
import six
109

1110
from . import Command
1211
from .run import Run
13-
from .compare import unroll_result
12+
from .compare import Compare
1413

15-
from ..console import truncate_left, color_print
1614
from ..repo import get_repo
15+
from ..console import color_print
1716
from .. import results
18-
from .. import util
1917

2018
from . import common_args
2119

@@ -75,73 +73,27 @@ def run(cls, conf, branch=None, base=None, factor=2.0, show_stderr=False, bench=
7573
if result:
7674
return result
7775

78-
tabulated = []
79-
all_benchmarks = {}
80-
for commit_hash in commit_hashes:
81-
subtab = {}
82-
totals = {}
83-
76+
def results_iter(commit_hash):
8477
for env in run_objs['environments']:
8578
filename = results.get_filename(
8679
run_objs['machine_params']['machine'], commit_hash, env.name)
8780
filename = os.path.join(conf.results_dir, filename)
8881
result = results.Results.load(filename)
89-
90-
for benchmark_name, benchmark in six.iteritems(run_objs['benchmarks']):
91-
for name, value in unroll_result(benchmark_name,
92-
result.results.get(benchmark_name, None)):
93-
if value is not None:
94-
all_benchmarks[name] = benchmark
95-
subtab.setdefault(name, 0.0)
96-
totals.setdefault(name, 0)
97-
subtab[name] += value
98-
totals[name] += 1
99-
100-
for name in totals.keys():
101-
subtab[name] /= totals[name]
102-
103-
tabulated.append(subtab)
104-
105-
after, before = tabulated
106-
107-
table = []
108-
slowed_down = False
109-
for name, benchmark in six.iteritems(all_benchmarks):
110-
if before[name] == 0:
111-
if after[name] == 0:
112-
change = 1.0
113-
else:
114-
change = float('inf')
115-
else:
116-
change = after[name] / before[name]
117-
118-
if change > factor or change < 1.0 / factor:
119-
table.append(
120-
(change, before[name], after[name], name, benchmark))
121-
if change > factor:
122-
slowed_down = True
123-
124-
print("")
125-
126-
if not len(table):
82+
for name, benchmark in six.iteritems(run_objs['benchmarks']):
83+
yield name, result.results.get(name, float("nan"))
84+
85+
status = Compare.print_table(conf, parent, head,
86+
resultset_1=results_iter(parent),
87+
resultset_2=results_iter(head),
88+
factor=factor, split=False, only_changed=True,
89+
sort_by_ratio=True)
90+
worsened, improved = status
91+
92+
if worsened:
93+
color_print("SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.\n", 'red')
94+
elif improved:
95+
color_print("SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.\n", 'green')
96+
else:
12797
color_print("BENCHMARKS NOT SIGNIFICANTLY CHANGED.\n", 'green')
128-
return 0
129-
130-
table.sort(reverse=True)
131-
132-
color_print(
133-
"{0:40s} {1:>8} {2:>8} {3:>8}\n".format("BENCHMARK", "BEFORE", "AFTER", "FACTOR"),
134-
'blue')
135-
for change, before, after, name, benchmark in table:
136-
before_display = util.human_value(before, benchmark['unit'])
137-
after_display = util.human_value(after, benchmark['unit'])
138-
139-
print("{0:40s} {1:>8} {2:>8} {3:.8f}x".format(
140-
truncate_left(name, 40),
141-
before_display, after_display, change))
142-
143-
print("")
144-
color_print(
145-
"SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY.\n", 'red')
14698

147-
return slowed_down
99+
return worsened

test/example_results/cheetah/fcf8c079-py2.7-Cython-numpy1.8.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"time_units.time_simple_unit_parse": 0.003806138038635254,
3030
"time_units.time_unit_compose": 0.0015271089076995849,
3131
"time_units.time_unit_parse": 0.011466357707977295,
32-
"time_units.time_unit_to": 4.8321509361267087e-05,
32+
"time_units.time_unit_to": 1.8321509361267087e-05,
3333
"time_units.time_very_simple_unit_parse": 1.3104991912841798e-05,
3434
"time_other.time_parameterized": {
3535
"params": [["1", "2", "3"]],

test/test_compare.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
2626
before after ratio
2727
[22b920c6] [fcf8c079]
28+
! n/a failed n/a params_examples.ParamSuite.track_value
2829
failed failed n/a time_AAA_failure
2930
n/a n/a n/a time_AAA_skip
3031
! 454.03μs failed n/a time_coordinates.time_latitude
@@ -40,10 +41,23 @@
4041
+ 125.11μs 3.81ms 30.42 time_units.time_simple_unit_parse
4142
1.64ms 1.53ms 0.93 time_units.time_unit_compose
4243
+ 372.11μs 11.47ms 30.81 time_units.time_unit_parse
43-
69.09μs 48.32μs 0.70 time_units.time_unit_to
44+
- 69.09μs 18.32μs 0.27 time_units.time_unit_to
4445
11.87μs 13.10μs 1.10 time_units.time_very_simple_unit_parse
4546
"""
4647

48+
REFERENCE_ONLY_CHANGED = """
49+
before after ratio
50+
[22b920c6] [fcf8c079]
51+
! n/a failed n/a params_examples.ParamSuite.track_value
52+
! 454.03μs failed n/a time_coordinates.time_latitude
53+
! 3.00s failed n/a time_other.time_parameterized(3)
54+
+ 933.71μs 108.22ms 115.90 time_quantity.time_quantity_init_array
55+
+ 1.75ms 152.84ms 87.28 time_quantity.time_quantity_array_conversion
56+
+ 372.11μs 11.47ms 30.81 time_units.time_unit_parse
57+
+ 125.11μs 3.81ms 30.42 time_units.time_simple_unit_parse
58+
+ 1.31ms 7.75ms 5.91 time_quantity.time_quantity_ufunc_sin
59+
- 69.09μs 18.32μs 0.27 time_units.time_unit_to
60+
"""
4761

4862
def test_compare(capsys, tmpdir):
4963
tmpdir = six.text_type(tmpdir)
@@ -60,3 +74,12 @@ def test_compare(capsys, tmpdir):
6074

6175
text, err = capsys.readouterr()
6276
assert text.strip() == REFERENCE.strip()
77+
78+
# Check print_table output as called from Continuous
79+
status = Compare.print_table(conf, '22b920c6', 'fcf8c079', factor=2, machine='cheetah',
80+
split=False, only_changed=True, sort_by_ratio=True)
81+
worsened, improved = status
82+
assert worsened
83+
assert improved
84+
text, err = capsys.readouterr()
85+
assert text.strip() == REFERENCE_ONLY_CHANGED.strip()

test/test_workflow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def test_continuous(capfd, basic_conf):
141141

142142
text, err = capfd.readouterr()
143143
assert "SOME BENCHMARKS HAVE CHANGED SIGNIFICANTLY" in text
144-
assert "params_examples.track_find_test(2) 1.0 6.0 6.00000000x" in text
144+
assert "+ 1.00s 6.00s 6.00 params_examples.track_find_test(2)" in text
145145
assert "params_examples.ClassOne" in text
146146

147147

0 commit comments

Comments
 (0)