Skip to content

Commit 8d55244

Browse files
authored
Add --only and --exclude to benchcomp visualize (#2409)
These flags allow users to select which visualizations to run---a subset of those in the configuration file. Typically this would be used when the `error_on_regression` is used in CI, or any other visualization that terminates benchcomp with a non-zero return code. The idea is that users can first run all visualizations, except for ones that cause benchcomp to terminate, using `--except error_on_regression`. Users can then save any output files from visualizations, before running `benchcomp visualize --only error_on_regression`.
1 parent d654849 commit 8d55244

File tree

4 files changed

+130
-3
lines changed

4 files changed

+130
-3
lines changed

tools/benchcomp/benchcomp/cmd_args.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ def _get_args_dict():
174174
"type": pathlib.Path,
175175
"help":
176176
"read result from F instead of %(default)s. "
177+
}, {
178+
"flags": ["--only"],
179+
"nargs": "+",
180+
"metavar": "V",
181+
"help":
182+
"Only run visualization V; ignore others in "
183+
"config file"
184+
}, {
185+
"flags": ["--except"],
186+
"dest": "except_for",
187+
"nargs": "+",
188+
"metavar": "V",
189+
"help": "Run all visualizations except V",
177190
}],
178191
},
179192
}

tools/benchcomp/benchcomp/entry/visualize.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def main(args):
1414
with open(args.result_file, encoding="utf-8") as handle:
1515
results = yaml.safe_load(handle)
1616

17-
generate_visualizations = benchcomp.visualizers.utils.Generator(args.config)
17+
generate_visualizations = benchcomp.visualizers.utils.Generator(
18+
args.config, args.except_for, args.only)
1819
generate_visualizations(results)
1920
sys.exit(benchcomp.visualizers.utils.EXIT_CODE)

tools/benchcomp/benchcomp/visualizers/utils.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,26 @@ class Generator:
9696
"""Generate all visualizations in a config file given a dict of results"""
9797

9898
config: benchcomp.ConfigFile
99+
except_for: list
100+
only: list
99101

100102

101103
def __call__(self, results):
102-
for viz in self.config["visualize"]:
104+
visualizations = self.config["visualize"]
105+
106+
if self.except_for:
107+
for viz_name in self.except_for:
108+
vizs = [v for v in visualizations if v["type"] == viz_name]
109+
for viz in vizs:
110+
visualizations.remove(viz)
111+
if self.only:
112+
for viz_name in [v["type"] for v in visualizations]:
113+
if viz_name not in self.only:
114+
vizs = [v for v in visualizations if v["type"] == viz_name]
115+
for viz in vizs:
116+
visualizations.remove(viz)
117+
118+
for viz in visualizations:
103119
viz_type = viz.pop("type")
104120
klass = getattr(benchcomp.visualizers, viz_type)
105121
visualize = klass(**viz)

tools/benchcomp/test/test_regression.py

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ def __init__(self, config):
3030
wd = tempfile.mkdtemp()
3131
self.working_directory = pathlib.Path(wd)
3232

33-
def __call__(self, subcommand=None, default_flags=None, *flags):
33+
def __call__(self, subcommand=None, default_flags=None, flags=None):
3434
subcommand = subcommand or []
3535
default_flags = default_flags or [
3636
"--out-prefix", "/tmp/benchcomp/test"]
3737
config_flags = ["--config", str(self.config_file)]
3838

39+
flags = flags or []
40+
3941
cmd = [self.bc, *config_flags, *subcommand, *default_flags, *flags]
4042
self.proc = subprocess.Popen(
4143
cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
@@ -386,6 +388,99 @@ def test_error_on_regression_visualization_ratio_regressed(self):
386388
run_bc.proc.returncode, 1, msg=run_bc.stderr)
387389

388390

391+
def test_only_dump_yaml(self):
392+
"""Ensure that benchcomp terminates with return code 0 when `--only dump_yaml` is passed, even if the error_on_regression visualization would have resulted in a return code of 1"""
393+
394+
with tempfile.TemporaryDirectory() as tmp:
395+
run_bc = Benchcomp({
396+
"variants": {
397+
"passed": {
398+
"config": {
399+
"directory": str(tmp),
400+
"command_line":
401+
"mkdir bench_1 bench_2 && "
402+
"echo true > bench_1/success &&"
403+
"echo true > bench_2/success"
404+
},
405+
},
406+
"failed": {
407+
"config": {
408+
"directory": str(tmp),
409+
"command_line":
410+
"mkdir bench_1 bench_2 && "
411+
"echo true > bench_1/success &&"
412+
"echo false > bench_2/success"
413+
}
414+
}
415+
},
416+
"run": {
417+
"suites": {
418+
"suite_1": {
419+
"parser": { "module": "test_file_to_metric" },
420+
"variants": ["passed", "failed"]
421+
}
422+
}
423+
},
424+
"visualize": [{
425+
"type": "dump_yaml",
426+
}, {
427+
"type": "error_on_regression",
428+
"variant_pairs": [["passed", "failed"]],
429+
"checks": [{
430+
"metric": "success",
431+
"test":
432+
"lambda old, new: True"
433+
}]
434+
}]
435+
})
436+
run_bc(flags=["--only", "dump_yaml"])
437+
438+
self.assertEqual(
439+
run_bc.proc.returncode, 0, msg=run_bc.stderr)
440+
441+
with open(run_bc.working_directory / "result.yaml") as handle:
442+
result = yaml.safe_load(handle)
443+
444+
445+
def test_ignore_dump_yaml(self):
446+
"""Ensure that benchcomp does not print any YAML output even with the dump_yaml visualization when the `--except dump_yaml` flag is passed"""
447+
448+
with tempfile.TemporaryDirectory() as tmp:
449+
run_bc = Benchcomp({
450+
"variants": {
451+
"variant_1": {
452+
"config": {
453+
"directory": tmp,
454+
"command_line": "true",
455+
}
456+
},
457+
"variant_2": {
458+
"config": {
459+
"directory": tmp,
460+
"command_line": "true",
461+
}
462+
}
463+
},
464+
"run": {
465+
"suites": {
466+
"suite_1": {
467+
"parser": {"module": "test"},
468+
"variants": ["variant_1", "variant_2"]
469+
}
470+
}
471+
},
472+
"visualize": [{
473+
"type": "dump_yaml",
474+
}],
475+
})
476+
run_bc(flags=["--except", "dump_yaml"])
477+
478+
self.assertEqual(
479+
run_bc.stdout, "", msg=run_bc.stdout)
480+
481+
with open(run_bc.working_directory / "result.yaml") as handle:
482+
result = yaml.safe_load(handle)
483+
389484

390485
def test_return_0(self):
391486
"""Ensure that benchcomp terminates with return code 0"""
@@ -423,6 +518,7 @@ def test_return_0(self):
423518
with open(run_bc.working_directory / "result.yaml") as handle:
424519
result = yaml.safe_load(handle)
425520

521+
426522
def test_return_0_on_fail(self):
427523
"""Ensure that benchcomp terminates with 0 even if a suite fails"""
428524

@@ -459,6 +555,7 @@ def test_return_0_on_fail(self):
459555
with open(run_bc.working_directory / "result.yaml") as handle:
460556
result = yaml.safe_load(handle)
461557

558+
462559
def test_env(self):
463560
"""Ensure that benchcomp reads the 'env' key of variant config"""
464561

0 commit comments

Comments
 (0)