diff --git a/benchmarks/bench_report.nim b/benchmarks/bench_report.nim new file mode 100644 index 000000000..6842315e8 --- /dev/null +++ b/benchmarks/bench_report.nim @@ -0,0 +1,48 @@ +# Constantine +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Copyright (c) 2020-Present Mamy Andre-Ratsimbazafy +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import std/strutils + +var printedMarkdownHeaders: seq[string] + +func markdownEscape*(cell: string): string = + cell.multiReplace( + ("\\", "\\\\"), + ("|", "\\|"), + ("\r", ""), + ("\n", "
") + ) + +func markdownTableHeader*(headers: openArray[string]): string = + result = "|" + for header in headers: + result.add " " & markdownEscape(header) & " |" + +func markdownTableSeparator*(columns: int): string = + result = "|" + for _ in 0 ..< columns: + result.add " --- |" + +func markdownTableRow*(cells: openArray[string]): string = + result = "|" + for cell in cells: + result.add " " & markdownEscape(cell) & " |" + +proc reportMarkdownTable*(headers, cells: openArray[string]) = + doAssert headers.len == cells.len + + let key = headers.join("\t") + for printedHeader in printedMarkdownHeaders: + if printedHeader == key: + echo markdownTableRow(cells) + return + + echo markdownTableHeader(headers) + echo markdownTableSeparator(headers.len) + printedMarkdownHeaders.add key + echo markdownTableRow(cells) diff --git a/benchmarks/bench_summary_template.nim b/benchmarks/bench_summary_template.nim index 4c32ec808..b3b35adb0 100644 --- a/benchmarks/bench_summary_template.nim +++ b/benchmarks/bench_summary_template.nim @@ -29,6 +29,7 @@ import constantine/hash_to_curve/hash_to_curve, # Helpers helpers/prng_unsafe, + ./bench_report, ./bench_blueprint export @@ -45,9 +46,15 @@ proc report(op, domain: string, start, stop: MonoTime, startClk, stopClk: int64, let ns = inNanoseconds((stop-start) div iters) let throughput = 1e9 / float64(ns) when SupportsGetTicks: - echo &"{op:<35} {domain:<40} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)" + reportMarkdownTable( + ["Operation", "Domain", "Throughput", "Latency", "CPU cycles (approx)"], + [op, domain, &"{throughput:.3f} ops/s", &"{ns} ns/op", $((stopClk - startClk) div iters)] + ) else: - echo &"{op:<35} {domain:<40} {throughput:>15.3f} ops/s {ns:>9} ns/op" + reportMarkdownTable( + ["Operation", "Domain", "Throughput", "Latency"], + [op, domain, &"{throughput:.3f} ops/s", &"{ns} ns/op"] + ) macro fixEllipticDisplay(T: typedesc): untyped = # At compile-time, enums are integers and their display is buggy diff --git a/constantine.nimble b/constantine.nimble index 8e0202c79..f8cf17504 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -410,6 +410,7 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[ # KDF # ---------------------------------------------------------- ("tests/t_kdf_hkdf.nim", false), + ("tests/t_bench_report.nim", false), # Primitives # ---------------------------------------------------------- diff --git a/tests/t_bench_report.nim b/tests/t_bench_report.nim new file mode 100644 index 000000000..b8db40d5d --- /dev/null +++ b/tests/t_bench_report.nim @@ -0,0 +1,19 @@ +# Constantine +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Copyright (c) 2020-Present Mamy Andre-Ratsimbazafy +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import + std/unittest, + ../benchmarks/bench_report + +suite "Benchmark Markdown reports": + test "renders a Markdown table header": + check markdownTableHeader(["Operation", "Domain"]) == "| Operation | Domain |" + check markdownTableSeparator(2) == "| --- | --- |" + + test "escapes Markdown table cells": + check markdownTableRow(["A | B", "line 1\nline 2"]) == "| A \\| B | line 1
line 2 |"