gampleman/elm-bench/1.0.0

NOTE: the latest version is 1.1.1

Bench

A benchmarking library designed for the elm-benchmark CLI runner.

Provides a richer API than elm-explorations/benchmark with:

  • Automatic correctness checks — compare, rank, and scale verify that all implementations produce the same result before benchmarking.
  • Fuzzer-based inputs — generate random test data using elm-explorations/test fuzzers.
  • Scaling analysis — measure how algorithms perform at different input sizes.
  • Filtering — the CLI can run a subset of benchmarks by name.

Creating Benchmarks

A benchmark definition. Can be a single measurement, a comparison of multiple implementations, a scaling analysis, or a named group.

benchmark : String -> (() -> a) -> Benchmark

Benchmark a single function.

benchmark "List.map" <|
    \_ -> List.map ((+) 1) (List.range 1 100)
compare : String -> ( String, () -> a ) -> ( String, () -> a ) -> Benchmark

Compare two implementations. Automatically verifies they produce the same result before benchmarking.

compare "reversing"
    ( "List.reverse", \_ -> List.reverse data )
    ( "List.foldl (::)", \_ -> List.foldl (::) [] data )
rank : String -> (f -> a) -> List ( String, f ) -> Benchmark

Compare multiple implementations with a shared runner function. Automatically verifies that all implementations produce the same result.

rank "mapToList"
    (\mapToList -> mapToList negate ints1To100)
    [ ( "with foldr", Array.Extra.MapToList.withFoldr )
    , ( "with toIndexedList", Array.Extra.MapToList.withListMap )
    ]
describe : String -> List Benchmark -> Benchmark

Organize benchmarks into a named group.

describe "Array.Extra"
    [ rank "mapToList" ...
    , rank "filterMap" ...
    ]
String
-> List Int
-> (Int -> input)
-> List ( String, input -> a )

Run multiple implementations at different input sizes. Useful for understanding algorithmic complexity. Automatically verifies correctness at each size.

scale "sorting"
    [ 10, 100, 1000 ]
    (\n -> List.range 1 n |> List.reverse)
    [ ( "List.sort", List.sort )
    , ( "mergeSort", mergeSort )
    ]
series : String -> List ( String, () -> a ) -> Benchmark

A simple series of named benchmarks. Does not verify equality (use rank if you want correctness checks).

series "approaches"
    [ ( "List.sort", \_ -> List.sort data )
    , ( "List.sortBy identity", \_ -> List.sortBy identity data )
    ]

Fuzzer Variants

These use fuzzers from elm-explorations/test to generate random input data. The fuzzer is sampled once per benchmark run (seeded deterministically).

String
-> Fuzzer input
-> ( String, input -> a )
-> ( String, input -> a )

Like compare, but generates input from a fuzzer. The fuzzer is also used for the correctness check (fuzz test).

compareFuzz "reversing"
    (Fuzz.list Fuzz.int)
    ( "List.reverse", List.reverse )
    ( "List.foldl (::)", List.foldl (::) [] )
String
-> Fuzzer input
-> (f -> input -> a)
-> List ( String, f )

Like rank, but generates input from a fuzzer.

rankFuzz "mapToList"
    (Fuzz.array Fuzz.int)
    (\mapToList array -> mapToList negate array)
    [ ( "with foldr", Array.Extra.MapToList.withFoldr )
    , ( "with toIndexedList", Array.Extra.MapToList.withListMap )
    ]
String
-> List Int
-> (Int -> Fuzzer input)
-> List ( String, input -> a )

Like scale, but generates input from a size-dependent fuzzer.

scaleFuzz "sorting"
    [ 10, 100, 1000 ]
    (\n -> Fuzz.listOfLength n Fuzz.int)
    [ ( "List.sort", List.sort )
    , ( "mergeSort", mergeSort )
    ]

Correctness Verification

compare, rank, and scale automatically verify that all implementations produce the same result. Use skipEqualityCheck to opt out.

Disable the automatic equality check for a benchmark. Use this when implementations intentionally produce different results (e.g. different orderings that are both valid).

rank "set operations"
    (\toList -> toList mySet)
    [ ( "Set.toList", Set.toList )
    , ( "custom", customToList ) -- different order, both valid
    ]
    |> skipEqualityCheck

Filtering

filter : String -> Benchmark -> Maybe Benchmark

Filter benchmarks by name (case-insensitive substring match). Groups are kept if any child matches. Returns Nothing if nothing matches.

For Runners

These are used internally by the CLI runner. You shouldn't need them directly.

toInternalBenchmark : Seed -> Benchmark -> Benchmark

Convert to elm-explorations/benchmark's Benchmark type for execution. The seed is used to generate deterministic fuzzer-based input.

toInternalTest : Benchmark -> Maybe Test

Extract the correctness test from a benchmark tree. The CLI runner executes this before benchmarking to catch broken implementations early.

encode : Benchmark -> Value

Encode the benchmark tree structure as JSON. Used by the CLI to understand the tree shape for filtering and display.