← ClaudeAtlas

haskell-benchmarkinglisted

Write and run Haskell performance benchmarks. Covers the `benchmark` cabal stanza, `tasty-bench` for timing (the default), `weigh` for memory-allocation measurement, baseline comparison to catch regressions, the laziness traps (`nf` vs `whnf`), and how to integrate with GHC profiling/flame graphs for deeper investigation. Also explains when to switch to `criterion` for HTML reports. Use when adding benchmarks, debugging a "this got slower" regression, comparing two implementations of the same function, hunting space leaks, or wiring benchmarks into CI.
ivelten/claude-haskell-skills · ★ 0 · Testing & QA · score 60
Install: claude install-skill ivelten/claude-haskell-skills
# Haskell Benchmarking Default stack: **`tasty-bench`** for timing + **`weigh`** for allocation. Use `criterion` only when you specifically need its HTML reports. Benchmarks live in a dedicated `benchmark` cabal stanza, separate from tests, and are run with `cabal bench` (not `cabal test`). Don't mix the two — tests are correctness gates that run on every commit; benchmarks are observability tools that run on demand or nightly because their variance is too high to gate builds. ## Cabal stanza Place benchmarks in `bench/` next to `src/` and `test/`. Compile with `-O2` always — benchmarking `-O0` code measures nothing useful. ```cabal benchmark my-project-bench import: shared type: exitcode-stdio-1.0 hs-source-dirs: bench main-is: Bench.hs ghc-options: -O2 build-depends: , base , my-project , tasty-bench ^>=0.4 , weigh ^>=0.0.17 ``` Run with `cabal bench` (or `cabal bench my-project-bench` to target a specific stanza). ## Timing benchmarks with `tasty-bench` ```haskell module Main (main) where import Test.Tasty.Bench import qualified Data.Map.Strict as Map import qualified Data.IntMap.Strict as IntMap main :: IO () main = defaultMain [ bgroup "lookup" [ bench "Map.lookup @1000" $ nf (Map.lookup 500) mapData , bench "IntMap.lookup @1000" $ nf (IntMap.lookup 500) intMapData ] , bgroup "insert" [ bench "Map.insert @1000" $ nf (Map.insert 1001 ()) map