diff --git a/enable/gcbench/bench.py b/enable/gcbench/bench.py index b87d38374..1083f7eca 100644 --- a/enable/gcbench/bench.py +++ b/enable/gcbench/bench.py @@ -26,7 +26,7 @@ "quartz": "enable.null.quartz", }, "file": { - "pdf": "enable.null.pdf", + "pdf": "enable.gcbench.pdf", "ps": "enable.null.ps", "svg": "enable.null.svg", }, @@ -38,16 +38,26 @@ def benchmark(outdir=None): """ suite = gen_suite() - results = {} - # NOTE: Only checking UI backends for now - for name, mod_name in _BACKENDS["ui"].items(): - print(f"Benchmarking backend: {name}", end="") - try: - module = importlib.import_module(mod_name) - except ImportError: - print(" ... Not available") - continue - results[name] = benchmark_backend(suite, name, module, outdir=outdir) + results = {t: {} for t in _BACKENDS} + for btype, backends in _BACKENDS.items(): + for name, mod_name in backends.items(): + print(f"Benchmarking backend: {name}", end="") + try: + module = importlib.import_module(mod_name) + except ImportError: + print(" ... Not available") + continue + + # UI backends are checked for performance, File backends are not. + if btype == "ui": + results[btype][name] = benchmark_backend( + suite, name, module, outdir=outdir + ) + else: + # XXX: Use the fact that `name` is the same as the file ext. + results[btype][name] = exercise_backend( + suite, name, module, extension=name, outdir=outdir + ) return results @@ -58,7 +68,7 @@ def benchmark_backend(suite, mod_name, module, outdir=None): GraphicsContext = getattr(module, "GraphicsContext") gc = GraphicsContext(_SIZE) - timings = {} + results = {} for name, symbol in suite.items(): print(f"\n\tBenchmark {name}", end="") try: @@ -70,20 +80,63 @@ def benchmark_backend(suite, mod_name, module, outdir=None): # Double sized with gc: gc.scale_ctm(2, 2) - timings[name] = gen_timings(gc, instance) + stats = gen_timings(gc, instance) else: # Normal scale - timings[name] = gen_timings(gc, instance) + stats = gen_timings(gc, instance) - if timings[name] is None: + if stats is None: print(f" ... Failed", end="") + results[name] = None + continue - if timings[name] is not None and outdir is not None: + results[name] = {"times": stats} + if outdir is not None: fname = os.path.join(outdir, f"{mod_name}.{name}.png") gc.save(fname) + results[name]["format"] = "png" + results[name]["filename"] = os.path.basename(fname) print() # End the line that was left - return timings + return results + + +def exercise_backend(suite, mod_name, module, extension, outdir=None): + """ Exercise a single backend + """ + GraphicsContext = getattr(module, "GraphicsContext") + + results = {name: None for name in suite} + for name, symbol in suite.items(): + # Skip 2x versions + if name.endswith("2x"): + results[name] = {"skip": True} + continue + + # Use a fresh context each time + gc = GraphicsContext(_SIZE) + + print(f"\n\tBenchmark {name}", end="") + try: + instance = symbol(gc, module) + except Exception: + continue + + try: + instance() + except Exception: + print(f" ... Failed", end="") + continue + + results[name] = {"times": {}} + if outdir is not None: + fname = os.path.join(outdir, f"{mod_name}.{name}.{extension}") + gc.save(fname) + results[name]["format"] = extension + results[name]["filename"] = os.path.basename(fname) + + print() # End the line that was left + return results def gen_suite(): diff --git a/enable/gcbench/pdf.py b/enable/gcbench/pdf.py new file mode 100644 index 000000000..dc46af88b --- /dev/null +++ b/enable/gcbench/pdf.py @@ -0,0 +1,30 @@ +# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX +# All rights reserved. +# +# This software is provided without warranty under the terms of the BSD +# license included in LICENSE.txt and may be redistributed only under +# the conditions described in the aforementioned license. The license +# is also available online at http://www.enthought.com/licenses/BSD.txt +# +# Thanks for using Enthought open source! +from reportlab.lib.pagesizes import letter +from reportlab.pdfgen.canvas import Canvas + +import kiva.pdf as pdf_backend + +# Pass it along +CompiledPath = pdf_backend.CompiledPath + + +class GraphicsContext(pdf_backend.GraphicsContext): + """ This is a wrapper of the PDF GraphicsContext which works with the + benchmark program. + """ + def __init__(self, size, *args, **kw): + canvas = Canvas('', pagesize=letter) + super().__init__(canvas, *args, **kw) + + def save(self, filename, *args, **kw): + # Reportlab is a bit silly + self.gc._filename = filename + super().save() diff --git a/enable/gcbench/publish.py b/enable/gcbench/publish.py index bad6ed95d..4163489de 100644 --- a/enable/gcbench/publish.py +++ b/enable/gcbench/publish.py @@ -33,6 +33,8 @@ td.invalid {{ background: lightpink; }} + td.skipped {{ + }}
@@ -79,17 +81,21 @@ def publish(results, outdir): """ Write the test results out as a simple webpage. """ - backends = list(results) + backends = [] functions = {} - for bend in backends: - for func, stats in results[bend].items(): - functions.setdefault(func, {})[bend] = stats - # Scale timing values relative to the "kiva.agg" backend implementation + # Transpose the results so that they're accesible by function. + for btype, backend_results in results.items(): + backends.extend(list(backend_results)) + for bend in backend_results: + for name, res in backend_results[bend].items(): + functions.setdefault(name, {})[bend] = res + comparisons = {} for name, results in functions.items(): _build_function_page(name, results, outdir) - comparisons[name] = _format_mean(results, "kiva.agg") + # Scale timing values relative to the "kiva.agg" backend implementation + comparisons[name] = _format_benchmark(results, "kiva.agg") comparison_table = _build_comparison_table(backends, comparisons) path = os.path.join(outdir, "index.html") @@ -108,10 +114,8 @@ def _build_comparison_table(backends, comparisons): link = f'' row = [f"
