Skip to content

Commit e09993b

Browse files
authored
Don't crash when benchmark contains unknown metric (rust-lang#2985)
Previously, the code assumed that all metrics of the benchmark results would be 'declared' in the "metrics" key of the parser output. This commit ensures that if a parser emits a benchmark containing a metric that hasn't been declared in the "metrics" key, that result is ignored and benchcomp does not crash.
1 parent 769561c commit e09993b

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

tools/benchcomp/benchcomp/visualizers/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import json
77
import logging
88
import subprocess
9+
import sys
910
import textwrap
1011

1112
import jinja2
@@ -232,12 +233,19 @@ def _organize_results_into_metrics(results):
232233
for bench, bench_result in results["benchmarks"].items():
233234
for variant, variant_result in bench_result["variants"].items():
234235
for metric, value in variant_result["metrics"].items():
236+
if metric not in ret:
237+
ret[metric] = {}
238+
logging.warning(
239+
"Benchmark '%s' contained a metric '%s' in the "
240+
"'%s' variant result that was not declared in "
241+
"the 'metrics' dict. Add '%s: {}' to the metrics "
242+
"dict", bench, metric, variant, metric)
235243
try:
236244
ret[metric][bench][variant] = variant_result["metrics"][metric]
237245
except KeyError:
238246
ret[metric][bench] = {
239247
variant: variant_result["metrics"][metric]
240-
}
248+
}
241249
return ret
242250

243251

tools/benchcomp/test/test_regression.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# tests.
77

88
import pathlib
9+
import re
910
import subprocess
1011
import tempfile
1112
import textwrap
@@ -834,3 +835,70 @@ def test_run_failing_command_visualization(self):
834835
run_bc()
835836
self.assertNotEqual(
836837
run_bc.proc.returncode, 0, msg=run_bc.stderr)
838+
839+
840+
def test_unknown_metric_in_benchmark(self):
841+
"""Ensure that benchcomp continues with warning if a benchmark result contained an unknown metric"""
842+
843+
with tempfile.TemporaryDirectory() as tmp:
844+
out_file = pathlib.Path(tmp) / str(uuid.uuid4())
845+
run_bc = Benchcomp({
846+
"variants": {
847+
"v1": {
848+
"config": {
849+
"command_line": "true",
850+
"directory": tmp,
851+
}
852+
},
853+
"v2": {
854+
"config": {
855+
"command_line": "true",
856+
"directory": tmp,
857+
}
858+
}
859+
},
860+
"run": {
861+
"suites": {
862+
"suite_1": {
863+
"parser": {
864+
"command": """
865+
echo '{
866+
metrics: {
867+
foo: {},
868+
bar: {},
869+
},
870+
benchmarks: {
871+
bench_1: {
872+
metrics: {
873+
baz: 11
874+
}
875+
}
876+
}
877+
}'
878+
"""
879+
},
880+
"variants": ["v2", "v1"]
881+
}
882+
}
883+
},
884+
"visualize": [{
885+
"type": "dump_markdown_results_table",
886+
"out_file": "-",
887+
"extra_columns": {},
888+
}],
889+
})
890+
891+
output_pat = re.compile(
892+
"Benchmark 'bench_1' contained a metric 'baz' in the 'v1' "
893+
"variant result that was not declared in the 'metrics' dict.")
894+
895+
run_bc()
896+
self.assertRegex(run_bc.stderr, output_pat)
897+
898+
self.assertEqual(run_bc.proc.returncode, 0, msg=run_bc.stderr)
899+
900+
with open(run_bc.working_directory / "result.yaml") as handle:
901+
result = yaml.safe_load(handle)
902+
903+
for item in ["benchmarks", "metrics"]:
904+
self.assertIn(item, result)

0 commit comments

Comments
 (0)