diff --git a/yampa-test/CHANGELOG b/yampa-test/CHANGELOG index 4b0e16ff..562252af 100644 --- a/yampa-test/CHANGELOG +++ b/yampa-test/CHANGELOG @@ -1,3 +1,7 @@ +2023-08-07 Ivan Perez + * Version bump (0.14.4) (#274). + * Add version bounds to dependencies (#273). + 2023-06-07 Ivan Perez * Version bump (0.14.3) (#269). * Improve readability of CHANGELOGs (#261). diff --git a/yampa-test/yampa-test.cabal b/yampa-test/yampa-test.cabal index 30cf737b..4642a8c6 100644 --- a/yampa-test/yampa-test.cabal +++ b/yampa-test/yampa-test.cabal @@ -31,7 +31,7 @@ cabal-version: >= 1.10 build-type: Simple name: yampa-test -version: 0.14.3 +version: 0.14.4 author: Ivan Perez maintainer: ivan.perez@keera.co.uk homepage: http://github.com/ivanperez-keera/Yampa @@ -81,10 +81,10 @@ library FRP.Yampa.Stream build-depends: - base >= 4 && < 5 - , normaldistribution - , QuickCheck - , Yampa >= 0.14.3 && < 0.15 + base >= 4 && < 5 + , normaldistribution >= 1.1.0.1 && < 1.2 + , QuickCheck >= 2.12 && < 2.15 + , Yampa >= 0.14.4 && < 0.15 default-language: Haskell2010 @@ -121,11 +121,11 @@ test-suite yampa-quicheck build-depends: base < 5 - , Cabal >= 1.19 - , QuickCheck - , random - , tasty - , tasty-quickcheck + , Cabal >= 1.19 && < 3.9 + , QuickCheck >= 2.12 && < 2.15 + , random >= 1.1 && < 1.3 + , tasty >= 0.1 && < 1.5 + , tasty-quickcheck >= 0.1 && < 0.11 , Yampa , yampa-test diff --git a/yampa/CHANGELOG b/yampa/CHANGELOG index 49e3cc6c..9698211a 100644 --- a/yampa/CHANGELOG +++ b/yampa/CHANGELOG @@ -1,3 +1,8 @@ +2023-08-07 Ivan Perez + * Version bump (0.14.4) (#274). + * Introduce benchmark (#167). + * Add version bounds to dependencies (#273). + 2023-06-07 Ivan Perez * Version bump (0.14.3) (#269). * Improve readability of CHANGELOGs (#261). diff --git a/yampa/README.md b/yampa/README.md index ea9c6ec3..5eb4b0b1 100644 --- a/yampa/README.md +++ b/yampa/README.md @@ -431,6 +431,10 @@ This project is split in two: Yampa's unit tests are mostly implemented as tests inside the yampa-test library. The module hierarchy of `yampa-test/tests/Test` mirrors that of Yampa. +Yampa also includes some benchmarks as part of the main library. You are +encouraged to use them to evaluate your pull requests, and to improve the +benchmarks themselves. + A directory `yampa/examples` contains a number of examples of Yampa programs, some of which can be installed with the flag `-fexamples`. diff --git a/yampa/Yampa.cabal b/yampa/Yampa.cabal index 7ac7d6dd..ddb48b2f 100644 --- a/yampa/Yampa.cabal +++ b/yampa/Yampa.cabal @@ -30,7 +30,7 @@ cabal-version: >= 1.10 build-type: Simple name: Yampa -version: 0.14.3 +version: 0.14.4 author: Henrik Nilsson, Antony Courtney maintainer: Ivan Perez (ivan.perez@keera.co.uk) homepage: https://github.com/ivanperez-keera/Yampa/ @@ -315,3 +315,23 @@ executable yampa-examples-tailgatingdetector else buildable: False + +benchmark yampa-bench + type: + exitcode-stdio-1.0 + + main-is: + Bench.hs + + build-depends: + base < 5 + , criterion >= 0.5.0.0 && < 1.7 + , filepath >= 1.3.0.1 && < 1.5 + , time >= 1.4 && < 1.13 + , Yampa + + default-language: + Haskell2010 + + hs-source-dirs: + benchmarks diff --git a/yampa/benchmarks/Bench.hs b/yampa/benchmarks/Bench.hs new file mode 100644 index 00000000..25aa54a0 --- /dev/null +++ b/yampa/benchmarks/Bench.hs @@ -0,0 +1,155 @@ +-- | +-- Description : A benchmark for Yampa. +-- Copyright : (c) Ivan Perez, 2023 +-- Authors : Ivan Perez +-- +-- A benchmark for Yampa. +module Main where + +import Criterion (bench, bgroup, nf) +import Criterion.Main (defaultConfig, defaultMainWith) +import Criterion.Types (Config(csvFile, resamples, verbosity) + , Verbosity(Quiet)) +import Data.Time.LocalTime (getZonedTime) +import Data.Time.Format (formatTime, defaultTimeLocale) +import System.Environment (getArgs, withArgs) +import System.FilePath (()) + +import FRP.Yampa + +-- | Run all benchmarks. +main :: IO () +main = do + config <- customConfig + withArgs [] $ + defaultMainWith config + [ bgroup "basic" + [ bench "identity" $ nf basicIdentity 10000 + , bench "id" $ nf basicId 10000 + ] + , bgroup "compositions" + [ bench "identity" $ nf composeIdentity 10000 + , bench "idid" $ nf composeIdId 10000 + , bench "plus" $ nf composePlus 10000 + , bench "plusplus" $ nf composePlusPlus 10000 + , bench "plusmult" $ nf composePlusMult 10000 + , bench "mult" $ nf composeMult 10000 + , bench "multmult" $ nf composeMultMult 10000 + ] + , bgroup "counter" + [ bench "counter1" $ nf counter1 10000 + , bench "counter2" $ nf counter2 10000 + ] + ] + +-- * Benchmarks + +-- ** Basic + +-- | Yampa's specialized identity function. +basicIdentity :: Int -> [Int] +basicIdentity n = embed sf stream + where + sf = identity + stream = deltaEncode 1.0 (replicate n 1) + +-- | Standard function identity lifted to SFs. +basicId :: Int -> [Int] +basicId n = embed sf stream + where + sf = arr id + stream = deltaEncode 1.0 (replicate n 1) + +-- ** Compositions + +-- | Composition of Yampa's specialized identity function. +composeIdentity :: Int -> [Int] +composeIdentity n = embed sf stream + where + sf = identity >>> identity + stream = deltaEncode 1.0 (replicate n 1) + +-- | Composition of standard function identity lifted to SFs. +composeIdId :: Int -> [Int] +composeIdId n = embed sf stream + where + sf = arr id >>> arr id + stream = deltaEncode 1.0 (replicate n 1) + +-- | Plus operation. +-- +-- This is not a composition; it merely exists to serve as a comparison with +-- composePlusPlus. +composePlus :: Int -> [Int] +composePlus n = embed sf stream + where + sf = arr (+3) + stream = deltaEncode 1.0 $ take n [1..] + +-- | Composition of addition lifted to SFs. +composePlusPlus :: Int -> [Int] +composePlusPlus n = embed sf stream + where + sf = arr (+1) >>> arr (+2) + stream = deltaEncode 1.0 $ take n [1..] + +-- | Composition of addition with multiplication, lifted to SFs. +composePlusMult :: Int -> [Int] +composePlusMult n = embed sf stream + where + sf = arr (+100) >>> arr (*2) + stream = deltaEncode 1.0 $ take n [10..] + +-- | Multiplication operation. +-- +-- This is not a composition; it merely exists to serve as a comparison with +-- composeMultMult. +composeMult :: Int -> [Int] +composeMult n = embed sf stream + where + sf = arr (*20) + stream = deltaEncode 1.0 $ take n [10..] + +-- | Composition of multiplication lifted to SFs. +composeMultMult :: Int -> [Int] +composeMultMult n = embed sf stream + where + sf = arr (*10) >>> arr (*2) + stream = deltaEncode 1.0 $ take n [10..] + +-- ** Counter + +-- | Counter without explicit seq. +counter1 :: Int -> [Int] +counter1 n = embed sf stream + where + sf = loopPre 0 (arr (dup . uncurry (+))) + stream = deltaEncode 1.0 (replicate n 1) + +-- | Counter with explicit seq. +counter2 :: Int -> [Int] +counter2 n = embed sf stream + where + sf = loopPre 0 (arr ((\x -> x `seq` (x, x)). uncurry (+))) + stream = deltaEncode 1.0 (replicate n 1) + +-- * Auxiliary functions + +-- Construct a config with increased number of sampling +-- and a custom name for the report. +customConfig :: IO Config +customConfig = do + args <- getArgs + + let dir = case args of + [] -> "." + (x:xs) -> x + + -- Custom filename using the current time + timeString <- (formatTime defaultTimeLocale "%F-%H%M%S") <$> getZonedTime + let filename = concat [ timeString, "-", "bench.csv" ] + + return $ defaultConfig { csvFile = Just $ dir filename + , resamples = 100000 + , verbosity = Quiet + }