ffi-rzmq 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/AUTHORS.txt +1 -0
  2. data/History.txt +35 -0
  3. data/README.rdoc +48 -15
  4. data/Rakefile +7 -2
  5. data/examples/README.rdoc +21 -76
  6. data/examples/{local_lat.rb → v2api/local_lat.rb} +27 -12
  7. data/examples/v2api/local_lat_poll.rb +66 -0
  8. data/examples/{local_throughput.rb → v2api/local_throughput.rb} +24 -9
  9. data/examples/v2api/publish_subscribe.rb +82 -0
  10. data/examples/{remote_lat.rb → v2api/remote_lat.rb} +26 -8
  11. data/examples/v2api/remote_throughput.rb +39 -0
  12. data/examples/v2api/reqrep_poll.rb +62 -0
  13. data/examples/v2api/request_response.rb +40 -0
  14. data/examples/v2api/throughput_measurement.rb +138 -0
  15. data/examples/v3api/local_lat.rb +59 -0
  16. data/examples/v3api/local_lat_poll.rb +66 -0
  17. data/examples/v3api/local_throughput.rb +65 -0
  18. data/examples/v3api/publish_subscribe.rb +82 -0
  19. data/examples/v3api/remote_lat.rb +71 -0
  20. data/examples/v3api/remote_throughput.rb +47 -0
  21. data/examples/v3api/reqrep_poll.rb +62 -0
  22. data/examples/v3api/request_response.rb +40 -0
  23. data/examples/v3api/throughput_measurement.rb +166 -0
  24. data/ext/README +5 -0
  25. data/ffi-rzmq.gemspec +4 -4
  26. data/lib/ffi-rzmq.rb +4 -1
  27. data/lib/ffi-rzmq/constants.rb +178 -0
  28. data/lib/ffi-rzmq/context.rb +61 -45
  29. data/lib/ffi-rzmq/device.rb +22 -9
  30. data/lib/ffi-rzmq/exceptions.rb +0 -98
  31. data/lib/ffi-rzmq/libc.rb +19 -0
  32. data/lib/ffi-rzmq/libzmq.rb +188 -0
  33. data/lib/ffi-rzmq/message.rb +33 -40
  34. data/lib/ffi-rzmq/poll.rb +49 -52
  35. data/lib/ffi-rzmq/socket.rb +902 -392
  36. data/lib/ffi-rzmq/util.rb +101 -0
  37. data/spec/context_spec.rb +47 -21
  38. data/spec/device_spec.rb +78 -58
  39. data/spec/message_spec.rb +90 -12
  40. data/spec/multipart_spec.rb +162 -0
  41. data/spec/nonblocking_recv_spec.rb +325 -0
  42. data/spec/pushpull_spec.rb +95 -34
  43. data/spec/reqrep_spec.rb +55 -20
  44. data/spec/socket_spec.rb +353 -204
  45. data/spec/spec_helper.rb +46 -3
  46. data/version.txt +1 -1
  47. metadata +91 -66
  48. data/examples/local_lat_poll.rb +0 -54
  49. data/examples/local_lat_zerocopy.rb +0 -24
  50. data/examples/publish_subscribe.rb +0 -52
  51. data/examples/remote_lat_zerocopy.rb +0 -35
  52. data/examples/remote_throughput.rb +0 -27
  53. data/examples/reqrep_poll.rb +0 -49
  54. data/examples/request_response.rb +0 -23
  55. data/lib/ffi-rzmq/wrapper.rb +0 -121
  56. data/lib/ffi-rzmq/zmq.rb +0 -198
