<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>