Subject:
[ruby-ffi] Re: Turning a Struct into its binary representation
From:
Wayne Meissner
Date:
5/7/11 10:27 PM
To:
ruby-ffi@googlegroups.com



On Friday, 6 May 2011 23:39:09 UTC+10, candlerb wrote:
(1) What's the most direct way to get the binary representation of
'f'? Eventually I found:

    f.pointer.get_bytes(0, Foo.size)

This was made a bit awkward because I was looking for 'read' methods,
and there was no 'read_bytes'. It turns out there are a handful for
methods which have "get" but no "read" equivalent:

Some of those (the float32/float64 ones) are only there for backwards compat - get/read_float and get/read_double are the preferred  way).

The missing read_bytes and read_array_of_string will be fixed shortly.

(2) Suppose I want to create a packed structure which is a contiguous
array of Foos. I found an example for InlineArrayOfStructs, but not
how to make an array of structs at the top level.

Have a read of:

https://groups.google.com/d/msg/ruby-ffi/2JxDNdXlcTc/GP2gbjtatqAJ

If you can figure it out from that thread, *please* add a wiki page on it.
 
(3) What's the difference between FFI::Pointer, FFI::MemoryPointer and
FFI::Buffer?

This one is a bit tricky to explain.  

tl;dr - use FFI::MemoryPointer and you code will work fine, but may be a little slower on JRuby than it need be.

Long, hand wavy explanation:  Its very VM dependent whether Buffer works better than Pointer in certain circumstances.  

On JRuby, there are two types of memory used by FFI - native memory at a fixed address (i.e. what a Pointer or MemoryPointer refers to), and the memory where ruby objects themselves are allocated (e.g. Fixnum, String, Buffer).  This latter type is very fast to allocate and access from ruby code, but needs to be copied to/from temporary native memory to be accessed from native code, as the JVM does not provide direct access to the memory contents.

On the other hand, FFI::MemoryPointer, whilst it can be accessed directly by native code, and still reasonably fast from ruby code, has horrendous management overhead on JRuby - its just the way GC is tuned on the VM - java objects are very fast and lightweight, but the overhead of managing the lifecycle of native objects is huge.

One obvious use where FFI::Buffer is a clear win, is for small, single-use native memory areas (e.g. the 'length' pointer in getsockopt).  It is up to an order of magnitude (10x) faster to use a FFI::Buffer which gets copied to/from native memory for that single use, than it is to use a FFI::MemoryPointer and handle the allocation/release management overhead.

But, as you can see, its not very obvious to the casual programmer when using FFI::Buffer will lead to a speed improvement, which is why I usually say "just use FFI::MemoryPointer and be happy" these days.