packages feed

apecs-0.10.1: bench/Main.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Strict #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}

import Control.DeepSeq (NFData (..))
import Control.Monad
import Criterion
import qualified Criterion.Main as C
import Criterion.Types
import Data.Vector.Unboxed.Deriving (derivingUnbox)
import Linear

import Apecs
import Foreign (Storable)

-- pos_vel, uncached
newtype Pos = Pos (V2 Float) deriving (Eq, Show)
instance Component Pos where type Storage Pos = Map Pos

newtype Vel = Vel (V2 Float) deriving (Eq, Show)
instance Component Vel where type Storage Vel = Map Vel

-- pos_vel, boxed cache
newtype BPos = BPos (V2 Float) deriving (Eq, Show)
instance Component BPos where type Storage BPos = Cache 10000 (Map BPos)

newtype BVel = BVel (V2 Float) deriving (Eq, Show)
instance Component BVel where type Storage BVel = Cache 1000 (Map BVel)

-- pos_vel, storable cache
newtype SPos = SPos (V2 Float) deriving (Eq, Show, Storable)
instance Component SPos where type Storage SPos = SCache 10000 (Map SPos)

newtype SVel = SVel (V2 Float) deriving (Eq, Show, Storable)
instance Component SVel where type Storage SVel = SCache 1000 (Map SVel)

-- pos_vel, unboxed cache
newtype UPos = UPos (V2 Float) deriving (Eq, Show)
derivingUnbox "UPos" [t|UPos -> V2 Float|] [|\(UPos v) -> v|] [|UPos|]
instance Component UPos where type Storage UPos = UCache 10000 (Map UPos)

newtype UVel = UVel (V2 Float) deriving (Eq, Show)
derivingUnbox "UVel" [t|UVel -> V2 Float|] [|\(UVel v) -> v|] [|UVel|]
instance Component UVel where type Storage UVel = UCache 1000 (Map UVel)

makeWorld "PosVel" [''MPos, ''MVel, ''BPos, ''BVel, ''SPos, ''SVel, ''UPos, ''UVel]
instance NFData PosVel where rnf PosVel{} = ()

rawInit :: System PosVel ()
rawInit = do
  replicateM_ 1000 $ newEntity (Pos 0, Vel 1)
  replicateM_ 9000 $ newEntity (Pos 0)

rawStep :: System PosVel ()
rawStep = cmap $ \(Vel v, Pos p) -> Pos (p + v)

boxedInit :: System PosVel ()
boxedInit = do
  replicateM_ 1000 $ newEntity (BPos 0, BVel 1)
  replicateM_ 9000 $ newEntity (BPos 0)

boxedStep :: System PosVel ()
boxedStep = cmap $ \(BVel v, BPos p) -> BPos (p + v)

storableInit :: System PosVel ()
storableInit = do
  replicateM_ 1000 $ newEntity (SPos 0, SVel 1)
  replicateM_ 9000 $ newEntity (SPos 0)

storableStep :: System PosVel ()
storableStep = cmap $ \(SVel v, SPos p) -> SPos (p + v)

unboxedInit :: System PosVel ()
unboxedInit = do
  replicateM_ 1000 $ newEntity (UPos 0, UVel 1)
  replicateM_ 9000 $ newEntity (UPos 0)

unboxedStep :: System PosVel ()
unboxedStep = cmap $ \(UVel v, UPos p) -> UPos (p + v)

posVelGroup :: String -> System PosVel () -> System PosVel () -> Benchmark
posVelGroup name initSys stepSys =
  bgroup
    name
    [ bench "init" $ whnfIO (initPosVel >>= runSystem initSys)
    , bench "step" $
        perBatchEnv
          (\_ -> initPosVel >>= \w -> runSystem initSys w >> pure w)
          (runSystem stepSys)
    ]

main :: IO ()
main =
  C.defaultMainWith
    (C.defaultConfig{timeLimit = 10})
    [ bgroup
        "pos_vel"
        [ posVelGroup "raw" rawInit rawStep
        , posVelGroup "boxed" boxedInit boxedStep
        , posVelGroup "storable" storableInit storableStep
        , posVelGroup "unboxed" unboxedInit unboxedStep
        ]
    ]