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

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


Thank you for this answer.

On Sun, Jun 19, 2016 at 1:08 AM, Amos Robinson <amos.robinson at gmail.com> wrote:
> Hi,
> You might want to add inline pragmas to "inc" and so on.
> STRef is boxed, so it will allocate. The 'URef' type here might be useful:
> http://hackage.haskell.org/package/mutable-containers-0.3.2.1/docs/Data-Mutable.html
> It is just a wrapper around unboxed mutable vector, as Carter suggests.

I added INLINE pragma on all my functions and it does not change
anything unfortunately.

I tried the package mutable-containers and the Api is really great,
but I'm surprised by the results :

- 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)

This is based on the creation of the Ref using a "mutable" function such as :

mutable v = asF <$> newRef v

(with asF == asPRef, asURef, ...)

However, if I'm providing a type signature for mutable, I got totally
different results :

mutable :: forall (f :: * -> *) a.
                 (Prim a, PrimMonad f) =>
                 a -> f (MyRef (PrimState f) a)
mutable v = asF <$> newRef v

(with type MyRef = PRef, URef, ...)

- PRef: 39ms (huge improvement, and winner as expected)
- URef: 45ms
- SRef: 43ms
- BRef: 84ms
- STRef: 54ms

I don't understand the speed difference which is only impacted by the
availability of a signature for mutable.

Now much of the allocation due to STRef have disappears. There is
still some which annoys me.

Most of the allocations comes from that line :

https://github.com/guibou/inversionsCount/blob/syntax/inversions.hs#L35

Which is nothing more that a boolean expression between different ST
action which are reading from unboxed Vector or PRef. So I was
expecting without allocation. Perhaps the fact that it uses "high
level" combinators such as "<$>", "<*>" and "=<<" is responsible ?

> The sad story is that in my experience, if you really want decent
> performance you will have to dump the Core and inspect it by hand. You'd
> then add inline and bang patterns based on the Core. I do not recommend it
> as a relaxing weekend exercise. I usually use an invocation something like:
>> ghc -ddump-prep -dppr-case-as-let -dsuppress-all -fforce-recomp
>> inversions.hs > inversions.hscore

Thank you ;) For now I rather prefer reading intel x86 assembler than
GHC core, but today is a rainy day, so I'll use it to start my
understanding of the GHC core ;)

-- 
G.


More information about the Haskell-Cafe mailing list