[Fwd: Memory corruption issues when using newAlignedPinnedByteArray, GC kicking in?]

All, I sent this mail to Haskell Cafe earlier today, and was pointed [1] at this list. As such... Any help/advice would be greatly appreciated! Thanks, Nicolas [1] http://www.haskell.org/pipermail/haskell-cafe/2012-July/102242.html -------- Forwarded Message --------
From: Nicolas Trangez
To: haskell-cafe@haskell.org Cc: Roman Leshchinskiy Subject: Memory corruption issues when using newAlignedPinnedByteArray, GC kicking in? Date: Tue, 10 Jul 2012 19:20:01 +0200 All,
While working on my vector-simd library, I noticed somehow memory I'm using gets corrupted/overwritten. I reworked this into a test case, and would love to get some help on how to fix this.
Previously I used some custom FFI calls to C to allocate aligned memory, which yields correct results, but this has a significant (+- 10x) performance impact on my benchmarks. Later on I discovered the newAlignedPinnedByteArray# function, and wrote some code using this.
Here's what I did in the test case: I created an MVector instance, with the exact same implementation as vector's Data.Vector.Storable.Mutable.MVector instance, except for basicUnsafeNew where I pass one more argument to mallocVector [1].
I also use 3 different versions of mallocVector (depending on compile-time flags):
mallocVectorOrig [2]: This is the upstream version, discarding the integer argument I added.
Then here's my first attempt, very similar to the implementation of mallocPlainForeignPtrBytes [3] at [4] using GHC.* libraries.
Finally there's something similar at [5] which uses the 'primitive' library.
The test case creates vectors of increasing size, then checks whether they contain the expected values. For the default implementation this works correctly. For both others it fails at some random size, and the values stored in the vector are not exactly what they should be.
I don't understand what's going on here. I suspect I lack a reference (or something along those lines) so GC kicks in, or maybe the buffer gets relocated, whilst it shouldn't.
Basically I'd need something like
GHC.ForeignPtr.mallocPlainAlignedForeignPtrBytes :: Int -> Int -> IO (ForeignPtr a)
Thanks,
Nicolas
[1] https://gist.github.com/3084806#LC37 [2] https://gist.github.com/3084806#LC119 [3] http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/GHC-For... [4] https://gist.github.com/3084806#LC100 [5] https://gist.github.com/3084806#LC81

On 10/07/2012 23:03, Nicolas Trangez wrote:
All,
I sent this mail to Haskell Cafe earlier today, and was pointed [1] at this list. As such...
Any help/advice would be greatly appreciated!
It looks like you're making a ForeignPtr from the Addr# or Ptr that points to the contents of the ByteArray#. Since this ForeignPtr doesn't keep the original ByteArray# alive, the GC will collect it. You need to keep a reference to the ByteArray# too. Basically you need a version of mallocForeignPtrBytes that has supports alignment. Unfortunately it's not possible to write one because the internals of ForeignPtrContents are not exported - we had a recent ticket about that (http://hackage.haskell.org/trac/ghc/ticket/7012) and in 7.6.1 we will export the necessary internals. If you want we could also add mallocForeignPtrAlignedBytes - please send a patch. Cheers, Simon
Thanks,
Nicolas
[1] http://www.haskell.org/pipermail/haskell-cafe/2012-July/102242.html
-------- Forwarded Message --------
From: Nicolas Trangez
To: haskell-cafe@haskell.org Cc: Roman Leshchinskiy Subject: Memory corruption issues when using newAlignedPinnedByteArray, GC kicking in? Date: Tue, 10 Jul 2012 19:20:01 +0200 All,
While working on my vector-simd library, I noticed somehow memory I'm using gets corrupted/overwritten. I reworked this into a test case, and would love to get some help on how to fix this.
Previously I used some custom FFI calls to C to allocate aligned memory, which yields correct results, but this has a significant (+- 10x) performance impact on my benchmarks. Later on I discovered the newAlignedPinnedByteArray# function, and wrote some code using this.
Here's what I did in the test case: I created an MVector instance, with the exact same implementation as vector's Data.Vector.Storable.Mutable.MVector instance, except for basicUnsafeNew where I pass one more argument to mallocVector [1].
I also use 3 different versions of mallocVector (depending on compile-time flags):
mallocVectorOrig [2]: This is the upstream version, discarding the integer argument I added.
Then here's my first attempt, very similar to the implementation of mallocPlainForeignPtrBytes [3] at [4] using GHC.* libraries.
Finally there's something similar at [5] which uses the 'primitive' library.
The test case creates vectors of increasing size, then checks whether they contain the expected values. For the default implementation this works correctly. For both others it fails at some random size, and the values stored in the vector are not exactly what they should be.
I don't understand what's going on here. I suspect I lack a reference (or something along those lines) so GC kicks in, or maybe the buffer gets relocated, whilst it shouldn't.
Basically I'd need something like
GHC.ForeignPtr.mallocPlainAlignedForeignPtrBytes :: Int -> Int -> IO (ForeignPtr a)
Thanks,
Nicolas
[1] https://gist.github.com/3084806#LC37 [2] https://gist.github.com/3084806#LC119 [3] http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/GHC-For... [4] https://gist.github.com/3084806#LC100 [5] https://gist.github.com/3084806#LC81
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

On Wed, 2012-07-11 at 09:50 +0100, Simon Marlow wrote:
On 10/07/2012 23:03, Nicolas Trangez wrote:
All,
I sent this mail to Haskell Cafe earlier today, and was pointed [1] at this list. As such...
Any help/advice would be greatly appreciated!
It looks like you're making a ForeignPtr from the Addr# or Ptr that points to the contents of the ByteArray#. Since this ForeignPtr doesn't keep the original ByteArray# alive, the GC will collect it. You need to keep a reference to the ByteArray# too.
Even though I suspected this and it's blatantly obvious, I failed to recognize the ForeignPtr as returned by mallocPlainForeignPtrBytes keeps the reference. Stupid me. Thanks.
Basically you need a version of mallocForeignPtrBytes that has supports alignment. Unfortunately it's not possible to write one because the internals of ForeignPtrContents are not exported - we had a recent ticket about that (http://hackage.haskell.org/trac/ghc/ticket/7012) and in 7.6.1 we will export the necessary internals. If you want we could also add mallocForeignPtrAlignedBytes - please send a patch.
http://hackage.haskell.org/trac/ghc/ticket/7067 Thanks, Nicolas
participants (2)
-
Nicolas Trangez
-
Simon Marlow