= Examples

== Requirements

1. lib dir

All of the examples assume the lib directory containing the gem sources is one directory up from the location of the example.

2. Installed libzmq library

The ZeroMQ C libraries need to be downloaded, compiled and installed separately from the gem. Please see http://www.zeromq.org/area:download for links to the downloadable files along with some simple installation instructions. Also, be sure to check the FAQ if you run into problems with compiling.

It is possible to install the libzmq* files directly into the gem in the ext/ directory. This directory is checked for loadable libraries first before it falls back to checking the system paths.

3. One terminal window

ZeroMQ is used to build network applications. At minimum, there is a "client" application and a "server" application that talk to each other over the network, IPC or an internal thread queue. Several of the examples start the client and server components within separate threads or use the polling mechanism to interleave I/O operations amongst several sockets. A few examples need two terminal windows because the client and server code is in separate files (local_lat.rb/remote_lat.rb, local_throughput.rb/remote_throughput.rb).

== Latency Test

The examples include a latency performance test. The example sets up a pair of REQ/REP sockets and send a message back and forth as fast as possible. There is only a single message in flight at any given moment. The time required to send the message the requested number of times determines overall single-message latency for this type of socket.

==== Files

* latency_measurement.rb

==== Arguments

The remote_lat.rb program takes 3 arguments:

  [link_address]  Requires a transport string of the format "transport"://"endpoint"<:><port>. For example, tcp://127.0.0.1:5555
  
  [message size] Size of each message measured in bytes. Allowable range is 1 to 2^(64-1).
  
  [message count] The number of round-trips used for the latency measurements. Allowable range is 1 to 2^(64-1).

  
==== Execution

In an open terminal window, execute the latency_measurement.rb file.

  % ruby latency_measurement.rb tcp://127.0.0.1:5555 1024 100_000

On a relatively new system, it can run 100k messages in under 30 seconds. When complete, the program prints out a few statistics and exits.

Running with a larger "message count" will yield a more accurate latency measurement since nearly all Ruby runtimes require a little warm up time to hit their stride. I recommend 100k as a minimum while 10 million is better for determining a true measure.

On a desktop computer purchased in 2007, all of the Ruby runtimes report a latency of approximately 110 microseconds per message. For comparison, the pure C latency test reports approximately 88 microseconds of latency.



== Throughput Test

The examples include a throughput performance test. The example sets up a pair of PUB/SUB sockets and publish messages as fast as possible to a subscriber listening for every message. The publisher can send much faster than the subscriber can retrieve messages. 

Since the publisher completes first, the program waits for all subscribers to exit before closing the PUB socket. This is necessary because all enqueued messages are discarded when the socket is closed.

The subscriber prints some statistics when it exits.

==== Files

* throughput_measurement.rb

==== Arguments

The throughput_measurement.rb program takes 3 arguments:

  [link_address]  Requires a transport string of the format "transport"://"endpoint"<:><port>. For example, tcp://127.0.0.1:5555
  
  [message size] Size of each message measured in bytes. Allowable range is 1 to 2^(64-1).
  
  [message count] The number of round-trips used for the latency measurements. Allowable range is 1 to 2^(64-1).


==== Execution

In an open terminal, execute the throughput_measurement.rb script.

  % ruby throughput_measurement.rb tcp://127.0.0.1:5555 1024 100_000

On a relatively new system, it can run 100k messages in under 10 seconds. When complete, the program prints out a few statistics and exits.

Running with a larger "message count" will yield a more accurate latency measurement since nearly all Ruby runtimes require a little warm up time to hit their stride. I recommend 100k as a minimum while 1 million is better for determining a true measure. NOTE! The publisher can send much faster than the subscriber so the publisher's queue will grow very rapidly in RAM. For 1 million messages (or more) this can consume hundreds of megabytes or gigabytes of RAM. On my system, sending 10 million messages requires 10 GB of RAM before the subscriber can catch up.

On a desktop computer purchased in 2007, all of the Ruby runtimes report a throughput of approximately 150k messages per second. For comparison, the pure C throughput test reports approximately 260k messages per second.



== Poll

For a reasonable example of using zmq_poll(), take a look at the reqrep_poll.rb program. It illustrates the use of zmq_poll(), as wrapped by the Ruby library, for detecting and responding to read and write events recorded on sockets. It also shows how to use ZMQ::NO_BLOCK/ZMQ::DONTWAIT for non-blocking send and receive.

==== Files

* reqrep_poll.rb

==== Arguments

None.

==== Execution

This program is completely self-contained, so it only requires a single terminal window for execution.

  % ruby reqrep_poll.rb

