ffi-rzmq 0.9.3 → 0.9.6

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.
data/History.txt CHANGED
@@ -1,3 +1,52 @@
1
+ == 0.9.6 / 20120808
2
+ * Never released 0.9.5 as a gem. It was available via github only.
3
+
4
+ * Improved error message when DLL loading fails on Windows.
5
+
6
+ * Added support for 0mq 2.2. Support for 2.1 might be getting shakey...
7
+ patches to make it fully support 2.1 (assuming it's even broken at
8
+ all) are welcome.
9
+
10
+ * Added support for 0mq 3.2 (no support for 3.0 or 3.1). Not all methods
11
+ are exposed yet. For example, setting values on the context after it
12
+ has been created is not supported; instead, pass the correct keys
13
+ (:io_threads and :max_sockets) to the call to Context.create or
14
+ Context#new.
15
+
16
+ * Reduced spec running time from 30+ seconds to under 1 by eliminating
17
+ most uses of "sleep." It now polls sockets to wait for message
18
+ delivery. It also uses a technique of binding an inproc transport and
19
+ busy-looping on the connect side until it succeeds. These techniques
20
+ both allowed me to eliminate most uses of sleep.
21
+
22
+ * Some changes to support usage on Win7x64 with a 64-bit libzmq DLL.
23
+
24
+ == 0.9.5 / 20120119
25
+ * BROKE THE API.
26
+ In 0mq 2.x, there were two functions zmq_send() and zmq_recv().
27
+ As of 3.x, those functions were renamed zmq_sendmsg() and
28
+ zmq_recvmsg(). As everyone starts moving to 0mq 3.x, it doesn't
29
+ make sense to make the code break with 2.x. So, I'm breaking this
30
+ binding so that it always uses sendmsg/recvmsg and eliminates the
31
+ original send/recv methods.
32
+ Sorry!
33
+ This is likely to be the last non-backward-compatible API breakage.
34
+ Release 1.0 is around the corner and the API will be stable (I follow
35
+ semantic versioning).
36
+
37
+ * Introduced ZMQ::NonBlocking. This flag returns the correct value to set
38
+ a socket in non-blocking mode when sending/receiving. This hides the
39
+ differences between 0mq 2.x and 3.x since the constant names have
40
+ changed.
41
+
42
+ == 0.9.4 / 20120102
43
+ * Fixed bug in Poller#delete. Added specs to catch a regression.
44
+ In short, a socket that was deleted from the Poller set wasn't
45
+ always actually *removed* from the array. This led to a closed
46
+ socket being part of the pollset which would return errno 38.
47
+ This took about 4 days to find. <sigh>
48
+
49
+
1
50
  == 0.9.3 / 20111214
2
51
  * Performance optimizations for #getsockopt.
3
52
 
@@ -15,6 +64,8 @@
15
64
  can avoid that work and dispatch directly. This effects all
16
65
  Ruby runtimes, but it was through the work of Evan Phoenix that
17
66
  I figured this out. Results in a 2-5% speedup on method dispatch.
67
+
68
+
18
69
 
19
70
  == 0.9.2 / 20111115
20
71
  * Removed all references to the version4 API.
data/README.rdoc CHANGED
@@ -54,6 +54,14 @@ shouting but I wanted to make sure this stood out.
54
54
 
55
55
  All example code has been updated to use the new Ruby API.
56
56
 
57
+ == Breaking API Change from 0.9.3 to 0.9.5
58
+
59
+ The 0mq library functions zmq_send() and zmq_recv() were changed to
60
+ zmq_sendmsg() and zmq_recvmsg() with the 0mq 3.x API change. I have changed
61
+ the binding to always use #sendmsg and #recvmsg. This breaks existing code.
62
+ This should be the last breaking change heading into the 1.0 release of these
63
+ bindings.
64
+
57
65
  == PERFORMANCE
58
66
 
59
67
  Check out the latest performance results:
@@ -93,13 +101,14 @@ All features are implemented.
93
101
 
94
102
  ctx = ZMQ::Context.new
95
103
  s = ctx.socket ZMQ::REP
96
- s.setsockopt(ZMQ::HWM, 100)
97
- s.bind(bind_to)
104
+ rc = s.setsockopt(ZMQ::HWM, 100)
105
+ rc = s.bind(bind_to)
98
106
 
