|
1 #!/usr/bin/env python2.4 |
|
2 """usage: %progname candidate_path baseline_path |
|
3 """ |
|
4 |
|
5 import json |
|
6 import optparse |
|
7 from contextlib import nested |
|
8 from operator import itemgetter |
|
9 |
|
10 |
|
11 def avg(seq): |
|
12 return sum(seq) / len(seq) |
|
13 |
|
14 |
|
15 def compare(current, baseline): |
|
16 percent_speedups = [] |
|
17 for key, current_result in current.iteritems(): |
|
18 try: |
|
19 baseline_result = baseline[key] |
|
20 except KeyError: |
|
21 print key, 'missing from baseline' |
|
22 continue |
|
23 val_getter = itemgetter('average_ms', 'stddev_ms') |
|
24 base_avg, base_stddev = val_getter(baseline_result) |
|
25 current_avg, current_stddev = val_getter(current_result) |
|
26 t_best, t_worst = current_avg - current_stddev, current_avg + current_stddev |
|
27 base_t_best, base_t_worst = base_avg - base_stddev, base_avg + base_stddev |
|
28 fmt = '%30s: %s' |
|
29 if t_worst < base_t_best: # Worst takes less time (better) than baseline's best. |
|
30 speedup = -((t_worst - base_t_best) / base_t_best) * 100 |
|
31 result = 'faster: %6.2fms < baseline %6.2fms (%+6.2f%%)' % \ |
|
32 (t_worst, base_t_best, speedup) |
|
33 percent_speedups.append(speedup) |
|
34 elif t_best > base_t_worst: # Best takes more time (worse) than baseline's worst. |
|
35 slowdown = -((t_best - base_t_worst) / base_t_worst) * 100 |
|
36 result = 'SLOWER: %6.2fms > baseline %6.2fms (%+6.2f%%) ' % \ |
|
37 (t_best, base_t_worst, slowdown) |
|
38 percent_speedups.append(slowdown) |
|
39 else: |
|
40 result = 'Meh.' |
|
41 print '%30s: %s' % (key, result) |
|
42 if percent_speedups: |
|
43 print 'Average speedup: %.2f%%' % avg(percent_speedups) |
|
44 |
|
45 |
|
46 def compare_immediate(current_map, baseline_path): |
|
47 baseline_file = open(baseline_path) |
|
48 baseline_map = json.load(baseline_file) |
|
49 baseline_file.close() |
|
50 compare(current_map, baseline_map) |
|
51 |
|
52 |
|
53 def main(candidate_path, baseline_path): |
|
54 candidate_file, baseline_file = open(candidate_path), open(baseline_path) |
|
55 candidate = json.load(candidate_file) |
|
56 baseline = json.load(baseline_file) |
|
57 compare(candidate, baseline) |
|
58 candidate_file.close() |
|
59 baseline_file.close() |
|
60 |
|
61 |
|
62 if __name__ == '__main__': |
|
63 parser = optparse.OptionParser(usage=__doc__.strip()) |
|
64 options, args = parser.parse_args() |
|
65 try: |
|
66 candidate_path = args.pop(0) |
|
67 except IndexError: |
|
68 parser.error('A JSON filepath to compare against baseline is required') |
|
69 try: |
|
70 baseline_path = args.pop(0) |
|
71 except IndexError: |
|
72 parser.error('A JSON filepath for baseline is required') |
|
73 main(candidate_path, baseline_path) |