@@ -184,8 +184,9 @@ instance Eq Product25 where
184 && a25 == b25
184 && a25 == b25
186-------------------------------------------------------------------------------
186-------------------------------------------------------------------------------
188-- Simple non-recursive ADT
187-- Simple non-recursive ADT
188+-------------------------------------------------------------------------------
189data CustomDT1
190data CustomDT1
191 | CDT1C2 Int
192 | CDT1C2 Int
@@ -199,30 +200,15 @@ $(DERIVE_CLASS ''CustomDT1)
201-------------------------------------------------------------------------------
202-------------------------------------------------------------------------------
203−{-# INLINE getSize #-}
204+-------------------------------------------------------------------------------
204−getSize :: forall a. SERIALIZE_CLASS a => a -> Int
206−getSize _ = sizeOf (Proxy :: Proxy a)
209− case size :: Size a of
213#ifndef USE_UNBOX
206#ifndef USE_UNBOX
214−{-# INLINE sizeOfOnce #-}
215−sizeOfOnce :: forall a. Serialize a => a -> Int
216−sizeOfOnce val = getSize val
219data BinTree a
207data BinTree a
220 = Tree (BinTree a) (BinTree a)
208 = Tree (BinTree a) (BinTree a)
222 deriving (Show, Read, Eq, Generic)
210 deriving (Show, Read, Eq, Generic)
224−-- XXX If a is ConstSize we can use an array to represent the binary tree. If
225−-- the tree is balanced space wastage would be minimum.
226#ifndef USE_TH
212#ifndef USE_TH
227instance Serialize (BinTree a)
213instance Serialize (BinTree a)
@@ -244,30 +230,24 @@ mkBinTree = go (generate $ arbitrary)
244 go r 0 = Leaf <$> r
230 go r 0 = Leaf <$> r
245 go r n = Tree <$> go r (n - 1) <*> go r (n - 1)
231 go r n = Tree <$> go r (n - 1) <*> go r (n - 1)
249−prop = forAll arbitrary (ioProperty . test)
251− where
235+-------------------------------------------------------------------------------
237+-------------------------------------------------------------------------------
253− test :: BinTree Int -> IO Bool
239+{-# INLINE getSize #-}
254− test t = do
240+getSize :: forall a. SERIALIZE_CLASS a => a -> Int
255− let n =
241+#ifdef USE_UNBOX
242+getSize _ = sizeOf (Proxy :: Proxy a)
256− case size :: Size (BinTree Int) of
245+ case size :: Size a of
257− ConstSize x -> x
246+ Size f -> f 0 val
260− _ <- serialize 0 arr t
261− (_, t1) <- deserialize 0 arr
265−runQC = quickCheckWith stdArgs {maxSuccess = 100} prop
269-------------------------------------------------------------------------------
249-------------------------------------------------------------------------------
270−-- Helpers
250+-- Common helpers
271-------------------------------------------------------------------------------
251-------------------------------------------------------------------------------
273-- Parts of "f" that are dependent on val will not be optimized out.
253-- Parts of "f" that are dependent on val will not be optimized out.
@@ -293,6 +273,13 @@ loopWith count f e val = go count val
293 then f e x >> go (n-1) x
273 then f e x >> go (n-1) x
294 else return ()
274 else return ()
276+benchSink :: NFData b => String -> Int -> (Int -> IO b) -> Benchmark
277+benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
279+-------------------------------------------------------------------------------
280+-- Serialization Helpers
281+-------------------------------------------------------------------------------
296{-# INLINE pokeWithSize #-}
283{-# INLINE pokeWithSize #-}
297pokeWithSize :: SERIALIZE_CLASS a => MutableByteArray -> a -> IO ()
284pokeWithSize :: SERIALIZE_CLASS a => MutableByteArray -> a -> IO ()
298pokeWithSize arr val = do
285pokeWithSize arr val = do
@@ -321,11 +308,12 @@ pokeTimes val times = do
321peek :: forall a. (Eq a, SERIALIZE_CLASS a) => a -> MutableByteArray -> IO ()
308peek :: forall a. (Eq a, SERIALIZE_CLASS a) => a -> MutableByteArray -> IO ()
322peek val arr = do
309peek val arr = do
323#ifdef USE_UNBOX
310#ifdef USE_UNBOX
324− val1
311+ (val1 :: a)
326 (_, val1 :: a)
313 (_, val1 :: a)
328 <- DESERIALIZE_OP 0 arr
315 <- DESERIALIZE_OP 0 arr
316+ assert (val == val1) (pure ())
329 -- Ensure that we are actually constructing the type and using it.
317 -- Ensure that we are actually constructing the type and using it.
330 -- Otherwise we may just read the values and discard them.
318 -- Otherwise we may just read the values and discard them.
331 -- The comparison adds to the cost though.
319 -- The comparison adds to the cost though.
@@ -369,37 +357,54 @@ trip val = do
369roundtrip :: (Eq a, SERIALIZE_CLASS a) => a -> Int -> IO ()
357roundtrip :: (Eq a, SERIALIZE_CLASS a) => a -> Int -> IO ()
370roundtrip val times = loop times trip val
358roundtrip val times = loop times trip val
372−benchSink :: NFData b => String -> Int -> (Int -> IO b) -> Benchmark
373−benchSink name times f = bench name (nfIO (randomRIO (times, times) >>= f))
375-------------------------------------------------------------------------------
360-------------------------------------------------------------------------------
376-- Benchmarks
361-- Benchmarks
377-------------------------------------------------------------------------------
362-------------------------------------------------------------------------------
379−{-# INLINE benchPoke #-}
364+{-# INLINE benchConst #-}
380−benchPoke :: String -> (forall a. SERIALIZE_CLASS a =>
367+ -> (forall a. (Eq a, SERIALIZE_CLASS a) => Int -> a -> Int -> IO ())
381− a -> Int -> IO ()) -> BinTree Int -> [Int] -> Int -> Benchmark
369+ -> Benchmark
382−benchPoke gname f tInt lInt times =
370+benchConst gname f times =
383 bgroup gname
371 bgroup gname
372+ [ let !n = getSize Unit
373+ in benchSink "Unit" times (f n Unit)
374+ , let !n = getSize CDT1C1
384− [ benchSink "C1" times
375+ in benchSink "C1" times (f n CDT1C1)
385− (f CDT1C1)
376+ , let val = CDT1C2 5
386− , benchSink "C2" (times `div` 2)
378+ in benchSink "C2" (times `div` 2) (f n val)
387− (f (CDT1C2 5))
379+ , let val = CDT1C3 5 2
388− , benchSink "C3" (times `div` 3)
381+ in benchSink "C3" (times `div` 3) (f n val)
389− (f (CDT1C3 5 2))
382+ , let !n = getSize Sum21
390− , benchSink "Sum2" times
383+ in benchSink "Sum2" times (f n Sum21)
391− (f Sum21)
384+ , let !n = getSize Sum2525
392− , benchSink "Sum25" times
385+ in benchSink "Sum25" times (f n Sum2525)
394− , benchSink "Product25" (times `div` 26)
395− (f (Product25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25))
386+ , let val = Product25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
388+ in benchSink "Product25" (times `div` 26) (f n val)
396#ifndef USE_UNBOX
391#ifndef USE_UNBOX
392+{-# INLINE benchVar #-}
395+ -> (forall a. (Eq a, SERIALIZE_CLASS a) => Int -> a -> Int -> IO ())
400+benchVar gname f tInt lInt times =
402+ [ let !n = getSize tInt
397− , benchSink "bintree-int" 1
403+ in benchSink "bintree-int" times (f n tInt)
398− (f tInt)
404+ , let !n = getSize lInt
399− , benchSink "list-int" 1
405+ in benchSink "list-int" times (f n lInt)
404-- Times is scaled by the number of constructors to normalize
409-- Times is scaled by the number of constructors to normalize
405#ifdef USE_UNBOX
410#ifdef USE_UNBOX
@@ -412,57 +417,20 @@ allBenchmarks tInt lInt times =
412 [ bgroup "sizeOf"
417 [ bgroup "sizeOf"
414#ifndef USE_UNBOX
419#ifndef USE_UNBOX
415− bench "bintree-int" $ nf sizeOfOnce tInt
420+ bench "bintree-int" $ nf getSize tInt
416− , bench "list-int" $ nf sizeOfOnce lInt
421+ , bench "list-int" $ nf getSize lInt
419− , benchPoke "poke" pokeTimes tInt lInt times
420− , benchPoke "pokeWithSize" pokeTimesWithSize tInt lInt times
422− [ let !n = getSize Unit
423− in benchSink "Unit" times (peekTimes n Unit)
424− , let !n = getSize CDT1C1
425− in benchSink "C1" times (peekTimes n CDT1C1)
426− , let val = CDT1C2 5
428− in benchSink "C2" (times `div` 2) (peekTimes n val)
429− , let val = CDT1C3 5 2
431− in benchSink "C3" (times `div` 3) (peekTimes n val)
432− , let !n = getSize Sum21
433− in benchSink "Sum2" times (peekTimes n Sum21)
434− , let !n = getSize Sum2525
435− in benchSink "Sum25" times (peekTimes n Sum2525)
436− , let val = Product25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
438− in benchSink "Product25" (times `div` 26) (peekTimes n val)
440− , let !n = getSize tInt
441− in benchSink "bintree-int" 1 (peekTimes n tInt)
442− , let !n = getSize lInt
443− in benchSink "list-int" 1 (peekTimes n lInt)
446− , bgroup "roundtrip"
424+ , benchConst "poke" (const pokeTimes) times
447− [ benchSink "C1" times
425+ , benchConst "pokeWithSize" (const pokeTimesWithSize) times
448− (roundtrip CDT1C1)
426+ , benchConst "peek" peekTimes times
449− , benchSink "C2" (times `div` 2)
427+ , benchConst "roundtrip" (const roundtrip) times
450− (roundtrip (CDT1C2 5))
451− , benchSink "C3" (times `div` 3)
452− (roundtrip (CDT1C3 5 2))
453− , benchSink "Sum2" times
455− , benchSink "Sum25" times
457− , benchSink "Product25" (times `div` 26)
458− (roundtrip (Product25 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25))
459#ifndef USE_UNBOX
428#ifndef USE_UNBOX
460− , benchSink "bintree-int" 1
429+ , benchVar "poke" (const pokeTimes) tInt lInt 1
461− (roundtrip tInt)
430+ , benchVar "pokeWithSize" (const pokeTimesWithSize) tInt lInt 1
462− , benchSink "list-int" 1
431+ , benchVar "peek" peekTimes tInt lInt 1
463− (roundtrip lInt)
432+ , benchVar "roundtrip" (const roundtrip) tInt lInt 1
468-------------------------------------------------------------------------------
436-------------------------------------------------------------------------------
@@ -496,8 +464,8 @@ main = do
496 -- Check the .dump-simpl output
464 -- Check the .dump-simpl output
497 let value = 100000
465 let value = 100000
498 -- print $ getSize (CDT1C3 4 2)
466 -- print $ getSize (CDT1C3 4 2)
499− -- print $ sizeOfOnce tInt
467+ -- print $ getSize tInt
500− -- print $ sizeOfOnce lInt
468+ -- print $ getSize lInt
502 -- pokeTimes tInt 1
470 -- pokeTimes tInt 1