Purpose
The official ruby bindings from the 0mq project only work with ruby runtimes that support the full C extension API. At this time that pretty much limits that gem to MRI 1.8.x and 1.9.x. The JRuby and Rubinius projects are fleshing out their C extension support so the official zmq gem may run on those platforms now.
This gem adds FFI bindings so that any ruby runtime supporting the latest FFI API will work. At this time the minimum versions that will work with the FFI bindings are MRI 1.8.7-p249, MRI 1.9.1-p376, JRuby 1.5 and Rubinius (commit df9f7467).
Performance Notes
Using Ruby-FFI adds a little bit of overhead to C function calls since the binding itself is written in ruby with some C or Java helpers behind the scenes. I have made every effort to reduce this overhead to a minimum.
For example, the send and recv method calls return a Message class**. This class contains an FFI::Struct which mimics the zmq_msg_t struct. It provides methods for returning an FFI::MemoryPointer pointing to the data buffer as well as a call to return the size of that buffer. Due to this wrapping, no copying of the zmq_msg_t is performed.
To process the data buffer, I recommend subclassing Message and lazily copy data from the buffer as necessary. Reference the FFI Wiki for information on how to work with FFI::MemoryPointer and FFI::Struct.
I ran a battery of tests on my desktop Mac. Your timings will definitely vary but the relative performance of each runtime should be roughly the same.
The latency test was performed on a lightly loaded machine using two shell terminals. Note that I used the "zerocopy" variant of the latency test; for the FFI bindings this means the message is not copied before being echoed back. This is an important note because the zmq gem does not have a similar mode. It turns every message into a Ruby string so it's doing more work.
Doing 10 million rounds gave the most stable results. Any shorter and the jitter was above 5 usec; doing more than 10 million didn't reduce the jitter.
% ruby remote_lat_zerocopy.rb tcp://127.0.0.1:5500 1024 10_000_000
and
% ruby local_lat_zerocopy.rb tcp://127.0.0.1:5500 1024 10_000_000
The average of 5 runs is posted below. This is an apples-to-oranges test.
| Language Runtime | Bindings | Mean usecs | Message Management |
| C | C | 88 | manual |
| MRI 1.9.2-p0 | zmq 2.0.7.1 | N/A | manual |
| MRI 1.9.2-p0 | ffi-rzmq 0.6.0 | 96 | manual |
| JRuby 1.5.1 —server | ffi-rzmq 0.6.0 | 95 | manual |
| Rubinius 1.0.1 df9f7467 | ffi-rzmq 0.6.0 | 91 | manual |
Doing an apples-to-apples test (where the FFI bindings copy the message string) results in higher numbers.
| Language Runtime | Bindings | Mean usecs | Message Management |
| C | C | N/A | manual |
| MRI 1.9.2-p0 | zmq 2.0.7.1 | 102 | GC |
| MRI 1.9.2-p0 | ffi-rzmq 0.6.0 | 125 | GC |
| JRuby 1.5.1 —server | ffi-rzmq 0.6.0 | 120 | GC |
| Rubinius 1.0.1 df9f7467 | zmq 2.0.7.1 | 107 | GC |
| Rubinius 1.0.1 df9f7467 | ffi-rzmq 0.6.0 | 109 | GC |
** Returning a {{Message}} is different from the 0mq ruby
bindings which take and return strings. Use ZMQ::Socket#send_string
and ZMQ::Socket#recv_string to get the old behavior.
I don't think any earth-shattering conclusion can be drawn from these results. I did note that Rubinius consistently showed the lowest FFI overhead of any runtime. Also, MRI using the C extension is hard to beat on a fair test.
Source Code
http://github.com/chuckremes/ffi-rzmq
Build and installation
Install the latest ØMQ release from here:
http://www.zeromq.org/area:download
There are two options for installing the gem.
1. Install from rubygems.org via gem install.
% gem install ffi-rzmq
2. Install the latest master source from github.
$ git clone http://github.com/chuckremes/ffi-rzmq.git
$ cd ffi-rzmq
$ gem build ffi-rzmq.gemspec
$ gem install ffi-rzmq-*.gem
You may have to run the last command with sudo if you do not have permission to install to a protected system directory.
Windows
The steps for installing the gem are exactly the same. Building and installing the 0mq library may take a few extra steps. Be sure to reference the instructions on the 0mq download page.
Documentation
The gem includes some very basic rdoc. While the docs are rather sparse at the moment, be sure to check the examples gem directory. Also, the 0mq C API documentation is a good reference. These ruby bindings mimic that API exactly though a few extra sugarings have been tossed in.
Also, be sure to read the ZeroMQ User Guide. The text is growing almost daily with new examples and clearer explanations.
Learn by Example
The learn ruby ZeroMQ project uses ffi-rzmq , providing what is currently the largest set of examples using the ffi-rzmq gem.
http://github.com/andrewvc/learn-ruby-zeromq
Test Suite
Run the examples. Requires rspec, rake and bones to be installed.
% rake spec
Bug Reporting
If you encounter problems please fill a bug report at:
http://github.com/chuckremes/ffi-rzmq/issues
or write an e-mail to:
cremes AT mac DOT com
Mailing List
Discussions about this language binding take place on the general zeromq-dev list.
