ffi-rzmq 0.9.3 → 0.9.6

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