16 """ Computes the diff between two bm runs and outputs significant results """
25 sys.path.append(os.path.join(os.path.dirname(sys.argv[0]),
'..'))
40 return (ary[(n - 1) // 2] + ary[(n - 1) // 2 + 1]) / 2.0
46 argp = argparse.ArgumentParser(
47 description=
'Perform diff on microbenchmarks')
48 argp.add_argument(
'-t',
50 choices=sorted(bm_constants._INTERESTING),
52 default=sorted(bm_constants._INTERESTING),
53 help=
'Which metrics to track')
54 argp.add_argument(
'-b',
57 choices=bm_constants._AVAILABLE_BENCHMARK_TESTS,
58 default=bm_constants._AVAILABLE_BENCHMARK_TESTS,
59 help=
'Which benchmarks to run')
66 'Number of times to loops the benchmarks. Must match what was passed to bm_run.py'
68 argp.add_argument(
'-r',
72 help=
'Regex to filter benchmarks run')
73 argp.add_argument(
'--counters', dest=
'counters', action=
'store_true')
74 argp.add_argument(
'--no-counters', dest=
'counters', action=
'store_false')
75 argp.set_defaults(counters=
True)
76 argp.add_argument(
'-n',
'--new', type=str, help=
'New benchmark name')
77 argp.add_argument(
'-o',
'--old', type=str, help=
'Old benchmark name')
78 argp.add_argument(
'-v',
81 help=
'Print details of before/after')
82 args = argp.parse_args()
100 True: collections.defaultdict(list),
101 False: collections.defaultdict(list)
109 self.
samples[new][f].append(float(data[f]))
112 for f
in sorted(track):
115 if not new
or not old:
119 (f, new_name, new, old_name, old, mdn_diff))
124 self.
final[f] =
'%+d%%' % s
128 return not self.
final
131 return [self.
final[f]
if f
in self.
final else '' for f
in flds]
140 stripped =
".".join(filename.split(
".")[:-2])
142 with open(filename)
as f:
146 if stripped
in nonexistant_files:
147 nonexistant_files[stripped] += 1
149 nonexistant_files[stripped] = 1
151 except ValueError
as e:
153 if stripped
in badjson_files:
154 badjson_files[stripped] += 1
156 badjson_files[stripped] = 1
161 return ''.join([
" " + k +
": " +
str(d[k]) +
"\n" for k
in d])
164 def diff(bms, loops, regex, track, old, new, counters):
165 benchmarks = collections.defaultdict(Benchmark)
168 nonexistant_files = {}
170 for loop
in range(0, loops):
171 for line
in subprocess.check_output([
172 'bm_diff_%s/opt/%s' % (old, bm),
'--benchmark_list_tests',
173 '--benchmark_filter=%s' % regex
175 line = line.decode(
'UTF-8')
176 stripped_line = line.strip().replace(
"/",
"_").replace(
177 "<",
"_").replace(
">",
"_").replace(
", ",
"_")
179 '%s.%s.opt.%s.%d.json' % (bm, stripped_line, new, loop),
180 badjson_files, nonexistant_files)
182 '%s.%s.opt.%s.%d.json' % (bm, stripped_line, old, loop),
183 badjson_files, nonexistant_files)
186 '%s.%s.counters.%s.%d.json' %
187 (bm, stripped_line, new, loop), badjson_files,
190 '%s.%s.counters.%s.%d.json' %
191 (bm, stripped_line, old, loop), badjson_files,
198 name = row[
'cpp_name']
199 if name.endswith(
'_mean')
or name.endswith(
'_stddev'):
201 benchmarks[name].add_sample(track, row,
True)
203 name = row[
'cpp_name']
204 if name.endswith(
'_mean')
or name.endswith(
'_stddev'):
206 benchmarks[name].add_sample(track, row,
False)
208 really_interesting =
set()
209 for name, bm
in benchmarks.items():
211 really_interesting.update(bm.process(track, new, old))
212 fields = [f
for f
in track
if f
in really_interesting]
217 _NOISY = [
"BM_WellFlushed"]
218 for name, bm
in benchmarks.items():
220 print(
"skipping noisy benchmark '%s' for labelling evaluation" %
224 d = bm.speedup[
'cpu_time']
229 print(
"histogram of speedups: ", histogram)
230 if len(histogram) == 0:
233 delta = histogram[
int(
len(histogram) * 0.95)]
248 headers = [
'Benchmark'] + fields
250 for name
in sorted(benchmarks.keys()):
251 if benchmarks[name].
skip():
253 rows.append([name] + benchmarks[name].row(fields))
255 if len(badjson_files):
256 note =
'Corrupt JSON data (indicates timeout or crash): \n%s' %
fmt_dict(
258 if len(nonexistant_files):
260 note +=
'\n\nMissing files (indicates new benchmark): \n%s' %
fmt_dict(
263 note =
'\n\nMissing files (indicates new benchmark): \n%s' %
fmt_dict(
266 return tabulate.tabulate(rows, headers=headers,
267 floatfmt=
'+.2f'), note, significance
272 if __name__ ==
'__main__':
274 diff, note =
diff(args.benchmarks, args.loops, args.regex, args.track,
275 args.old, args.new, args.counters)
276 print(
'%s\n%s' % (note, diff
if diff
else "No performance differences"))