ffi-rzmq 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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