I wrote a stored vector instance for the data type below ( original question here ):
data Atoms = I GHC.Int.Int32 | S GHC.Int.Int16
Below is the code to define these instances for Storable vector. While I am getting very good performance with the code below, I am very interested in general suggestions to improve the performance of this persistent instance. By general sentence, I mean the following:
- This does not apply to the GHC compiler version. You can assume that GHC 6.12.3+ eliminates performance errors if they are present in earlier versions and are related to this code.
- Platform oriented offerings are fine. You can assume the Linux x86_64 platform.
- A general proposal more in the form of an algorithm improvement (large O) is much appreciated than a proposal that uses hardware optimization. But, given a basic operation such as peek / poke here, there is little room for algorithmic improvement as far as I can tell (and therefore more valuable because it is a scarce product :)
- Compiler flags for x86_64 are valid (for example, tell the compiler to delete a floating point check, etc.). I use the "-O2 -make" option to compile the code.
If there is any known good library source code that does a similar thing (i.e. defines persistent instances for union / recursive types), I will be very interested in checking them.
import Data.Vector.Storable
import qualified Data.Vector.Storable as V
import Foreign
import Foreign.C.Types
import GHC.Int
data Atoms = I GHC.Int.Int32 | S GHC.Int.Int16
deriving (Show)
instance Storable Atoms where
sizeOf _ = 1 + sizeOf (undefined :: Int32)
alignment _ = 1 + alignment (undefined :: Int32)
{-# INLINE peek #-}
peek p = do
let p1 = (castPtr p::Ptr Word8) `plusPtr` 1 -- get pointer to start of the element. First byte is type of element
t <- peek (castPtr p::Ptr Word8)
case t of
0 -> do
x <- peekElemOff (castPtr p1 :: Ptr GHC.Int.Int32) 0
return (I x)
1 -> do
x <- peekElemOff (castPtr p1 :: Ptr GHC.Int.Int16) 0
return (S x)
{-# INLINE poke #-}
poke p x = case x of
I a -> do
poke (castPtr p :: Ptr Word8) 0
pokeElemOff (castPtr p1) 0 a
S a -> do
poke (castPtr p :: Ptr Word8) 1
pokeElemOff (castPtr p1) 0 a
where p1 = (castPtr p :: Ptr Word8) `plusPtr` 1 -- get pointer to start of the element. First byte is type of element
Update:
Daniel dflemstr, , Word32 Word8. , , , , , - . , (. - # 49). , , 33% ( sum ). ( - , ):
:
data Atoms = I {-
:
instance Storable Atoms where
sizeOf _ = 2*sizeOf (undefined :: Int32)
alignment _ = 4
{-# INLINE peek #-}
peek p = do
let p1 = (castPtr p::Ptr Word32) `plusPtr` 1
t <- peek (castPtr p::Ptr Word32)
case t of
0 -> do
x <- peekElemOff (castPtr p1 :: Ptr GHC.Int.Int32) 0
return (I x)
_ -> do
x <- peekElemOff (castPtr p1 :: Ptr GHC.Int.Int16) 0
return (S x)
{-# INLINE poke #-}
poke p x = case x of
I a -> do
poke (castPtr p :: Ptr Word32) 0
pokeElemOff (castPtr p1) 0 a
S a -> do
poke (castPtr p :: Ptr Word32) 1
pokeElemOff (castPtr p1) 0 a
where p1 = (castPtr p :: Ptr Word32) `plusPtr` 1