packages feed

golds-gym 0.4.0.0 → 0.5.0.0

raw patch · 6 files changed

+32/−80 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Test.Hspec.BenchGolden: whnf :: (a -> b) -> a -> BenchAction
- Test.Hspec.BenchGolden: whnfAppIO :: (a -> IO b) -> a -> BenchAction
- Test.Hspec.BenchGolden: whnfIO :: IO a -> BenchAction
- Test.Hspec.BenchGolden.Runner: whnf :: (a -> b) -> a -> BenchAction
- Test.Hspec.BenchGolden.Runner: whnfAppIO :: (a -> IO b) -> a -> BenchAction
- Test.Hspec.BenchGolden.Runner: whnfIO :: IO a -> BenchAction

Files

CHANGELOG.md view
@@ -1,5 +1,19 @@ # Changelog +## [0.5.0]++### Added++- Clarified copyright notice for vendored code from `tasty-bench`, (c) Andrew Lelechenko 2021 -++### Removed++- **BREAKING:** Removed `whnf` (weak head normal form) evaluation combinators, the library is geared towards non-infinite input data+  - Removed `whnf` - use `nf` instead for pure functions+  - Removed `whnfIO` - use `nfIO` instead for IO actions+  - Removed `whnfAppIO` - use `nfAppIO` instead for functions returning IO+  - Migration: Replace all `whnf*` calls with their `nf*` equivalents+ ## [0.4.0]  ### Added@@ -14,11 +28,8 @@  - **Evaluation strategy combinators** for proper laziness handling   - `nf` - Force result to normal form (deep evaluation)-  - `whnf` - Force result to weak head normal form (shallow evaluation)   - `nfIO` - Normal form for IO actions-  - `whnfIO` - Weak head normal form for IO actions   - `nfAppIO` - Normal form for functions returning IO-  - `whnfAppIO` - WHNF for functions returning IO   - `io` - Plain IO action (for backward compatibility)   - Vendored evaluation loops from tasty-bench with attribution 
README.md view
@@ -20,35 +20,28 @@ main :: IO () main = hspec $ do   describe "Performance" $ do-    -- Pure function with normal form evaluation (deep, full evaluation)+    -- Pure function with normal form evaluation (full evaluation of the function arguments)     benchGolden "list append" $       nf (\xs -> xs ++ xs) [1..1000] -    -- Weak head normal form (shallow, outermost constructor only)-    benchGolden "replicate" $-      whnf (replicate 1000) 42-     -- Custom configuration     benchGoldenWith defaultBenchConfig       { iterations = 500       , tolerancePercent = 10.0       }       "sorting" $-      nf sort [1000, 999..1]+      nf ...  ```  **Evaluation strategies** (required - specify how values are forced): - `nf f x` - Force result of `f x` to **normal form** (deep, full evaluation)-- `whnf f x` - Force result of `f x` to **weak head normal form** (shallow, outermost constructor only) - `nfIO action` - Execute IO action and force result to normal form-- `whnfIO action` - Execute IO action and force result to WHNF - `nfAppIO f x` - Apply function, execute resulting IO, force result to normal form-- `whnfAppIO f x` - Apply function, execute resulting IO, force result to WHNF - `io action` - Plain IO action without additional forcing -**Why evaluation strategies matter**: Without forcing, GHC may optimize away computations or share results across iterations, making benchmarks meaningless. Use `nf` for most cases unless you specifically want lazy evaluation (`whnf`).+**Why evaluation strategies matter**: Without forcing, GHC may optimize away computations or share results across iterations, making benchmarks meaningless. -**First run** creates `.golden/<arch>/list-append.golden` with baseline stats.  +**First run** creates `.golden/<arch>/<benchmark_name>.golden` with baseline stats.   **Subsequent runs** compare against baseline. Test fails if mean time changes beyond tolerance (default: ±15% OR ±0.01ms).  **Output format** :
example/Spec.hs view
@@ -132,7 +132,7 @@     -- Hybrid tolerance with custom absolute threshold     benchGoldenWithExpectation "hybrid tolerance custom"        defaultBenchConfig { iterations = 1000 }-      [expect _statsMean (Hybrid 5.0 0.0001)] +      [expect _statsMean (Hybrid 5.0 0.001)]        $ nf (\n -> sort [n, n-1 .. 1]) (200 :: Int)      -- Use robust statistics lens (trimmed mean)
golds-gym.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               golds-gym-version:            0.4.0.0+version:            0.5.0.0 synopsis:           Golden testing framework for performance benchmarks description:     A Haskell framework for golden testing of timing benchmarks.
src/Test/Hspec/BenchGolden.hs view
@@ -33,11 +33,7 @@ --   describe \"Performance\" $ do --     -- Pure function with normal form evaluation --     `benchGolden` "list sorting" $---       `nf` sort [1000, 999..1]------     -- Weak head normal form (lazy evaluation)---     `benchGolden` "replicate" $---       `whnf` (replicate 1000) 42+--       `nf` (\\n -> sort [n, n-1 .. 1]) 1000 -- --     -- IO action with result forced to normal form --     `benchGolden` "file read" $@@ -47,9 +43,8 @@ -- __Evaluation strategies__ control how values are forced: -- -- * 'nf' - Force to normal form (deep evaluation, use for most cases)--- * 'whnf' - Force to weak head normal form (only outermost constructor is evaluated)--- * 'nfIO', 'whnfIO' - Variants for IO actions--- * 'nfAppIO', 'whnfAppIO' - For functions returning IO+-- * 'nfIO' - Variant for IO actions+-- * 'nfAppIO' - For functions returning IO -- * 'io' - Plain IO action without forcing -- -- Without proper evaluation strategies, GHC may optimize away computations@@ -197,11 +192,8 @@      -- * Benchmarkable Constructors   , nf-  , whnf   , nfIO-  , whnfIO   , nfAppIO-  , whnfAppIO   , io      -- * Low-Level API@@ -226,7 +218,7 @@ import Test.Hspec.BenchGolden.Arch import qualified Test.Hspec.BenchGolden.Lenses as L import Test.Hspec.BenchGolden.Lenses hiding (Expectation)-import Test.Hspec.BenchGolden.Runner (runBenchGolden, setAcceptGoldens, setSkipBenchmarks, nf, whnf, nfIO, whnfIO, nfAppIO, whnfAppIO, io)+import Test.Hspec.BenchGolden.Runner (runBenchGolden, setAcceptGoldens, setSkipBenchmarks, nf, nfIO, nfAppIO, io) import Test.Hspec.BenchGolden.Types  -- | Create a benchmark golden test with default configuration.@@ -242,11 +234,8 @@ -- Use evaluation strategy combinators to control how values are forced: -- -- * 'nf' - Normal form (deep evaluation)--- * 'whnf' - Weak head normal form (shallow evaluation) -- * 'nfIO' - Normal form for IO actions--- * 'whnfIO' - WHNF for IO actions -- * 'nfAppIO' - Normal form for functions returning IO--- * 'whnfAppIO' - WHNF for functions returning IO -- * 'io' - Plain IO action (for backward compatibility) -- -- Default configuration:
src/Test/Hspec/BenchGolden/Runner.hs view
@@ -7,7 +7,7 @@ -- | -- Module      : Test.Hspec.BenchGolden.Runner -- Description : Benchmark execution and golden file comparison--- Copyright   : (c) 2026+-- Copyright   : (c) Marco Zocca 2026 -- License     : MIT -- Maintainer  : @ocramz --@@ -15,10 +15,10 @@ -- golden files. It includes: -- -- * Benchmark execution with warm-up iterations--- * Golden file I/O (reading/writing JSON statistics)+-- * Golden file IO (reading and writing JSON statistics) -- * Tolerance-based comparison with variance warnings -- * Support for updating baselines via GOLDS_GYM_ACCEPT environment variable--- * Evaluation strategies to control how values are forced (nf, whnf, etc.)+-- * Evaluation strategies to control how values are forced (nf variants). -- -- = Evaluation Strategies --@@ -26,14 +26,11 @@ -- optimizing away computations or sharing results across iterations: -- -- * 'nf' - Force result to normal form (deep, full evaluation)--- * 'whnf' - Force result to weak head normal form (shallow evaluation) -- * 'nfIO' - Execute IO and force result to normal form--- * 'whnfIO' - Execute IO and force result to WHNF -- * 'nfAppIO' - Apply function, execute IO, force result to normal form--- * 'whnfAppIO' - Apply function, execute IO, force result to WHNF -- * 'io' - Plain IO without additional forcing ----- These are vendored from tasty-bench with proper attribution (BSD-3-Clause).+-- These are vendored from tasty-bench under the MIT license, (c) 2021 Andrew Lelechenko.  module Test.Hspec.BenchGolden.Runner   ( -- * Running Benchmarks@@ -68,11 +65,8 @@     -- * Benchmarkable Constructors   , io   , nf-  , whnf   , nfIO-  , whnfIO   , nfAppIO-  , whnfAppIO   ) where  import Control.DeepSeq (NFData, rnf)@@ -100,19 +94,12 @@ import Test.Hspec.BenchGolden.Lenses (metricFor, varianceFor) import Test.Hspec.BenchGolden.Types --- -------------------------------------------------------------------------------- Evaluation Strategies--- Vendored from tasty-bench-0.5 with modifications--- Copyright (c) 2021 Andrew Lelechenko and tasty-bench contributors--- MIT License--- https://hackage.haskell.org/package/tasty-bench-0.5--- ------------------------------------------------------------------------------ -- | Benchmark a pure function applied to an argument, forcing the result to -- normal form (NF) using 'rnf' from "Control.DeepSeq". -- This ensures the entire result structure is evaluated. -- -- Example:+-- -- @ -- benchGolden "fib 30" (nf fib 30) -- @@@ -120,20 +107,10 @@ nf = funcToBench rnf {-# INLINE nf #-} --- | Benchmark a pure function applied to an argument, forcing the result to--- weak head normal form (WHNF) only. This evaluates just the outermost constructor.------ Example:--- @--- benchGolden "replicate" (whnf (replicate 1000) 42)--- @-whnf :: (a -> b) -> a -> BenchAction-whnf = funcToBench id-{-# INLINE whnf #-}- -- | Benchmark an 'IO' action, forcing the result to normal form. -- -- Example:+-- -- @ -- benchGolden "readFile" (nfIO $ readFile "data.txt") -- @@@ -141,19 +118,10 @@ nfIO = ioToBench rnf {-# INLINE nfIO #-} --- | Benchmark an 'IO' action, forcing the result to weak head normal form.------ Example:--- @--- benchGolden "getLine" (whnfIO getLine)--- @-whnfIO :: IO a -> BenchAction-whnfIO = ioToBench id-{-# INLINE whnfIO #-}- -- | Benchmark a function that performs 'IO', forcing the result to normal form. -- -- Example:+-- -- @ -- benchGolden "lookup in map" (nfAppIO lookupInDB "key") -- @@@ -161,20 +129,11 @@ nfAppIO = ioFuncToBench rnf {-# INLINE nfAppIO #-} --- | Benchmark a function that performs 'IO', forcing the result to weak head normal form.------ Example:--- @--- benchGolden "query database" (whnfAppIO queryDB params)--- @-whnfAppIO :: (a -> IO b) -> a -> BenchAction-whnfAppIO = ioFuncToBench id-{-# INLINE whnfAppIO #-}- -- | Benchmark an 'IO' action, discarding the result. -- This is for backward compatibility with code that uses @IO ()@ actions. -- -- Example:+--  -- @ -- benchGolden "compute" (io $ do --   result <- heavyComputation