107
+ msg = ""
99
108
  roundtrip_count.times do
100
- msg = s.recv_string 0
109
+ rc = s.recv_string msg
101
110
  raise "Message size doesn't match, expected [#{message_size}] but received [#{msg.size}]" if message_size != msg.size
102
- s.send_string msg, 0
111
+ rc = s.send_string msg, 0
103
112
  end
104
113
 
105
114
 
@@ -119,15 +128,16 @@ All features are implemented.
119
128
 
120
129
  ctx = ZMQ::Context.new
121
130
  s = ctx.socket ZMQ::REQ
122
- s.connect(connect_to)
131
+ rc = s.connect(connect_to)
123
132
 
124
133
  msg = "#{ '3' * message_size }"
125
134
 
126
135
  start_time = Time.now
127
136
 
137
+ msg = ""
128
138
  roundtrip_count.times do
129
- s.send_string msg, 0
130
- msg = s.recv_string 0
139
+ rc = s.send_string msg, 0
140
+ rc = s.recv_string msg
131
141
  raise "Message size doesn't match, expected [#{message_size}] but received [#{msg.size}]" if message_size != msg.size
132
142
  end
133
143
 
@@ -38,7 +38,7 @@ start_time = Time.now
38
38
 
39
39
  # kick it off
40
40
  message = ZMQ::Message.new("a" * message_size)
41
- assert(s1.send(message, ZMQ::NOBLOCK))
41
+ assert(s1.sendmsg(message, ZMQ::NonBlocking))
42
42
 
43
43
  i = roundtrip_count
44
44
 
@@ -49,8 +49,8 @@ until i.zero?
49
49
 
50
50
  poller.readables.each do |socket|
51
51
  received_message = ''
52
- assert(socket.recv_string(received_message, ZMQ::NOBLOCK))
53
- assert(socket.send(ZMQ::Message.new(received_message), ZMQ::NOBLOCK))
52
+ assert(socket.recv_string(received_message, ZMQ::NonBlocking))
53
+ assert(socket.sendmsg(ZMQ::Message.new(received_message), ZMQ::NonBlocking))
54
54
  end
55
55
  end
56
56
 
@@ -28,13 +28,13 @@ assert(s.setsockopt(ZMQ::SUBSCRIBE, ""))
28
28
  assert(s.bind(bind_to))
29
29
 
30
30
  msg = ZMQ::Message.new
31
- assert(s.recv(msg))
31
+ assert(s.recvmsg(msg))
32
32
 
33
33
  start_time = Time.now
34
34
 
35
35
  i = 1
36
36
  while i < message_count
37
- assert(s.recv(msg))
37
+ assert(s.recvmsg(msg))
38
38
  i += 1
39
39
  end
40
40
 
@@ -0,0 +1,46 @@
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::HWM, 10))
28
+ assert(s.bind(connect_to))
29
+
30
+ # the sleep gives the downstream SUB socket a chance to register its
31
+ # subscription filters with this PUB socket
32
+ puts "Hit any key to start publishing"
33
+ STDIN.gets
34
+
35
+ i = 0
36
+ while i < message_count
37
+ msg = ZMQ::Message.new(i.to_s)
38
+ assert(s.sendmsg(msg))
39
+ puts i
40
+ i += 1
41
+ end
42
+
43
+ sleep 10
44
+ assert(s.close)
45
+
46
+ ctx.terminate
@@ -71,7 +71,7 @@ assert(s4.recv_string(body)) if s4.more_parts?
71
71
  puts "s4 received topic [#{topic}], body [#{body}]"
72
72
 
73
73
  s5_string = ''
74
- rc = s5.recv_string(s5_string, ZMQ::NOBLOCK)
74
+ rc = s5.recv_string(s5_string, ZMQ::NonBlocking)
75
75
  eagain = (rc == -1 && ZMQ::Util.errno == ZMQ::EAGAIN)
76
76
  puts(eagain ? "s5 received no messages" : "s5 FAILED")
77
77
 
@@ -30,7 +30,7 @@ contents = "#{'0'*message_size}"
30
30
  i = 0
31
31
  while i < message_count
32
32
  msg = ZMQ::Message.new(contents)
33
- assert(s.send(msg))
33
+ assert(s.sendmsg(msg))
34
34
  i += 1
