Skip to content

Commit c424468

Browse files
authored
[libc++] Parse Google Benchmark results into LNT-compatible format (#157466)
This is a step towards being able to easily report benchmark results to a LNT instance. The LNT format can also be the basis for other tools to perform A/B comparisons when doing experiments.
1 parent 1f39435 commit c424468

File tree

4 files changed

+51
-2
lines changed

4 files changed

+51
-2
lines changed

libcxx/test/benchmarks/spec.gen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,5 @@
7474

7575
# Parse the results into a LNT-compatible format. This also errors out if there are no CSV files, which
7676
# means that the benchmark didn't run properly (the `runcpu` command above never reports a failure).
77-
print(f'RUN: %{{libcxx-dir}}/utils/parse-spec-result %T/result/CPUv8.001.*.train.csv --output-format=lnt > %T/results.lnt')
77+
print(f'RUN: %{{libcxx-dir}}/utils/parse-spec-results %T/result/CPUv8.001.*.train.csv --output-format=lnt > %T/results.lnt')
7878
print(f'RUN: cat %T/results.lnt')

libcxx/utils/libcxx/test/format.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import os
1313
import re
1414

15+
THIS_FILE = os.path.abspath(__file__)
16+
LIBCXX_UTILS = os.path.dirname(os.path.dirname(os.path.dirname(THIS_FILE)))
1517

1618
def _getTempPaths(test):
1719
"""
@@ -353,6 +355,8 @@ def execute(self, test, litConfig):
353355
]
354356
if "enable-benchmarks=run" in test.config.available_features:
355357
steps += ["%dbg(EXECUTED AS) %{exec} %t.exe --benchmark_out=%T/benchmark-result.json --benchmark_out_format=json"]
358+
parse_results = os.path.join(LIBCXX_UTILS, 'parse-google-benchmark-results')
359+
steps += [f"{parse_results} %T/benchmark-result.json --output-format=lnt > %T/results.lnt"]
356360
return self._executeShTest(test, litConfig, steps)
357361
elif re.search('[.]gen[.][^.]+$', filename): # This only happens when a generator test is not supported
358362
return self._executeShTest(test, litConfig, [])
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import csv
5+
import json
6+
import sys
7+
8+
def main(argv):
9+
parser = argparse.ArgumentParser(
10+
prog='parse-google-benchmark-results',
11+
description='Parse Google Benchmark result files (in JSON format) into CSV or LNT compatible output.')
12+
parser.add_argument('filename', type=argparse.FileType('r'), nargs='+',
13+
help='One of more JSON files to extract the results from. The results parsed from each '
14+
'file are concatenated together.')
15+
parser.add_argument('--timing', type=str, choices=['real_time', 'cpu_time'], default='real_time',
16+
help='The timing to extract from the Google Benchmark results. This can either be the '
17+
'"real time" or the "CPU time". Default is "real time".')
18+
parser.add_argument('--output-format', type=str, choices=['csv', 'lnt'], default='csv',
19+
help='The desired output format for the data. `csv` is CSV format and `lnt` is a format compatible with '
20+
'`lnt importreport` (see https://llvm.org/docs/lnt/importing_data.html#importing-data-in-a-text-file).')
21+
args = parser.parse_args(argv)
22+
23+
# Parse the data from all files, aggregating the results
24+
headers = ['Benchmark', args.timing]
25+
rows = []
26+
for file in args.filename:
27+
js = json.load(file)
28+
for bm in js['benchmarks']:
29+
row = [bm['name'], bm[args.timing]]
30+
rows.append(row)
31+
32+
# Print the results in the right format
33+
if args.output_format == 'csv':
34+
writer = csv.writer(sys.stdout)
35+
writer.writerow(headers)
36+
for row in rows:
37+
writer.writerow(row)
38+
elif args.output_format == 'lnt':
39+
benchmark = headers.index('Benchmark')
40+
time = headers.index(args.timing)
41+
for row in rows:
42+
print(f'{row[benchmark].replace(".", "_")}.execution_time {row[time]}')
43+
44+
if __name__ == '__main__':
45+
main(sys.argv[1:])

libcxx/utils/parse-spec-result renamed to libcxx/utils/parse-spec-results

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def main(argv):
4545
description='Parse SPEC result files (in CSV format) and extract the selected result table, in the selected format.')
4646
parser.add_argument('filename', type=argparse.FileType('r'), nargs='+',
4747
help='One of more CSV files to extract the results from. The results parsed from each file are concatenated '
48-
'together, creating a single CSV table.')
48+
'together.')
4949
parser.add_argument('--table', type=str, choices=['full', 'selected'], default='full',
5050
help='The name of the table to extract from SPEC results. `full` means extracting the Full Results Table '
5151
'and `selected` means extracting the Selected Results Table. Default is `full`.')

0 commit comments

Comments
 (0)