[reactive] whenE uses much memory

3 views
Skip to first unread message

Conal Elliott

unread,
Aug 24, 2010, 4:17:34 AM8/24/10
to reactive
Oops.  The list's spam-filter tossed this note.

---------- Forwarded message ----------
From: Alexander Foremny <alexande...@googlemail.com>
To: reac...@haskell.org
Date: Tue, 24 Aug 2010 10:14:11 +0200
Subject: whenE uses much memory
Hello,

I am trying to write a simple 2D tower defense game using reactive and
reactive-glut. I am spawning a wave of creeps that walk around the map
and when there are no creeps on the map, I'd like to spawn the next
wave. However, I cannot predict at which time there will be no creeps
on the maps since each creature might move with different speed. To
realize switching anyway I thought I could poll the number of creeps
and switch when the number is zero. With that solution I am having
serious performance problems. Here's the relevant code:

> data World = World { ... }
>
> wave1 :: Behavior World
>
> wave2 :: Behavior World
>
> worldB = wave1 `switcher` fmap (const wave2) (whenE (zeroCreeps wave1) pollE)
>     where pollE = atTimes [1..]
>
> zeroCreeps :: Behavior World -> Behavior Bool

When running worldB from main I can see the program's memory usage
increasing and everything becomes very unresponsive. It seems as if
whenE is accumalating all the occurences of the event. The problem
seems to boil down to snapshot having the same behavior.

> snapshot (pure False) (atTimes [1..])

This piece of code uses very much memory either. Is this due to
reactive being broken (I read that somewhere) or is my solution just
no solution at all?

I am using ghc 6.12.1 with reactive 0.11.5 and reactive-glut 0.1.9.

Regards
Alexander Foremny



Richard Smith

unread,
Aug 24, 2010, 7:26:25 PM8/24/10
to reactive
Hi,

On Tue, August 24, 2010 10:14, Alexander Foremny wrote:
> When running worldB from main I can see the program's memory usage
> increasing and everything becomes very unresponsive. It seems as if whenE
> is accumalating all the occurences of the event. The problem seems to boil
> down to snapshot having the same behavior.
>
>> snapshot (pure False) (atTimes [1..])
>
> This piece of code uses very much memory either. Is this due to
> reactive being broken (I read that somewhere) or is my solution just no
> solution at all?
>
> I am using ghc 6.12.1 with reactive 0.11.5 and reactive-glut 0.1.9.

Shameless plug alert...

I've attached my Haskell debugger hades <http://control.monad.st/> to the
following testcase:

import Control.Applicative
import FRP.Reactive
import FRP.Reactive.LegacyAdapters

foo = snapshot_ (pure (putStrLn "Hi")) (atTimes [0.001,0.002..])
main = adaptE foo >> adaptE foo

Curious as to what is being retained, I did some poking around in the
heap. Here's what I've found:

[... snip looking through backtrace ...]
> liftIO . putStr =<< prettyPrint 140513828164552
$1 = foo/s2fC
> pointers 140513828164552
[Ptr (RemotePtr 8279928),Ptr (RemotePtr 8324640)]
> liftIO . putStr =<< prettyPrint 8279928
$1 = (,) (Imp $134 (exactNB/smWn $138 $133 $134)) (Stepper $141 ((,) (Imp
$140 (exactNB/smWn $138 $139 $140)) (Stepper $141 ((,) (Imp $143
(exactNB/smWn $138 $142 $143)) (Stepper $141 ((,) (Imp $145 (exactNB/smWn
$138 $144 $145)) (Stepper $141 ((,) (Imp $147 (exactNB/smWn $138 $146
$147)) (Stepper $141 ((,) (Imp $149 (exactNB/smWn $138 $148 $149))
(Stepper $141 ((,) (Imp $151 (exactNB/smWn $138 $150 $151)) (Stepper $141
((,) (Imp $153 (exactNB/smWn $138 $152 $153)) ([...snip...]
[...]
$133 = 1.0e-3
$134 = (NoBound $133)
$135 = 'H'
$136 = (FileHandle $80 $81)
$137 = (hPutStr1 $120 ((,) NoBuffering $121) $122 (hPutStr2 $123 $124)
(hPutStr_$s$wa1 $127 $126) (hPutStr_$s$wa $127 $128))
$138 = (<instance field OrdAddBounds_<=> $2 (amb2 (forkIO2 (childHandler1
$24 $25 $26 $27 ($Lr3Ktlvl23 $23))) $31 (catches1 $31) (finally1 $31)
((Handler $32 writeWord64OffPtr1/r1uF):((Handler $131
writeWord64OffPtr1/r1uJ):((Handler (<dict for Exception> $53 $54 ($LrXBa7
$52) $57) (<instance field ShowNonTermination2>/r1uL)):((Handler $132
$Lr1yylvl1/r1uP):((Handler (<dict for Exception> $75 $76 ($LrXVa12 $74)
$79) ($Lr1yylvl1/r1uR (writeWord64OffPtr1/r1uD $136 $123 $137 $129
'"':$130))):$9))))) (SomeException $131 BothBottom) (SomeException $132
DontBother)))
$139 = 2.0e-3
$140 = (NoBound $139)
$141 = (main8 $123 $135:$50:$9 $136 $137)
$142 = 3.0e-3
$143 = (NoBound $142)
$144 = 4.0e-3
$145 = (NoBound $144)
$146 = 5.0e-3
$147 = (NoBound $146)
$148 = 6.0e-3
$149 = (NoBound $148)
$150 = 7.0e-3
$151 = (NoBound $150)
$152 = 8.0e-3
$153 = (NoBound $152)

So (obviously in retrospect), foo is retaining an object of this form:

(Imp (exactNB/smWn (NoBound 1.0e-3)), Stepper main8
(Imp (exactNB/smWn (NoBound 2.0e-3)), Stepper main8 (..., ...)))

Here, main8 looks to be the (putStrLn "Hi") computation.


A slight tweak to the code should sort this out:

foo () = snapshot_ (pure (putStrLn "Hi")) (atTimes [0.001,0.002..])
main = adaptE (foo ()) >> adaptE (foo ())

Now I no longer see the space leak. In hades, I can't even find a
reference to foo (presumably it got inlined out of existence). The event's
list now looks like this (start from $209):

$195 = 25.91600000000869
$196 = (NoBound $195)
$209 = listEG/sigh $210 $211
$210 = (Imp $196 (exactNB/smWn $216 $195 $196))
$211 = <instance field FunctorEventG_fmap>/siFL (withTimeE1 $212) $213
$212 = exactNB1
$213 = listEG/sigh $210 (Stepper () $214)
$214 = <worker for untilE>/sgyB $215 (<worker for untilE>/sfAZ $228 (Imp
$227 (atTimes3 $216)))
$215 = foldr/s2p1 (atTimes1 $216) $217
$216 = (<instance field OrdAddBounds_<=> $204 $201)
$217 = <worker for %>/s8ah $195 25.91700000000869 $218 $219 (<worker for
%>/s3ts $218 $219)
$218 = plusDouble
$219 = minusDouble


I hope this gives you enough insight to be able to fix your code!

Regards,
Richard Smith

_______________________________________________
Reactive mailing list
Reac...@haskell.org
http://www.haskell.org/mailman/listinfo/reactive

Conal Elliott

unread,
Aug 24, 2010, 11:29:37 PM8/24/10
to ric...@metafoo.co.uk, reactive
Richard,

Wow and wow!

I'm going to learn about hades.

   - Conal
Reply all
Reply to author
Forward
0 new messages