35
35
  end
36
36
 
@@ -38,7 +38,7 @@ until @done do
38
38
  payload = "#{ '3' * 1024 }"
39
39
 
40
40
  puts "sending payload nonblocking"
41
- assert(s1.send_string(payload, ZMQ::NOBLOCK))
41
+ assert(s1.send_string(payload, ZMQ::NonBlocking))
42
42
  @unsent = false
43
43
  end
44
44
 
@@ -46,7 +46,7 @@ until @done do
46
46
  if Time.now - start_time > 1
47
47
  poller.readables.each do |sock|
48
48
  received_msg = ''
49
- assert(sock.recv_string(received_msg, ZMQ::NOBLOCK))
49
+ assert(sock.recv_string(received_msg, ZMQ::NonBlocking))
50
50
 
51
51
  puts "message received [#{received_msg}]"
52
52
  @done = true
@@ -27,8 +27,8 @@ payload = "#{ '3' * 2048 }"
27
27
  sent_msg = ZMQ::Message.new(payload)
28
28
  received_msg = ZMQ::Message.new
29
29
 
30
- assert(s1.send(sent_msg))
31
- assert(s2.recv(received_msg))
30
+ assert(s1.sendmsg(sent_msg))
31
+ assert(s2.recvmsg(received_msg))
32
32
 
33
33
  result = payload == received_msg.copy_out_string ? "Request received" : "Received wrong payload"
34
34
 
@@ -0,0 +1,74 @@
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
+ p ZMQ::Util.version
9
+
10
+ def assert(rc)
11
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
12
+ end
13
+
14
+ bind_to = ARGV[0]
15
+ message_size = ARGV[1].to_i
16
+ message_count = ARGV[2].to_i
17
+ sleep_time = ARGV[3].to_f
18
+
19
+ begin
20
+ ctx = ZMQ::Context.new
21
+ s = ZMQ::Socket.new(ctx.pointer, ZMQ::SUB)
22
+ rescue ContextError => e
23
+ STDERR.puts "Failed to allocate context or socket!"
24
+ raise
25
+ end
26
+
27
+ #assert(s.setsockopt(ZMQ::LINGER, 100))
28
+ assert(s.setsockopt(ZMQ::IDENTITY, rand(999_999).to_s))
29
+ assert(s.setsockopt(ZMQ::SUBSCRIBE, ""))
30
+ assert(s.setsockopt(ZMQ::HWM, 1))
31
+ #assert(s.setsockopt(ZMQ::RCVHWM, 0))
32
+ #assert(s.setsockopt(ZMQ::SNDHWM, 0))
33
+
34
+ assert(s.connect(bind_to))
35
+ sleep 1
36
+
37
+ msg = ZMQ::Message.new
38
+ msg = ''
39
+ assert(s.recv_string(msg))
40
+ raise unless msg.to_i == 0
41
+
42
+ start_time = Time.now
43
+
44
+ i = 1
45
+ while i < message_count - 1
46
+ assert(s.recv_string(msg))
47
+ msg_i = msg.to_i
48
+ missed = (msg_i - i) - 1
49
+ puts "missed [#{missed}] messages" if missed > 0
50
+ i = msg_i
51
+
52
+ start = Time.now
53
+ while (Time.now - start) < sleep_time
54
+ end
55
+ end
56
+
57
+ end_time = Time.now
58
+
59
+ elapsed = (end_time.to_f - start_time.to_f) * 1000000
60
+ if elapsed == 0
61
+ elapsed = 1
62
+ end
63
+
64
+ throughput = message_count * 1000000 / elapsed
65
+ megabits = throughput * message_size * 8 / 1000000
66
+
67
+ puts "message size: %i [B]" % message_size
68
+ puts "message count: %i" % message_count
69
+ puts "mean throughput: %i [msg/s]" % throughput
70
+ puts "mean throughput: %.3f [Mb/s]" % megabits
71
+
72
+ assert(s.close)
73
+
74
+ ctx.terminate
@@ -58,11 +58,11 @@ class Receiver
58
58
 
59
59
  def run
60
60
  msg = ZMQ::Message.new
61
- assert(@socket.recv(msg))
61
+ assert(@socket.recvmsg(msg))
62
62
 
63
63
  elapsed = elapsed_microseconds do
