ForeignPtr performance.

Simon Marlow simonmar at
Mon Jul 19 05:35:02 EDT 2004

On 17 July 2004 05:31, John Meacham wrote:

> So, I was looking at the implementation of ForeignPtr's in an attempt
> to 
> determine why they were slow, and have an idea to speed them up..
> right now we have:
> ForeignPtr a
>   = ForeignPtr ForeignObj# !(IORef [IO ()])
>   | MallocPtr (MutableByteArray# RealWorld) !(IORef [IO ()])
> and I think the inderection caused by the disjunction is what is
> messing things up, not allowing ForeignPtrs to be inlined even in
> strict 
> contexts as the discriminator must still be examined. so how bout
> something like
> data ForeignPtr a = ForeignPtr Addr# !FP  -- note FP should be strict
> but BOXED [2] data FP = ForeignPtrObj ForeignObj# {-# UNPACK #-}
>         !(IORef [IO ()]) | MallocPtr (MutableByteArray# RealWorld)
> {-# UNPACK #-} !(IORef [IO ()])

At first I thought this wasn't safe, but having thought about it some
more I now think it might be.  The reason it is safe is because all
ForeignPtr access happens inside withForeignPtr, which is ended by
touch#.  The implementation of touch# is invisible to the compiler, so
GHC's optimiser *must* ensure that the FP stays alive until the touch#,
and hence the ForeignObj# also stays alive.

Interestingly, unless I'm being stupid (entirely possible) this implies
that we don't actually need ForeignObj# at all!  This would do:

data FP = ForeignPtrObj {-# UNPACK #-} !(IORef [IO ()])
        | MallocPtr (MutableByteArray# RealWorld)
                    {-# UNPACK #-} !(IORef [IO ()])

And in the ForeignPtrObj case, we place the finalizer on the IORef (we
need an atomic object with well-defined allocation semantics on which to
place the finalizer - just placing it on the FP wouldn't do).

Getting rid of ForeignObj# is a serious win.  Deleting code and
improving performance at the same time rarely happens these days!

Would you like to try this out?


More information about the Glasgow-haskell-users mailing list