<div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:12.727272033691406px;background-color:rgb(255,255,255)">Just another definition of </span><span style="background-color:rgb(255,255,255);color:rgb(34,34,34);font-family:arial,sans-serif;font-size:12.727272033691406px">calculateSeq:</span></div>
<div><span style="background-color:rgb(255,255,255);color:rgb(34,34,34);font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:12.727272033691406px;background-color:rgb(255,255,255)">calculateSeq = zipWith ($) (cycle [sin,cos]) . map sqrt</span><br>
<br><br><div class="gmail_quote">2012/11/15 Janek S. <span dir="ltr">&lt;<a href="mailto:fremenzone@poczta.onet.pl" target="_blank">fremenzone@poczta.onet.pl</a>&gt;</span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">&gt; Do you really mean to calculate the &#39;sin . sqrt&#39; of just the head of the list, or do you mean:<br>
&gt; calculateSeq = map (sin . sqrt)   ?<br>
</div>Argh.. of course not! That&#39;s what you get when you code in the middle of a night. But in my code I<br>
will not be able to use map because elements will be processed in pairs, so let&#39;s say that my<br>
sequential function looks like this:<br>
<div class="im"><br>
calculateSeq :: [Double] -&gt; [Double]<br>
calculateSeq [] = []<br>
</div>calculateSeq [x] = [sin . sqrt $ x]<br>
calculateSeq (x:y:xs) = (sin . sqrt $ x) : (cos . sqrt $ y) : calculateSeq xs<br>
<br>
&gt; I don&#39;t think there&#39;s a memory leak. It looks more like you&#39;re just<br>
&gt; allocating much more than is sane for such a simple function.<br>
&gt; On a recent processor, sin . sqrt is two instructions. Meanwhile, you have<br>
&gt; a list of (boxed?) integers being split up, then recombined. That&#39;s bound<br>
&gt; to hurt the GC.<br>
I am not entirely convinced that my idea of using eval+strategies is bound to be slow, because<br>
there are functions like parListChunk that do exactly this: split the list into chunks, process<br>
them in parallel and then concatenate the result. Functions in Control.Parallel.Strategies were<br>
designed to deal with list so I assume it is possible to process lists in parallel without GC<br>
problems. However I do not see a way to apply these functions in my setting where elements of<br>
lists are processed in pairs, not one at a time (parList and parMap will not do). Also, working<br>
on a list of tuples will not do.<br>
<br>
&gt; Also, you might want to configure criterion to GC between<br>
&gt; runs. That might help.<br>
The -g flag passed to criterion executable does that.<br>
<br>
&gt; What I&#39;d suggest doing instead, is breaking the input into chucks of, say,<br>
&gt; 1024, and representing it with a [Vector]. Then, run your sin.sqrt&#39;s on<br>
&gt; each vector in parallel. Finally, use Data.Vector.concat to combine your<br>
&gt; result.<br>
As stated in my post scriptum I am aware of that solution :) Here I&#39;m trying to figure what am I<br>
doing wrong with Eval.<br>
<br>
Thanks!<br>
Janek<br>
<br>
&gt;<br>
&gt; Hope that helps,<br>
&gt;   - Clark<br>
<div class="im HOEnZb">&gt;<br>
&gt; On Wed, Nov 14, 2012 at 4:43 PM, Janek S. &lt;<a href="mailto:fremenzone@poczta.onet.pl">fremenzone@poczta.onet.pl</a>&gt; wrote:<br>
&gt; &gt; Dear Haskellers,<br>
&gt; &gt;<br>
&gt; &gt; I am reading Simon Marlow&#39;s tutorial on parallelism and I have problems<br>
&gt; &gt; with correctly using Eval<br>
&gt; &gt; monad and Strategies. I *thought* I understand them but after writing<br>
&gt; &gt; some code it turns out that<br>
&gt; &gt; obviously I don&#39;t because parallelized code is about 20 times slower.<br>
&gt; &gt; Here&#39;s a short example<br>
&gt; &gt; (code + criterion benchmarks):<br>
&gt; &gt;<br>
&gt; &gt; {-# LANGUAGE BangPatterns #-}<br>
&gt; &gt; module Main where<br>
&gt; &gt;<br>
&gt; &gt; import Control.Parallel.Strategies<br>
&gt; &gt; import Criterion.Main<br>
&gt; &gt;<br>
&gt; &gt; main :: IO ()<br>
&gt; &gt; main = defaultMain [<br>
&gt; &gt;         bench &quot;Seq&quot; $ nf calculateSeq xs<br>
&gt; &gt;       , bench &quot;Par&quot; $ nf calculatePar xs ]<br>
&gt; &gt;     where xs = [1..16384]<br>
&gt; &gt;<br>
</div><div class="im HOEnZb">&gt; &gt; calculateSeq :: [Double] -&gt; [Double]<br>
&gt; &gt; calculateSeq [] = []<br>
&gt; &gt; calculateSeq (x:xs) = (sin . sqrt $ x) : xs<br>
&gt; &gt;<br>
</div><div class="HOEnZb"><div class="h5">&gt; &gt; calculatePar :: [Double] -&gt; [Double]<br>
&gt; &gt; calculatePar xss = runEval $ go xss<br>
&gt; &gt;     where<br>
&gt; &gt;       go :: Strategy [Double]<br>
&gt; &gt;       go [] = return []<br>
&gt; &gt;       go xs = do<br>
&gt; &gt;           lsh &lt;- (rpar `dot` rdeepseq) $ calculateSeq as<br>
&gt; &gt;           lst &lt;- go bs<br>
&gt; &gt;           return (lsh ++ lst)<br>
&gt; &gt;           where<br>
&gt; &gt;             !(as, bs) = splitAt 8192 xs<br>
&gt; &gt;<br>
&gt; &gt; Compiling and running with:<br>
&gt; &gt;<br>
&gt; &gt; ghc -O2 -Wall -threaded -rtsopts -fforce-recomp -eventlog evalleak.hs<br>
&gt; &gt; ./evalleak -oreport.html -g +RTS -N2 -ls -s<br>
&gt; &gt;<br>
&gt; &gt; I get:<br>
&gt; &gt;<br>
&gt; &gt; benchmarking Seq<br>
&gt; &gt; mean: 100.5990 us, lb 100.1937 us, ub 101.1521 us, ci 0.950<br>
&gt; &gt; std dev: 2.395003 us, lb 1.860923 us, ub 3.169562 us, ci 0.950<br>
&gt; &gt;<br>
&gt; &gt; benchmarking Par<br>
&gt; &gt; mean: 2.233127 ms, lb 2.169669 ms, ub 2.296155 ms, ci 0.950<br>
&gt; &gt; std dev: 323.5201 us, lb 310.2844 us, ub 344.8252 us, ci 0.950<br>
&gt; &gt;<br>
&gt; &gt; That&#39;s a hopeless result. Looking at the spark allocation everything<br>
&gt; &gt; looks fine:<br>
&gt; &gt;<br>
&gt; &gt; SPARKS: 202 (202 converted, 0 overflowed, 0 dud, 0 GC&#39;d, 0 fizzled)<br>
&gt; &gt;<br>
&gt; &gt; But analyzing eventlog with ThreadScope I see that parallel function<br>
&gt; &gt; spends most of the time doing<br>
&gt; &gt; garbage collection, which suggests that I have a memory leak somewhere. I<br>
&gt; &gt; suspected that problem<br>
&gt; &gt; might be caused by appending two lists together in the parallel<br>
&gt; &gt; implementation, but replacing<br>
&gt; &gt; this with difference lists doesn&#39;t help. Changing granularity (e.g.<br>
&gt; &gt; splitAt 512) also brings no<br>
&gt; &gt; improvement. Can anyone point me to what am I doing wrong?<br>
&gt; &gt;<br>
&gt; &gt; Janek<br>
&gt; &gt;<br>
&gt; &gt; PS. This is of course not a real world code - I know that I&#39;d be better<br>
&gt; &gt; of using unboxed data<br>
&gt; &gt; structures for doing computations on Doubles.<br>
&gt; &gt;<br>
&gt; &gt; _______________________________________________<br>
&gt; &gt; Haskell-Cafe mailing list<br>
&gt; &gt; <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
&gt; &gt; <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</div></div></blockquote></div><br>