[Haskell-cafe] ST Vector / STRef -- Performances and allocation

Guillaume Bouchard guillaum.bouchard+haskell at gmail.com
Sun Jun 19 14:10:53 UTC 2016


Thank you ! I'm now in an equal time with the C code ;)

On Sun, Jun 19, 2016 at 3:12 PM, Bertram Felgenhauer via Haskell-Cafe
<haskell-cafe at haskell.org> wrote:
> Guillaume Bouchard wrote:
>> - PRef (Unboxed bytearray of size 1, the closest thing to an unboxed
>> stack allocation) : 86ms
>> - URef (Unboxed vector of size 1) : 130ms
>> - SRef (Storable vector of size 1) : 43ms (This is an improvement !)
>> - BRef (Boxed ref) : 137ms
>> - STRef : 54ms (this was my baseline)
>
> You really shouldn't use any mutable variable at all for this, but pass
> the values around as function arguments instead:

Nice ! This is so obvious that I did not thought about it. Thank you.
(Thank you for the followup-mail, it is clear that it may be easier
for GHC to unbox / put in register "normal variable" than more complex
type such as the one involved in PRef).

> Besides, the code spends most of its time on parsing the input. The
> following more low-level code does the job far more quickly:

Impressive. On the profiling the parsing was accounting only for 10%
of the running time. Perhaps the profiler introduces more overhead on
the vector part than on the parsing.

> import Data.ByteString.Char8 as B
>
> parse' :: IO [Int32]
> parse' = do
>     content <- B.getContents
>     return $ map fromIntegral $ unfoldr (B.readInt . B.dropWhile (=='\n')) $ content

This is in part with the C code. ~16ms

> It's possible to improve this slightly by implementing the code from scratch:
>
> parse'' :: IO [Int32]
> parse'' = do
>   content <- B.getContents
>   return $ go content
>  where
>   go b = case B.uncons b of
>       Nothing -> []
>       Just ('\n',b) -> go b
>       Just ('-',b) -> go'' 0 b
>       Just (d,b) -> go' (fromIntegral (ord d - 48)) b
>   go' v b = case B.uncons b of
>       Nothing -> [v]
>       Just ('\n',b) -> v : go b
>       Just (d,b) -> go' (v*10 + fromIntegral (ord d - 48)) b
>   go'' v b = case B.uncons b of
>       Nothing -> [v]
>       Just ('\n',b) -> v : go b
>       Just (d,b) -> go' (v*10 - fromIntegral (ord d - 48)) b
>
> Taken together these changes improve the runtime from 79ms to 21ms here.

This is better than the C code ;)

Thank you. I learned a few thing today.

-- 
Guillaume


More information about the Haskell-Cafe mailing list