Advertisement
Guest User

Untitled

a guest
Mar 28th, 2017
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.10 KB | None | 0 0
  1. #!/usr/bin/env stack
  2. -- stack --resolver lts-8.3 exec --package vector --package criterion -- ghc -O2
  3. {-# LANGUAGE BangPatterns #-}
  4. {-# LANGUAGE ScopedTypeVariables #-}
  5. module Main where
  6.  
  7. import Control.Monad.ST (ST)
  8. import Criterion.Main
  9. import qualified Data.Vector.Unboxed as VU
  10. import qualified Data.Vector.Unboxed.Mutable as MVU
  11.  
  12. -- | Delayed Array.
  13. data DArray ix e = DArray { dSize :: !ix
  14. , dUnsafeIndex :: ix -> e }
  15.  
  16. -- | Manifest Array.
  17. data MArray ix e = MArray { mSize :: !ix
  18. , mUnsafeIndex :: ix -> e }
  19.  
  20.  
  21. -- | Efficient loop with an accumulator
  22. loop :: Int -> (Int -> Bool) -> (Int -> Int) -> a -> (Int -> a -> a) -> a
  23. loop !init' condition increment !initAcc f = go init' initAcc where
  24. go !step !acc =
  25. case condition step of
  26. False -> acc
  27. True -> go (increment step) (f step acc)
  28. {-# INLINE loop #-}
  29.  
  30. -- | Efficient monadic loop
  31. loopM_ :: Monad m => Int -> (Int -> Bool) -> (Int -> Int) -> (Int -> m a) -> m ()
  32. loopM_ !init' condition increment f = go init' where
  33. go !step =
  34. case condition step of
  35. False -> return ()
  36. True -> f step >> go (increment step)
  37. {-# INLINE loopM_ #-}
  38.  
  39. -- | Load a delayed Array into memory. Unlike strem fusion, this can also be parallelized.
  40. compute
  41. :: forall e . VU.Unbox e => DArray Int e -> MArray Int e
  42. compute (DArray k f) = MArray k $ (VU.unsafeIndex v)
  43. where
  44. -- Make sure it's evaluated (deepseq == seq is for Unboxed Vector)
  45. !v = VU.create generateArray
  46. generateArray :: ST s (MVU.MVector s e)
  47. generateArray = do
  48. mv <- MVU.unsafeNew k
  49. loopM_ 0 (< k) (+ 1) $ \ !i -> MVU.unsafeWrite mv i (f i)
  50. return mv
  51. {-# INLINE generateArray #-}
  52. {-# INLINE compute #-}
  53.  
  54.  
  55. makeArray1D :: Int -> (Int -> e) -> DArray Int e
  56. makeArray1D = DArray
  57. {-# INLINE makeArray1D #-}
  58.  
  59. mapA :: (b -> e) -> DArray ix b -> DArray ix e
  60. mapA f (DArray k g) = DArray k (f . g)
  61. {-# INLINE mapA #-}
  62.  
  63. foldlA :: (t1 -> t -> t1) -> t1 -> DArray Int t -> t1
  64. foldlA f !acc (DArray k g) = loop 0 (< k) (+ 1) acc $ \ !i !acc0 -> f acc0 (g i)
  65. {-# INLINE foldlA #-}
  66.  
  67. sumA :: DArray Int Int -> Int
  68. sumA = foldlA (+) 0
  69. {-# INLINE sumA #-}
  70.  
  71. main :: IO ()
  72. main = do
  73. let !sz = 640000
  74. let arr1D = (`makeArray1D` id)
  75. let vec = (`VU.generate` id)
  76. {-# INLINE vec #-} -- <-- Degraded performance if not inlined.
  77. defaultMain
  78. [ bgroup
  79. "Fold Only"
  80. [ bench "1D Array" $ whnf (sumA . arr1D) sz
  81. , bench "Vector Unboxed" $ whnf (VU.sum . vec) sz
  82. ]
  83. , bgroup
  84. "Fold Fused"
  85. [ bench "1D Array" $ whnf (sumA . mapA (+ 25) . arr1D) sz
  86. , bench "Vector Unboxed" $ whnf (VU.sum . VU.map (+ 25) . vec) sz
  87. ]
  88. , bgroup
  89. "Compute Only"
  90. [ bench "1D Array" $ whnf (compute . arr1D) sz
  91. , bench "Vector Unboxed" $ whnf (`VU.generate` id) sz
  92. , bench "Vector Unboxed (very slow - not inlined!?!?)" $ whnf vec sz
  93. ]
  94. , bgroup
  95. "Compute Fused"
  96. [ bench "1D Array" $ whnf (compute . mapA (+ 50) . arr1D) sz
  97. , bench "Vector Unboxed" $ whnf (VU.map (+ 50) . vec) sz
  98. ]
  99. ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement