Hi Folks, I'd like to propose two new functions for the ForeignPtr interface: mallocForeignPtr :: Storable a => IO (ForeignPtr a) mallocForeignPtrBytes :: Int -> IO (ForeignPtr a) (the names can change, of course). The implementations are trivial in terms of existing things: mallocForeignPtr = do p <- malloc newForeignPtr p free mallocForeignPtrBytes size = do p <- mallocBytes size newForeignPtr p free However, in GHC we can provide a far more efficient implementation by using pinned ByteArray#s, avoiding the overhead of malloc()/free() and the finalizer. Since this is quite a common idiom when using ForeignPtrs, I think it's a good case to optimise. I did a little test, and using the above functions gave a 6x improvement in a small example which just repeatedly allocated a new ForeignPtr and passed it to a foreign function. The GHC implementation is to extend the ForeignPtr type like this: data ForeignPtr a = ForeignPtr ForeignObj# | MallocPtr (MutableByteArray# RealWorld) so it does in theory slow down normal ForeignPtrs slightly, but I didn't measure any difference in the limited tests I did. Comments? Cheers, Simon
Can you achieve the same performance gain by adding some rewrite rules? -- Alastair
"Simon Marlow" <simonmar@microsoft.com> wrote,
I'd like to propose two new functions for the ForeignPtr interface:
mallocForeignPtr :: Storable a => IO (ForeignPtr a) mallocForeignPtrBytes :: Int -> IO (ForeignPtr a)
(the names can change, of course). The implementations are trivial in terms of existing things:
mallocForeignPtr = do p <- malloc newForeignPtr p free
mallocForeignPtrBytes size = do p <- mallocBytes size newForeignPtr p free
However, in GHC we can provide a far more efficient implementation by using pinned ByteArray#s, avoiding the overhead of malloc()/free() and the finalizer. Since this is quite a common idiom when using ForeignPtrs, I think it's a good case to optimise.
I did a little test, and using the above functions gave a 6x improvement in a small example which just repeatedly allocated a new ForeignPtr and passed it to a foreign function.
The GHC implementation is to extend the ForeignPtr type like this:
data ForeignPtr a = ForeignPtr ForeignObj# | MallocPtr (MutableByteArray# RealWorld)
so it does in theory slow down normal ForeignPtrs slightly, but I didn't measure any difference in the limited tests I did.
I vaguely remeber that in the context of the withForeignPtr discussion we where once trying to achieve some similar effect (but couldn't come up with something that would work). Do you remember? Does this, then, effectively solve this old problem? Wouldn't you want newXXX and withXXX variants of the above, too? Cheers, Manuel
Hi Folks, I'd like to propose two new functions for the ForeignPtr interface:
I'm a bit uneasy about this. It seems like decisions made on technological grounds (i.e., because they enable an optimization) tend to date rather quickly because the technology tends to change too. The functions may cover a fairly common case of using ForeignPtrs (though I've never used ForeignObjs or MallocPtrs that way) - but most code doesn't use ForeignPtrs so it's a common case of an uncommon thing. It'd be a bit more compelling if the combos made things easier (as the withFoo functions do) or raised the level of abstraction. I'm inclined to say: add it to GHC for now and prod us again once a decent body of examples builds up. -- Alastair Reid alastair@reid-consulting-uk.ltd.uk Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/
participants (3)
-
Alastair Reid -
Manuel M T Chakravarty -
Simon Marlow