[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