@@ -0,0 +1,59 @@
1
+ #
2
+ # Copyright (c) 2007-2010 iMatix Corporation
3
+ #
4
+ # This file is part of 0MQ.
5
+ #
6
+ # 0MQ is free software; you can redistribute it and/or modify it under
7
+ # the terms of the Lesser GNU General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # 0MQ is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # Lesser GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the Lesser GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
20
+
21
+ if ARGV.length < 3
22
+ puts "usage: ruby local_lat.rb <connect-to> <message-size> <roundtrip-count>"
23
+ exit
24
+ end
25
+
26
+ bind_to = ARGV[0]
27
+ message_size = ARGV[1].to_i
28
+ roundtrip_count = ARGV[2].to_i
29
+
30
+ def assert(rc)
31
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
32
+ end
33
+
34
+ begin
35
+ ctx = ZMQ::Context.new
36
+ s = ctx.socket(ZMQ::REP)
37
+ rescue ContextError => e
38
+ STDERR.puts "Failed to allocate context or socket!"
39
+ raise
40
+ end
41
+
42
+ assert(s.setsockopt(ZMQ::LINGER, 100))
43
+ assert(s.setsockopt(ZMQ::RCVHWM, 100))
44
+ assert(s.setsockopt(ZMQ::SNDHWM, 100))
45
+
46
+ assert(s.bind(bind_to))
47
+
48
+ roundtrip_count.times do
49
+ string = ''
50
+ assert(s.recv_string(string, 0))
51
+
52
+ raise "Message size doesn't match, expected [#{message_size}] but received [#{string.size}]" if message_size != string.size
53
+
54
+ assert(s.send_string(string, 0))
55
+ end
56
+
57
+ assert(s.close)
58
+
59
+ ctx.terminate
@@ -0,0 +1,66 @@
1
+
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
3
+
4
+ if ARGV.length < 3
5
+ puts "usage: ruby local_lat.rb <connect-to> <message-size> <roundtrip-count>"
6
+ exit
7
+ end
8
+
9
+ link = ARGV[0]
10
+ message_size = ARGV[1].to_i
11
+ roundtrip_count = ARGV[2].to_i
12
+
13
+ def assert(rc)
14
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
15
+ end
16
+
17
+ begin
18
+ ctx = ZMQ::Context.new
19
+ s1 = ctx.socket(ZMQ::REQ)
20
+ s2 = ctx.socket(ZMQ::REP)
21
+ rescue ContextError => e
22
+ STDERR.puts "Failed to allocate context or socket!"
23
+ raise
24
+ end
25
+
26
+ assert(s1.setsockopt(ZMQ::LINGER, 100))
27
+ assert(s2.setsockopt(ZMQ::LINGER, 100))
28
+
29
+ assert(s1.connect(link))
30
+ assert(s2.bind(link))
31
+
32
+ poller = ZMQ::Poller.new
33
+ poller.register_readable(s2)
34
+ poller.register_readable(s1)
35
+
36
+
37
+ start_time = Time.now
38
+
39
+ # kick it off
40
+ message = ZMQ::Message.new("a" * message_size)
41
+ assert(s1.sendmsg(message, ZMQ::DONTWAIT))
42
+
43
+ i = roundtrip_count
44
+
45
+ until i.zero?
46
+ i -= 1
47
+
48
+ assert(poller.poll_nonblock)
49
+
50
+ poller.readables.each do |socket|
51
+ received_message = ''
52
+ assert(socket.recv_string(received_message, ZMQ::DONTWAIT))
53
+ assert(socket.sendmsg(ZMQ::Message.new(received_message), ZMQ::DONTWAIT))
54
+ end
55
+ end
56
+
57
+ elapsed_usecs = (Time.now.to_f - start_time.to_f) * 1_000_000
58
+ latency = elapsed_usecs / roundtrip_count / 2
59
+
60
+ puts "mean latency: %.3f [us]" % latency
61
+ puts "received all messages in %.3f seconds" % (elapsed_usecs / 1_000_000)
62
+
63
+ assert(s1.close)
64
+ assert(s2.close)
65
+
66
+ ctx.terminate
@@ -0,0 +1,65 @@
1
+
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
3
+
4
+ if ARGV.length != 3
5
+ puts "usage: ruby local_throughtput.rb <bind-to> <message-size> <message-count>"
6
+ Process.exit
7
+ end
8
+
9
+ def assert(rc)
10
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
11
+ end
12
+
13
+ bind_to = ARGV[0]
14
+ message_size = ARGV[1].to_i
15
+ message_count = ARGV[2].to_i
16
+
17
+ begin
18
+ ctx = ZMQ::Context.new
19
+ s = ZMQ::Socket.new(ctx.pointer, ZMQ::SUB)
20
+ rescue ContextError => e
21
+ STDERR.puts "Failed to allocate context or socket!"
22
+ raise
23
+ end
24
+
25
+ #assert(s.setsockopt(ZMQ::LINGER, 100))
26
+ assert(s.setsockopt(ZMQ::SUBSCRIBE, ""))
27
+ #assert(s.setsockopt(ZMQ::RCVHWM, 0))
28
+ #assert(s.setsockopt(ZMQ::SNDHWM, 0))
29
+
30
+ assert(s.bind(bind_to))
31
+ sleep 1
32
+
33
+ msg = ZMQ::Message.new
34
+ msg = ''
35
+ assert(s.recv_string(msg))
36
+ #assert(s.recvmsg(msg))
37
+
38
+ start_time = Time.now
39
+
40
+ i = 1
41
+ while i < message_count
42
+ #assert(s.recvmsg(msg))
43
+ assert(s.recv_string(msg))
44
+ puts i
45
+ i += 1
46
+ end
47
+
48
+ end_time = Time.now
49
+
50
+ elapsed = (end_time.to_f - start_time.to_f) * 1000000
51
+ if elapsed == 0
52
+ elapsed = 1
53
+ end
54
+
55
+ throughput = message_count * 1000000 / elapsed
56
+ megabits = throughput * message_size * 8 / 1000000
57
+
58
+ puts "message size: %i [B]" % message_size
59
+ puts "message count: %i" % message_count
60
+ puts "mean throughput: %i [msg/s]" % throughput
61
+ puts "mean throughput: %.3f [Mb/s]" % megabits
62
+
63
+ assert(s.close)
64
+
65
+ ctx.terminate
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
2
+
3
+
4
+ def assert(rc)
5
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
6
+ end
7
+
8
+ link = "tcp://127.0.0.1:5555"
9
+
10
+ begin
11
+ ctx = ZMQ::Context.new
12
+ s1 = ctx.socket(ZMQ::PUB)
13
+ s2 = ctx.socket(ZMQ::SUB)
14
+ s3 = ctx.socket(ZMQ::SUB)
15
+ s4 = ctx.socket(ZMQ::SUB)
16
+ s5 = ctx.socket(ZMQ::SUB)
17
+ rescue ContextError => e
18
+ STDERR.puts "Failed to allocate context or socket!"
19
+ raise
20
+ end
21
+
22
+ assert(s1.setsockopt(ZMQ::LINGER, 100))
23
+ assert(s2.setsockopt(ZMQ::SUBSCRIBE, '')) # receive all
24
+ assert(s3.setsockopt(ZMQ::SUBSCRIBE, 'animals')) # receive any starting with this string
25
+ assert(s4.setsockopt(ZMQ::SUBSCRIBE, 'animals.dog'))
26
+ assert(s5.setsockopt(ZMQ::SUBSCRIBE, 'animals.cat'))
27
+
28
+ assert(s1.bind(link))
29
+ assert(s2.connect(link))
30
+ assert(s3.connect(link))
31
+ assert(s4.connect(link))
32
+ assert(s5.connect(link))
33
+
34
+ sleep 1
35
+
36
+ topic = "animals.dog"
37
+ payload = "Animal crackers!"
38
+
39
+ s1.identity = "publisher-A"
40
+ puts "sending"
41
+ # use the new multi-part messaging support to
42
+ # automatically separate the topic from the body
43
+ assert(s1.send_string(topic, ZMQ::SNDMORE))
44
+ assert(s1.send_string(payload, ZMQ::SNDMORE))
45
+ assert(s1.send_string(s1.identity))
46
+
47
+ topic = ''
48
+ assert(s2.recv_string(topic))
49
+
50
+ body = ''
51
+ assert(s2.recv_string(body)) if s2.more_parts?
52
+
53
+ identity = ''
54
+ assert(s2.recv_string(identity)) if s2.more_parts?
55
+ puts "s2 received topic [#{topic}], body [#{body}], identity [#{identity}]"
56
+
57
+
58
+
59
+ topic = ''
60
+ assert(s3.recv_string(topic))
61
+
62
+ body = ''
63
+ assert(s3.recv_string(body)) if s3.more_parts?
64
+ puts "s3 received topic [#{topic}], body [#{body}]"
65
+
66
+ topic = ''
67
+ assert(s4.recv_string(topic))
68
+
69
+ body = ''
70
+ assert(s4.recv_string(body)) if s4.more_parts?
71
+ puts "s4 received topic [#{topic}], body [#{body}]"
72
+
73
+ s5_string = ''
74
+ rc = s5.recv_string(s5_string, ZMQ::DONTWAIT)
75
+ eagain = (rc == -1 && ZMQ::Util.errno == ZMQ::EAGAIN)
76
+ puts(eagain ? "s5 received no messages" : "s5 FAILED")
77
+
78
+ [s1, s2, s3, s4, s5].each do |socket|
79
+ assert(socket.close)
80
+ end
81
+
82
+ ctx.terminate
@@ -0,0 +1,71 @@
1
+ #
2
+ # Copyright (c) 2007-2010 iMatix Corporation
3
+ #
4
+ # This file is part of 0MQ.
5
+ #
6
+ # 0MQ is free software; you can redistribute it and/or modify it under
7
+ # the terms of the Lesser GNU General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # 0MQ is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # Lesser GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the Lesser GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+
20
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
21
+
22
+ if ARGV.length < 3
23
+ puts "usage: ruby remote_lat.rb <connect-to> <message-size> <roundtrip-count>"
24
+ exit
25
+ end
26
+
27
+ def assert(rc)
28
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
29
+ end
30
+
31
+ connect_to = ARGV[0]
32
+ message_size = ARGV[1].to_i
33
+ roundtrip_count = ARGV[2].to_i
34
+
35
+ begin
36
+ ctx = ZMQ::Context.new
37
+ s = ctx.socket(ZMQ::REQ)
38
+ rescue ContextError => e
39
+ STDERR.puts "Failed to allocate context or socket!"
40
+ raise
41
+ end
42
+
43
+ assert(s.setsockopt(ZMQ::LINGER, 100))
44
+ assert(s.connect(connect_to))
45
+
46
+ msg = "#{ '3' * message_size }"
47
+
48
+ start_time = Time.now
49
+
50
+ roundtrip_count.times do
51
+ assert(s.send_string(msg, 0))
52
+
53
+ msg = ''
54
+ assert(s.recv_string(msg, 0))
55
+
56
+ raise "Message size doesn't match, expected [#{message_size}] but received [#{msg.size}]" if message_size != msg.size
57
+ end
58
+
59
+ end_time = Time.now
60
+ elapsed_secs = (end_time.to_f - start_time.to_f)
61
+ elapsed_usecs = elapsed_secs * 1000000
62
+ latency = elapsed_usecs / roundtrip_count / 2
63
+
64
+ puts "message size: %i [B]" % message_size
65
+ puts "roundtrip count: %i" % roundtrip_count
66
+ puts "throughput (msgs/s): %i" % (roundtrip_count / elapsed_secs)
67
+ puts "mean latency: %.3f [us]" % latency
68
+
69
+ assert(s.close)
70
+
71
+ ctx.terminate
@@ -0,0 +1,47 @@
1
+
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
3
+
4
+ if ARGV.length != 3
5
+ puts "usage: ruby remote_throughput.rb <connect-to> <message-size> <message-count>"
6
+ Process.exit
7
+ end
8
+
9
+ connect_to = ARGV[0]
10
+ message_size = ARGV[1].to_i
11
+ message_count = ARGV[2].to_i
12
+
13
+ def assert(rc)
14
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
15
+ end
16
+
17
+ begin
18
+ ctx = ZMQ::Context.new
19
+ s = ZMQ::Socket.new(ctx.pointer, ZMQ::PUB)
20
+ rescue ContextError => e
21
+ STDERR.puts "Could not allocate a context or socket!"
22
+ raise
23
+ end
24
+
25
+ #assert(s.setsockopt(ZMQ::LINGER, 1_000))
26
+ #assert(s.setsockopt(ZMQ::RCVHWM, 0))
27
+ #assert(s.setsockopt(ZMQ::SNDHWM, 0))
28
+ assert(s.connect(connect_to))
29
+
30
+ # the sleep gives the downstream SUB socket a chance to register its
31
+ # subscription filters with this PUB socket
32
+ sleep 1
33
+
34
+ contents = "#{'0'*message_size}"
35
+
36
+ i = 0
37
+ while i < message_count
38
+ msg = ZMQ::Message.new(contents)
39
+ assert(s.sendmsg(msg))
40
+ puts i
41
+ i += 1
42
+ end
43
+
44
+ sleep 10
45
+ assert(s.close)
46
+
47
+ ctx.terminate
@@ -0,0 +1,62 @@
1
+
2
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'ffi-rzmq')
3
+
4
+
5
+ def assert(rc)
6
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
7
+ end
8
+
9
+ link = "tcp://127.0.0.1:5554"
10
+
11
+ begin
12
+ ctx = ZMQ::Context.new
13
+ s1 = ctx.socket(ZMQ::REQ)
14
+ s2 = ctx.socket(ZMQ::REP)
15
+ rescue ContextError => e
16
+ STDERR.puts "Failed to allocate context or socket!"
17
+ raise
18
+ end
19
+
20
+ assert(s1.setsockopt(ZMQ::LINGER, 100))
21
+ assert(s2.setsockopt(ZMQ::LINGER, 100))
22
+
23
+ assert(s1.connect(link))
24
+ assert(s2.bind(link))
25
+
26
+ poller = ZMQ::Poller.new
27
+ poller.register_readable(s2)
28
+ poller.register_writable(s1)
29
+
30
+ start_time = Time.now
31
+ @unsent = true
32
+
33
+ until @done do
34
+ assert(poller.poll_nonblock)
35
+
36
+ # send the message after 5 seconds
37
+ if Time.now - start_time > 5 && @unsent
38
+ payload = "#{ '3' * 1024 }"
39
+
40
+ puts "sending payload nonblocking"
41
+ assert(s1.send_string(payload, ZMQ::DONTWAIT))
42
+ @unsent = false
43
+ end
44
+
45
+ # check for messages after 1 second
46
+ if Time.now - start_time > 1
47
+ poller.readables.each do |sock|
48
+ received_msg = ''
49
+ assert(sock.recv_string(received_msg, ZMQ::DONTWAIT))
50
+
51
+ puts "message received [#{received_msg}]"
52
+ @done = true
53
+ end
54
+ end
55
+ end
56
+
57
+ puts "executed in [#{Time.now - start_time}] seconds"
58
+
59
+ assert(s1.close)
60
+ assert(s2.close)
61
+
62
+ ctx.terminate