[Haskell-cafe] some newbie FFI questions

Alastair Reid alastair at reid-hoffmann.net
Thu Jul 1 07:39:29 EDT 2004


> 1. Speed: I'm reading in a 2000x1500 pixel image, and have defined a
>    Pixel type like this:
>
> data Pixel a = Pixel !a !a !a deriving Show
>
> [with a==Float being a typical instantiation]

For images of this size, I'd recommend using a different datatype because:

1) Each Pixel Float will take at least 56 bytes to store instead of 
   the 12 you expect in C.
   An array of pixels will require 4 bytes to point to each pixel bringing
   the total cost to 60 bytes or 180M instead of 36M per image.

   (I'm adding 2 words of GC-related header which I think is accurate
   for GHC.)

2) Access will be inefficient: 2 levels of indirection to access each field.
   GHC may also check that a pixel and a field are evaluated on each
   dereference so expect 4 memory reads and 2 branches per field access.

3) Memory locality is a major factor when processing images of this 
   size.  A conventional C-style array gives good locality for
   either columns or rows while a Haskell array of Pixel will give
   terrible locality because the garbage collector will keep 
   moving things around without any thoughts about locality.

4) Most image processing operations can be coded up using 1 and 2-dimensional
   array variants of the familiar list operations: map, fold{l,r}, scan{l,r}.

   This lets you hide details of the representation from most
   code manipulating images and to match the pattern of access
   to the memory layout of the image to improve cache locality.

Overall, I'd probably use an unboxed Haskell array.  This would let you get a 
memory layout (and memory consumption) close to the normal C layout.  I'd use 
access functions to hide the boxing/unboxing and I'd write some 
map/fold/scan-like functions to operate on the arrays.

In some cases, I'd leave the object in the C world and access it using FFI 
functions and using various convolution operators written in C.  This works 
great if you already have a good image processing library, you're not 
interested in writing too many new image mangling functions of your own, and 
costs of copying the image from C to Haskell (and back again, no doubt), are 
excessive.  (I did this some years ago in a real time visual tracking system 
that had to deal with 640x512 images coming in at the rate of 30 frames per 
second.)

Hope this helps,

--
Alastair Reid


More information about the Haskell-Cafe mailing list