77module Performance.Minibench
88 ( bench
99 , benchWith
10+ , benchWith'
11+ , BenchResult
12+ , withUnits
1013 ) where
1114
12- import Control.Monad.Eff (Eff , forE )
13- import Control.Monad.Eff.Console (CONSOLE , log )
14- import Control.Monad.Eff.Uncurried (EffFn1 , runEffFn1 )
15- import Control.Monad.ST (modifySTRef , newSTRef , readSTRef , runST )
15+ import Prelude hiding (min ,max )
16+
1617import Data.Int (toNumber )
18+ import Effect (Effect , forE )
19+ import Effect.Console (log )
20+ import Effect.Ref as Ref
21+ import Effect.Uncurried (EffectFn1 , runEffectFn1 )
1722import Global (infinity )
1823import Math (max , min , sqrt )
1924import Partial.Unsafe (unsafeCrashWith )
20- import Prelude hiding (min ,max )
2125
2226-- | A wrapper around the Node `process.hrtime()` function.
23- foreign import hrTime :: forall eff . EffFn1 eff (Array Int ) (Array Int )
27+ foreign import hrTime :: EffectFn1 (Array Int ) (Array Int )
2428
2529-- | Force garbage collection.
2630-- | Requires node to be run with the --force-gc flag.
27- foreign import gc :: forall eff . Eff eff Unit
31+ foreign import gc :: Effect Unit
2832
2933foreign import toFixed :: Number -> String
3034
@@ -46,37 +50,58 @@ withUnits t
4650-- | To increase benchmark accuracy by forcing garbage collection before the
4751-- | benchmark is run, node should be invoked with the '--expose-gc' flag.
4852benchWith
49- :: forall eff a
53+ :: forall a
54+ . Int
55+ -> (Unit -> a )
56+ -> Effect Unit
57+ benchWith n f = do
58+ res <- benchWith' n f
59+ log (" mean = " <> withUnits res.mean)
60+ log (" stddev = " <> withUnits res.stdDev)
61+ log (" min = " <> withUnits res.min)
62+ log (" max = " <> withUnits res.max)
63+
64+ type BenchResult =
65+ { mean :: Number
66+ , stdDev :: Number
67+ , min :: Number
68+ , max :: Number
69+ }
70+
71+ benchWith'
72+ :: forall a
5073 . Int
5174 -> (Unit -> a )
52- -> Eff ( console :: CONSOLE | eff ) Unit
53- benchWith n f = runST do
54- sumRef <- newSTRef 0.0
55- sum2Ref <- newSTRef 0.0
56- minRef <- newSTRef infinity
57- maxRef <- newSTRef 0.0
75+ -> Effect BenchResult
76+ benchWith' n f = do
77+ sumRef <- Ref .new 0.0
78+ sum2Ref <- Ref .new 0.0
79+ minRef <- Ref .new infinity
80+ maxRef <- Ref .new 0.0
5881 gc
5982 forE 0 n \_ -> do
60- t1 <- runEffFn1 hrTime [0 , 0 ]
61- t2 <- const (runEffFn1 hrTime t1) (f unit)
83+ t1 <- runEffectFn1 hrTime [0 , 0 ]
84+ t2 <- const (runEffectFn1 hrTime t1) (f unit)
6285 let ns = fromHrTime t2
6386 square = ns * ns
64- _ <- modifySTRef sumRef (_ + ns)
65- _ <- modifySTRef sum2Ref (_ + square)
66- _ <- modifySTRef minRef (_ `min` ns)
67- _ <- modifySTRef maxRef (_ `max` ns)
87+ _ <- Ref .modify (_ + ns) sumRef
88+ _ <- Ref .modify (_ + square) sum2Ref
89+ _ <- Ref .modify (_ `min` ns) minRef
90+ _ <- Ref .modify (_ `max` ns) maxRef
6891 pure unit
69- sum <- readSTRef sumRef
70- sum2 <- readSTRef sum2Ref
71- min' <- readSTRef minRef
72- max' <- readSTRef maxRef
92+ sum <- Ref .read sumRef
93+ sum2 <- Ref .read sum2Ref
94+ min' <- Ref .read minRef
95+ max' <- Ref .read maxRef
7396 let n' = toNumber n
7497 mean = sum / n'
7598 stdDev = sqrt ((sum2 - n' * mean * mean) / (n' - 1.0 ))
76- log (" mean = " <> withUnits mean)
77- log (" stddev = " <> withUnits stdDev)
78- log (" min = " <> withUnits min')
79- log (" max = " <> withUnits max')
99+ pure
100+ { mean
101+ , stdDev
102+ , min: min'
103+ , max: max'
104+ }
80105
81106-- | Estimate the running time of a function and print a summary to the console,
82107-- | by running the function 1000 times.
@@ -92,8 +117,5 @@ benchWith n f = runST do
92117-- | mean = 414.00 μs
93118-- | stddev = 494.82 μs
94119-- | ```
95- bench
96- :: forall eff a
97- . (Unit -> a )
98- -> Eff (console :: CONSOLE | eff ) Unit
120+ bench :: forall a . (Unit -> a ) -> Effect Unit
99121bench = benchWith 1000
0 commit comments