Guest User

Untitled

a guest
Nov 18th, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.56 KB | None | 0 0
  1. {-# LANGUAGE BangPatterns #-}
  2. {-# LANGUAGE MagicHash #-}
  3.  
  4. {-# OPTIONS_GHC -O2 #-}
  5.  
  6.  
  7. import Control.Monad
  8. import Data.Primitive
  9. import Control.Monad.ST
  10. import Criterion.Main
  11. import GHC.Prim
  12. import GHC.Int
  13. import qualified Weigh as W
  14.  
  15. main :: IO ()
  16. main = do
  17. let !thousand = upto 1000
  18. !tenThousand = upto 10000
  19. when (boxedFoldInt (+) 0 thousand /= (div (999 * 1000) 2)) $ do
  20. fail "boxedFoldInt is incorrect"
  21. when (unboxedFoldInt (+#) 0 thousand /= (div (999 * 1000) 2)) $ do
  22. fail "unboxedFoldInt is incorrect"
  23. let runCriterionBench = defaultMain
  24. [ bgroup "mapping ByteArray"
  25. [ bench "boxed" $ whnf (boxedFoldInt (+) 0) tenThousand
  26. , bench "unboxed" $ whnf (unboxedFoldInt (+#) 0) tenThousand
  27. ]
  28. ]
  29. runWeighBench = W.mainWith $ do
  30. W.func "boxed" (boxedFoldInt (+) 0) tenThousand
  31. W.func "unboxed" (unboxedFoldInt (+#) 0) tenThousand
  32. -- You can either run the criterion benchmark or the
  33. -- weigh benchmark but not both at the same time. Criterion
  34. -- will show you that the unboxed variant is faster.
  35. -- Weigh will show you why it's faster.
  36. runCriterionBench
  37. -- runWeighBench
  38. putStrLn "Finished Benchmarking"
  39.  
  40.  
  41.  
  42. upto :: Int -> ByteArray
  43. upto n = runST $ unsafeFreezeByteArray =<< go 0 =<< newByteArray (sizeOf (undefined :: Int) * n)
  44. where
  45. go :: Int -> MutableByteArray s -> ST s (MutableByteArray s)
  46. go ix arr = if ix < n
  47. then do
  48. writeByteArray arr ix ix
  49. go (ix + 1) arr
  50. else return arr
  51.  
  52. -- If we don't put NOINLINE pragmas on these, GHC optimizer gets too
  53. -- smart and inlines even the partial applications of these, making
  54. -- the benchmark entirely worthless. Specifically, what this means is
  55. -- that we end up a partial application of boxedFoldInt to (+) and 0.
  56. -- GHC ends up proceeds to optimizes this new function, and since
  57. -- it now knows the function being used as the fold, it can inline
  58. -- it and unbox everything.
  59.  
  60. {-# NOINLINE boxedFoldInt #-}
  61. boxedFoldInt :: (Int -> Int -> Int) -> Int -> ByteArray -> Int
  62. boxedFoldInt f acc0 arr = go 0 acc0
  63. where
  64. !sz = div (sizeofByteArray arr) (sizeOf (undefined :: Int))
  65. go !ix !acc = if ix < sz
  66. then go (ix + 1) (f (indexByteArray arr ix) acc)
  67. else acc
  68.  
  69. {-# NOINLINE unboxedFoldInt #-}
  70. unboxedFoldInt :: (Int# -> Int# -> Int#) -> Int -> ByteArray -> Int
  71. unboxedFoldInt f (I# acc0) boxedArr@(ByteArray arr) = I# (go 0 acc0)
  72. where
  73. !sz = div (sizeofByteArray boxedArr) (sizeOf (undefined :: Int))
  74. go :: Int -> Int# -> Int#
  75. go !ix@(I# ix#) !acc = if ix < sz
  76. then go (ix + 1) (f (indexIntArray# arr ix#) acc)
  77. else acc
Add Comment
Please, Sign In to add comment