<div dir="ltr">withImage creates intermediate lists, which is probably the main bottleneck. Also, is it any faster if you specialize withImage instead of making it generic in the monad, e.g. withImage :: (Pixel pixel) => Int -> Int -> (Int -> Int -> IO Pixel) -> IO (Image pixel) ?<br>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Mar 20, 2014 at 5:12 AM, Vlatko Basic <span dir="ltr"><<a href="mailto:vlatko.basic@gmail.com" target="_blank">vlatko.basic@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello Cafe,<br>
<br>
JuicyFruite library has two functions for creating images. One is pure "generateImage", and another monadic "withImage".<br>
I run some speed tests, and got the following results in microsecs:<br>
<br>
generateImage = 1.0 us<br>
withImage = 1501241.1 us<br>
<br>
This is the code for both functions, and the full code is at [1].<br>
<br>
generateImage :: forall a. (Pixel a)<br>
=> (Int -> Int -> a) -- ^ Generating function, with `x` and `y` params.<br>
-> Int -- ^ Width in pixels<br>
-> Int -- ^ Height in pixels<br>
-> Image a<br>
generateImage f w h = Image { imageWidth = w, imageHeight = h, imageData = generated }<br>
where compCount = componentCount (undefined :: a)<br>
generated = runST $ do<br>
arr <- M.new (w * h * compCount)<br>
let lineGenerator _ y | y >= h = return ()<br>
lineGenerator lineIdx y = column lineIdx 0<br>
where column idx x | x >= w = lineGenerator idx $ y + 1<br>
column idx x = do<br>
unsafeWritePixel arr idx $ f x y<br>
column (idx + compCount) $ x + 1<br>
<br>
lineGenerator 0 0<br>
V.unsafeFreeze arr<br>
<br>
<br>
withImage :: forall m pixel. (Pixel pixel, PrimMonad m)<br>
=> Int -- ^ Image width<br>
-> Int -- ^ Image height<br>
-> (Int -> Int -> m pixel) -- ^ Generating functions<br>
-> m (Image pixel)<br>
withImage width height pixelGenerator = do<br>
let pixelComponentCount = componentCount (undefined :: pixel)<br>
arr <- M.new (width * height * pixelComponentCount)<br>
let mutImage = MutableImage<br>
{ mutableImageWidth = width<br>
, mutableImageHeight = height<br>
, mutableImageData = arr<br>
}<br>
<br>
let pixelPositions = [(x, y) | y <- [0 .. height-1], x <- [0..width-1]]<br>
sequence_ [pixelGenerator x y >>= unsafeWritePixel arr idx<br>
| ((x,y), idx) <- zip pixelPositions [0, pixelComponentCount ..]]<br>
unsafeFreezeImage mutImage<br>
<br>
<br>
<br>
The measurement times are for functions alone, without loading etc.<br>
The tests were done with same image(s) and same generating function in the same "main", one after another and in both orders, so laziness shouldn't be an issue.<br>
<br>
I'm looking at the code, but can't explain to myself why is the monadic one so, so much slower.<br>
One function is recursive and another uses sequence, but beside that they look quite similar.<br>
<br>
Can someone explain where does such large difference comes from?<br>
<br>
<br>
[1] <a href="http://hackage.haskell.org/package/JuicyPixels-3.1.4.1/docs/src/Codec-Picture-Types.html#withImage" target="_blank">http://hackage.haskell.org/<u></u>package/JuicyPixels-3.1.4.1/<u></u>docs/src/Codec-Picture-Types.<u></u>html#withImage</a><br>
<br>
<br>
Best regards,<br>
<br>
vlatko<br>
<br>
<br>
______________________________<u></u>_________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/<u></u>mailman/listinfo/haskell-cafe</a><br>
</blockquote></div><br></div>