packed-data-0.1.0.0: benchmark/Increment.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CApiFFI #-}
module Increment (benchmark) where
import Control.DeepSeq
import Control.Monad
import Criterion.Main
import Data.List (intercalate)
import Data.Packed
import Data.Packed.Needs (applyNeeds)
import qualified Data.Packed.Needs as N
import qualified Data.Packed.Reader as R
import Data.Void
import Foreign
import Foreign.C
import Utils
import Prelude hiding (concat)
foreign import capi unsafe "benchmark.h increment" c_increment :: Ptr Void -> IO ()
foreign import capi unsafe "benchmark.h build_tree" c_build_tree :: CInt -> IO (Ptr Void)
foreign import capi unsafe "benchmark.h free_tree" c_free_tree :: Ptr Void -> IO ()
data Tree1 a = Leaf1 a | Node1 (Tree1 a) (Tree1 a)
instance NFData (Tree1 a) where
rnf (Leaf1 a) = a `seq` ()
rnf (Node1 l r) = l `seq` r `seq` ()
$(mkPacked ''Tree1 [])
benchmark :: [Int] -> Benchmark
benchmark depths =
bgroup
"increment"
$ fmap computeTreeSumWithDepth depths
computeTreeSumWithDepth :: Int -> Benchmark
computeTreeSumWithDepth n =
bgroup
(depthGroupName n)
[ envWithCleanup (c_build_tree (fromIntegral n)) c_free_tree $
bench cTestName . nfAppIO c_increment
, bench nativeTestName $
nf increment nativeTree
, bench (intercalate "-" [packedTestName, "needsbuilder"]) $
nfAppIO incrementPackedRunner packedTree
, bench (intercalate "-" ["unpack", "repack"]) $
nf (pack . increment . fst . unpack) packedTree
, bench (intercalate "-" [packedTestName, "rebuild-repack"]) $
nfAppIO repackingIncrementPackedRunner packedTree
]
where
!packedTree = pack nativeTree
!nativeTree = buildNativeTree n
increment :: Tree1 Int -> Tree1 Int
increment (Leaf1 n) = Leaf1 (n + 1)
increment (Node1 t1 t2) = Node1 (increment t1) (increment t2)
-- Produces an needsbuilder for a tree alread incremented, and finishes it
incrementPackedRunner :: Packed '[Tree1 Int] -> IO (Packed '[Tree1 Int])
incrementPackedRunner packed = do
(!needs, _) <- runReader incrementPacked packed
return $ finish needs
incrementPacked :: PackedReader '[Tree1 Int] r (Needs '[] '[Tree1 Int])
incrementPacked =
transformTree1
( R.do
n <- reader
R.return (write (n + 1))
)
( R.do
left <- incrementPacked
right <- incrementPacked
R.return (applyNeeds left N.>> applyNeeds right)
)
buildNativeTree :: Int -> Tree1 Int
buildNativeTree 0 = Leaf1 1
buildNativeTree n = Node1 subTree subTree
where
subTree = buildNativeTree (n - 1)
-- Produces an unpacked tree alread incremented, and packs it
repackingIncrementPackedRunner :: Packed '[Tree1 Int] -> IO (Packed '[Tree1 Int])
repackingIncrementPackedRunner packed = do
(!tree, _) <- runReader repackingIncrementPacked packed
let !repacked = pack tree
return repacked
repackingIncrementPacked :: PackedReader '[Tree1 Int] r (Tree1 Int)
repackingIncrementPacked =
caseTree1
( R.do
n <- reader
R.return (Leaf1 (n + 1))
)
( R.do
!left <- repackingIncrementPacked
!right <- repackingIncrementPacked
R.return (Node1 left right)
)