[vector] #33: Strange performance with mutable vectors

vector vector at projects.haskell.org
Mon Aug 23 12:59:28 EDT 2010


#33: Strange performance with mutable vectors
----------------------+-----------------------------------------------------
Reporter:  anonymous  |       Owner:     
    Type:  defect     |      Status:  new
Priority:  major      |   Milestone:     
 Version:             |    Keywords:     
----------------------+-----------------------------------------------------
 I run into some strange performance problem with mutable vectors. Function
 uniform below performs very poorly (with ~60x slowdown) but simple and not
 very logical changes return performance to normal

 {{{
 newtype Gen s = Gen (M.MVector s Word32)

 class Variate a where
     uniform :: (PrimMonad m) => Gen (PrimState m) -> m a
 instance Variate Word32 where
     uniform = uniformWord32
     {-# INLINE uniform #-}

 uniformWord32 :: PrimMonad m => Gen (PrimState m) -> m Word32
 uniformWord32 (Gen q) = do
   i <- nextIndex `liftM` M.unsafeRead q 256
   t <- M.unsafeRead q i
   M.unsafeWrite q 256 (fromIntegral i)
   return t
 {-# INLINE uniformWord32 #-}
 }}}

 First option is to add `Unbox a' constraint to the Variate type class.
 Another option is to replace function uniformWord32 with:

 {{{
 uniformWord32 (Gen q) = do
   i <- nextIndex `liftM` M.unsafeRead q 256
   M.unsafeWrite q 256 (fromIntegral i)
   M.unsafeRead q i
 }}}

 Tested with GHC6.12.1 (debian) and vector-0.6.0.2 and current darcs head.

 File attachments doesn't work so I'm pasting code inline:

 MWC.hs
 {{{
 module MWC ( Gen
            , Variate(..)
            , create
            ) where

 import Control.Monad           (liftM)
 import Control.Monad.Primitive (PrimMonad, PrimState)
 import Data.Bits               (shiftR)
 import Data.Word               (Word8,Word32,Word64)
 import qualified Data.Vector.Generic         as G
 import qualified Data.Vector.Unboxed         as I
 import qualified Data.Vector.Unboxed.Mutable as M

 -- class M.Unbox a => Variate a where
 class Variate a where
     uniform :: (PrimMonad m) => Gen (PrimState m) -> m a
 instance Variate Word32 where
     uniform = uniformWord32
     {-# INLINE uniform #-}

 -- | State of the pseudo-random number generator.
 newtype Gen s = Gen (M.MVector s Word32)

 -- | Create a generator for variates using a fixed seed.
 create :: PrimMonad m => m (Gen (PrimState m))
 create = do
   q <- M.unsafeNew 257
   G.copy q defaultSeed
   return (Gen q)
 {-# INLINE create #-}

 -- | Compute the next index into the state pool.  This is simply
 -- addition modulo 256.
 nextIndex :: Integral a => a -> Int
 nextIndex i = fromIntegral j
     where j = fromIntegral (i+1) :: Word8
 -- {-# INLINE nextIndex #-}

 uniformWord32 :: PrimMonad m => Gen (PrimState m) -> m Word32
 uniformWord32 (Gen q) = do
   i <- nextIndex `liftM` M.unsafeRead q 256
   t <- M.unsafeRead q i
   M.unsafeWrite q 256 (fromIntegral i)
   return t
 {-# INLINE uniformWord32 #-}

 {- This variant is fast:
   M.unsafeWrite q 256 (fromIntegral i)
   M.unsafeRead q i
 -}

 defaultSeed :: I.Vector Word32
 defaultSeed = I.fromList $ reverse [0..256]
 }}}

 benchmark.hs:
 {{{
 import Data.Word
 import Criterion.Main
 import MWC

 main = do
   gen <- create
   defaultMain [ bench "mwc-Double" (uniform gen :: IO Word32) ]
 }}}
 This test case is stripped down code from mwc-random.

-- 
Ticket URL: <http://trac.haskell.org/vector/ticket/33>
vector <http://trac.haskell.org/vector>
Package vector


More information about the vector mailing list