64
64
  (@count -1).times do
65
- assert(@socket.recv(msg))
65
+ assert(@socket.recvmsg(msg))
66
66
  end
67
67
  end
68
68
 
@@ -110,7 +110,7 @@ class Transmitter
110
110
  i = 0
111
111
  while i < @count
112
112
  msg = ZMQ::Message.new(contents)
113
- assert(@socket.send(msg))
113
+ assert(@socket.sendmsg(msg))
114
114
  i += 1
115
115
  end
116
116
 
@@ -43,7 +43,7 @@ until @done do
43
43
 
44
44
  5.times do |i|
45
45
  payload = "#{ i.to_s * 40 }"
46
- assert(s1.send_string(payload, ZMQ::NOBLOCK))
46
+ assert(s1.send_string(payload, ZMQ::NonBlocking))
47
47
  end
48
48
  @unsent = false
49
49
  end
@@ -54,12 +54,12 @@ until @done do
54
54
 
55
55
  if sock.identity =~ /xrep/
56
56
  routing_info = ''
57
- assert(sock.recv_string(routing_info, ZMQ::NOBLOCK))
57
+ assert(sock.recv_string(routing_info, ZMQ::NonBlocking))
58
58
  puts "routing_info received [#{routing_info}] on socket.identity [#{sock.identity}]"
59
59
  else
60
60
  routing_info = nil
61
61
  received_msg = ''
62
- assert(sock.recv_string(received_msg, ZMQ::NOBLOCK))
62
+ assert(sock.recv_string(received_msg, ZMQ::NonBlocking))
63
63
 
64
64
  # skip to the next iteration if received_msg is nil; that means we got an EAGAIN
65
65
  next unless received_msg
@@ -68,13 +68,13 @@ until @done do
68
68
 
69
69
  while sock.more_parts? do
70
70
  received_msg = ''
71
- assert(sock.recv_string(received_msg, ZMQ::NOBLOCK))
71
+ assert(sock.recv_string(received_msg, ZMQ::NonBlocking))
72
72
 
73
73
  puts "message received [#{received_msg}]"
74
74
  end
75
75
 
76
76
  puts "kick back a reply"
77
- assert(sock.send_string(routing_info, ZMQ::SNDMORE | ZMQ::NOBLOCK)) if routing_info
77
+ assert(sock.send_string(routing_info, ZMQ::SNDMORE | ZMQ::NonBlocking)) if routing_info
78
78
  time = Time.now.strftime "%Y-%m-%dT%H:%M:%S.#{Time.now.usec}"
79
79
  reply = "reply " + sock.identity.upcase + " #{time}"
80
80
  puts "sent reply [#{reply}], #{time}"
@@ -38,7 +38,7 @@ start_time = Time.now
38
38
 
39
39
  # kick it off
40
40
  message = ZMQ::Message.new("a" * message_size)
41
- assert(s1.sendmsg(message, ZMQ::DONTWAIT))
41
+ assert(s1.sendmsg(message, ZMQ::NonBlocking))
42
42
 
43
43
  i = roundtrip_count
44
44
 
@@ -49,8 +49,8 @@ until i.zero?
49
49
 
50
50
  poller.readables.each do |socket|
51
51
  received_message = ''
52
- assert(socket.recv_string(received_message, ZMQ::DONTWAIT))
53
- assert(socket.sendmsg(ZMQ::Message.new(received_message), ZMQ::DONTWAIT))
52
+ assert(socket.recv_string(received_message, ZMQ::NonBlocking))
53
+ assert(socket.sendmsg(ZMQ::Message.new(received_message), ZMQ::NonBlocking))
54
54
  end
55
55
  end
56
56
 
@@ -0,0 +1,46 @@
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, 100))
28
+ assert(s.bind(connect_to))
29
+
30
+ # the sleep gives the downstream SUB socket a chance to register its
31
+ # subscription filters with this PUB socket
32
+ puts "Hit any key to start publishing"
33
+ STDIN.gets
34
+
35
+ i = 0
36
+ while i < message_count
37
+ msg = ZMQ::Message.new(i.to_s)
38
+ assert(s.sendmsg(msg))
39
+ puts i
40
+ i += 1
41
+ end
42
+
43
+ sleep 10
44
+ assert(s.close)
45
+
46
+ ctx.terminate