Scott Dillard | 16 Dec 21:56

ForeignPtr performance

Hi,

I do a lot of programming with small compound objects, things like 3d
vectors or RGBA tuples for images. For performance reasons, I keep
them in StorableArrays, since there is no way to use these things with
UArrays. (But that's a topic for another thread.)

Some how the notion got into my head that StorableArrays were slow, I
think from old versions of GHC. So I've gotten into the habit of using
withStorableArray and peek/poke to work on my arrays. This, as you can
imagine, is cumbersome. Not only because of the extra typing, but also
because I have to do everything in the IO monad, even if the array is
read-only.

So I'm thinking about writing my own IArray instance using ForeignPtr
for storage and unsafePerformIO for access. I did a little experiment,
comparing

> forM_ [0..lots] $ \i -> withForeignPtr fp $ \p -> pokeElemOff p i i

to

> withForeignPtr fp $ \p -> forM_ [0..lots] $ \i -> pokeElemOff p i i

And there seemed to be no difference in running time, which is great.
So I'm thinking of making unsafeAt something like

> unsafeAt (MyArray fp) i = unsafePerformIO $ withForeignPtr fp $ \p -> peekElemOff p i

My question is: what exactly does GHC.Prim.touch# do? This appears to
(Continue reading)

Bulat Ziganshin | 16 Dec 23:24

Re: ForeignPtr performance

Hello Scott,

Sunday, December 16, 2007, 11:57:33 PM, you wrote:

> My question is: what exactly does GHC.Prim.touch# do? This appears to

it's a no-op (for ghc 6.6+ at least). its only task is to notify ghc
optimizer that data were accessed so it doesn't free the memory

--

-- 
Best regards,
 Bulat                            mailto:Bulat.Ziganshin <at> gmail.com
Simon Marlow | 17 Dec 11:33

Re: ForeignPtr performance

Bulat Ziganshin wrote:
> Hello Scott,
> 
> Sunday, December 16, 2007, 11:57:33 PM, you wrote:
> 
>> My question is: what exactly does GHC.Prim.touch# do? This appears to
> 
> it's a no-op (for ghc 6.6+ at least). its only task is to notify ghc
> optimizer that data were accessed so it doesn't free the memory

Yes, exactly.  touch# generates no code, but it is vitally important 
because if the ForeignPtr is referencing data in the heap (like 
mallocForeignPtrBytes does), it prevents the data from being GC'd before 
the operation completes.

Cheers,
	Simon
Bulat Ziganshin | 17 Dec 12:12

Re[2]: ForeignPtr performance

Hello Simon,

Monday, December 17, 2007, 1:33:19 PM, you wrote:
>>> My question is: what exactly does GHC.Prim.touch# do? This appears to
>> 
>> it's a no-op (for ghc 6.6+ at least). its only task is to notify ghc
>> optimizer that data were accessed so it doesn't free the memory

> Yes, exactly.  touch# generates no code, but it is vitally important 
> because if the ForeignPtr is referencing data in the heap (like 
> mallocForeignPtrBytes does), it prevents the data from being GC'd before
> the operation completes.

a bit more details for Scott:

generated code is like this:

ptr <- unsafeForeignPtrToPtr fptr
yourAction ptr
touch# fptr

without touch, the *last* action where fptr involved is its conversion
to ptr. GHC Runtime (not optimizer as i said) have no idea that ptr
and fptr is the same object, so after conversion it feels free to
dispose object pointed by fptr if GC occurs. this means that during
execution of your action data pointed by fptr/ptr may be suddenly
freed, allocated by other object, bang!

the touch pseudo-action is performed *after* your action and
references fptr again. so Runtime thinks "there is one more usage of
(Continue reading)

Scott Dillard | 17 Dec 16:24

Re: Re[2]: ForeignPtr performance

Thanks for the response guys.

I'm still curious as to the specific mechanism by which a strictly
compile-time function affects the run-time behavior of the GC. Bulat
says that touch# makes the runtime aware that the fptr object is still
in use, but how does it do this if, at runtime, it doesn't do
anything? Does if affect the scheduling of collections? Does it mark
the fptr object with some flag when its allocated? What if, for
example, if I put the touch# behind a branch that is conditional on
run-time values? How would this affect things?

I'm sure the answer to this is detailed and involves a lot of
specifics about GHC that I probably won't grasp, and maybe it isn't
appropriate for the whole list, but if there happens to be a short
answer, or there's a reference you can point me to, I'd appreciate it.

Thanks,
Scott

On Dec 17, 2007 4:12 AM, Bulat Ziganshin <bulat.ziganshin <at> gmail.com> wrote:
> Hello Simon,
>
> Monday, December 17, 2007, 1:33:19 PM, you wrote:
> >>> My question is: what exactly does GHC.Prim.touch# do? This appears to
> >>
> >> it's a no-op (for ghc 6.6+ at least). its only task is to notify ghc
> >> optimizer that data were accessed so it doesn't free the memory
>
> > Yes, exactly.  touch# generates no code, but it is vitally important
> > because if the ForeignPtr is referencing data in the heap (like
(Continue reading)

Simon Marlow | 17 Dec 16:47

Re: ForeignPtr performance

Scott Dillard wrote:
> Thanks for the response guys.
> 
> I'm still curious as to the specific mechanism by which a strictly
> compile-time function affects the run-time behavior of the GC. Bulat
> says that touch# makes the runtime aware that the fptr object is still
> in use, but how does it do this if, at runtime, it doesn't do
> anything? Does if affect the scheduling of collections? Does it mark
> the fptr object with some flag when its allocated? What if, for
> example, if I put the touch# behind a branch that is conditional on
> run-time values? How would this affect things?

It's not as complicated as you think.  touch# takes a single argument, and 
does nothing with it; it's only purpose is to ensure that the value passed 
as its argument is "alive" as far as the rest of the compiler and runtime 
is concerned.

There's no special mechanism at work here: touch# is just like an ordinary 
IO operation, except that its implementation is empty, and the compiler 
cannot use this fact for optimisation purposes.  The compiler therefore 
arranges that the argument to touch# is available, just as it would for any 
other function.

Cheers,
	Simon
Stefan O'Rear | 17 Dec 23:10

Re: ForeignPtr performance

On Mon, Dec 17, 2007 at 02:12:31PM +0300, Bulat Ziganshin wrote:
> Hello Simon,
> 
> Monday, December 17, 2007, 1:33:19 PM, you wrote:
> >>> My question is: what exactly does GHC.Prim.touch# do? This appears to
> >> 
> >> it's a no-op (for ghc 6.6+ at least). its only task is to notify ghc
> >> optimizer that data were accessed so it doesn't free the memory
> 
> > Yes, exactly.  touch# generates no code, but it is vitally important 
> > because if the ForeignPtr is referencing data in the heap (like 
> > mallocForeignPtrBytes does), it prevents the data from being GC'd before
> > the operation completes.
> 
> a bit more details for Scott:
> 
> generated code is like this:
> 
> ptr <- unsafeForeignPtrToPtr fptr
> yourAction ptr
> touch# fptr
> 
> without touch, the *last* action where fptr involved is its conversion
> to ptr. GHC Runtime (not optimizer as i said) have no idea that ptr
> and fptr is the same object, so after conversion it feels free to
> dispose object pointed by fptr if GC occurs. this means that during
> execution of your action data pointed by fptr/ptr may be suddenly
> freed, allocated by other object, bang!

I'd like to elaborate that ptr, as far as the GC is concerned is *not a
(Continue reading)


Gmane