rbczmq 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/.gitignore +23 -0
  2. data/.travis.yml +19 -0
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +19 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +247 -0
  7. data/Rakefile +67 -0
  8. data/examples/loop.rb +109 -0
  9. data/examples/poller.rb +37 -0
  10. data/examples/pub_sub.rb +101 -0
  11. data/examples/push_pull.rb +104 -0
  12. data/examples/req_rep.rb +100 -0
  13. data/ext/czmq.tar.gz +0 -0
  14. data/ext/rbczmq/context.c +280 -0
  15. data/ext/rbczmq/context.h +26 -0
  16. data/ext/rbczmq/extconf.rb +138 -0
  17. data/ext/rbczmq/frame.c +401 -0
  18. data/ext/rbczmq/frame.h +24 -0
  19. data/ext/rbczmq/jruby.h +22 -0
  20. data/ext/rbczmq/loop.c +413 -0
  21. data/ext/rbczmq/loop.h +24 -0
  22. data/ext/rbczmq/message.c +620 -0
  23. data/ext/rbczmq/message.h +24 -0
  24. data/ext/rbczmq/poller.c +308 -0
  25. data/ext/rbczmq/poller.h +29 -0
  26. data/ext/rbczmq/pollitem.c +251 -0
  27. data/ext/rbczmq/pollitem.h +25 -0
  28. data/ext/rbczmq/rbczmq_ext.c +198 -0
  29. data/ext/rbczmq/rbczmq_ext.h +94 -0
  30. data/ext/rbczmq/rbczmq_prelude.h +22 -0
  31. data/ext/rbczmq/rubinius.h +24 -0
  32. data/ext/rbczmq/ruby18.h +43 -0
  33. data/ext/rbczmq/ruby19.h +15 -0
  34. data/ext/rbczmq/socket.c +1570 -0
  35. data/ext/rbczmq/socket.h +136 -0
  36. data/ext/rbczmq/timer.c +110 -0
  37. data/ext/rbczmq/timer.h +23 -0
  38. data/ext/zeromq.tar.gz +0 -0
  39. data/lib/rbczmq.rb +3 -0
  40. data/lib/zmq.rb +77 -0
  41. data/lib/zmq/context.rb +50 -0
  42. data/lib/zmq/default_handler.rb +16 -0
  43. data/lib/zmq/frame.rb +11 -0
  44. data/lib/zmq/handler.rb +76 -0
  45. data/lib/zmq/loop.rb +131 -0
  46. data/lib/zmq/message.rb +9 -0
  47. data/lib/zmq/poller.rb +22 -0
  48. data/lib/zmq/pollitem.rb +31 -0
  49. data/lib/zmq/socket.rb +125 -0
  50. data/lib/zmq/socket/dealer.rb +33 -0
  51. data/lib/zmq/socket/pair.rb +39 -0
  52. data/lib/zmq/socket/pub.rb +30 -0
  53. data/lib/zmq/socket/pull.rb +29 -0
  54. data/lib/zmq/socket/push.rb +32 -0
  55. data/lib/zmq/socket/rep.rb +37 -0
  56. data/lib/zmq/socket/req.rb +37 -0
  57. data/lib/zmq/socket/router.rb +38 -0
  58. data/lib/zmq/socket/sub.rb +27 -0
  59. data/lib/zmq/timer.rb +12 -0
  60. data/lib/zmq/version.rb +5 -0
  61. data/perf/pair.rb +7 -0
  62. data/perf/pair/local.rb +22 -0
  63. data/perf/pair/remote.rb +25 -0
  64. data/perf/pub_sub.rb +7 -0
  65. data/perf/pub_sub/local.rb +22 -0
  66. data/perf/pub_sub/remote.rb +25 -0
  67. data/perf/push_pull.rb +7 -0
  68. data/perf/push_pull/local.rb +21 -0
  69. data/perf/push_pull/remote.rb +25 -0
  70. data/perf/req_rep.rb +7 -0
  71. data/perf/req_rep/local.rb +35 -0
  72. data/perf/req_rep/remote.rb +28 -0
  73. data/perf/runner.rb +142 -0
  74. data/rbczmq.gemspec +22 -0
  75. data/test/helper.rb +21 -0
  76. data/test/socket/test_dealer_socket.rb +14 -0
  77. data/test/socket/test_pair_socket.rb +24 -0
  78. data/test/socket/test_pair_sockets.rb +74 -0
  79. data/test/socket/test_pub_socket.rb +17 -0
  80. data/test/socket/test_pub_sub_sockets.rb +87 -0
  81. data/test/socket/test_pull_socket.rb +17 -0
  82. data/test/socket/test_push_pull_sockets.rb +81 -0
  83. data/test/socket/test_push_socket.rb +17 -0
  84. data/test/socket/test_rep_socket.rb +25 -0
  85. data/test/socket/test_req_rep_sockets.rb +42 -0
  86. data/test/socket/test_req_socket.rb +27 -0
  87. data/test/socket/test_router_socket.rb +14 -0
  88. data/test/socket/test_routing.rb +66 -0
  89. data/test/socket/test_sub_socket.rb +17 -0
  90. data/test/test_context.rb +86 -0
  91. data/test/test_frame.rb +78 -0
  92. data/test/test_handler.rb +28 -0
  93. data/test/test_loop.rb +252 -0
  94. data/test/test_message.rb +201 -0
  95. data/test/test_poller.rb +154 -0
  96. data/test/test_pollitem.rb +78 -0
  97. data/test/test_socket.rb +403 -0
  98. data/test/test_threading.rb +34 -0
  99. data/test/test_timer.rb +37 -0
  100. data/test/test_zmq.rb +62 -0
  101. metadata +208 -0
data/perf/runner.rb ADDED
@@ -0,0 +1,142 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('lib')
4
+ require 'zmq'
5
+
6
+ class Runner
7
+ DEFAULT_MSG_COUNT = 100_000
8
+ DEFAULT_MSG_SIZE = 100
9
+ DEFAULT_ENCODING = :string
10
+
11
+ attr_reader :msg_count, :msg_size, :encoding, :workers_count, :stats_buf
12
+
13
+ def initialize(msg_count, msg_size, encoding, workers_count = 1)
14
+ @msg_count = (msg_count || DEFAULT_MSG_COUNT).to_i
15
+ @msg_size = (msg_size || DEFAULT_MSG_SIZE).to_i
16
+ @encoding = (encoding || DEFAULT_ENCODING).to_sym
17
+ @workers_count = (workers_count || 1).to_i
18
+ @stats_buf, @workers = [], []
19
+ register_signal_handlers
20
+ end
21
+
22
+ def start(test)
23
+ @workers_count.times{ fork_local(test) }
24
+ fork_remote(test)
25
+ puts "Workers: #{@workers.join(', ')}"
26
+ puts "Producer: #{@producer}"
27
+ after_start
28
+ ensure
29
+ stop
30
+ end
31
+
32
+ def process_msg_count
33
+ msg_count / workers_count
34
+ end
35
+
36
+ def endpoint
37
+ self.class.const_get(:ENDPOINT)
38
+ end
39
+
40
+ def payload
41
+ @payload ||= "#{'0'*msg_size}"
42
+ end
43
+
44
+ def stats(start_time)
45
+ end_time = Time.now
46
+ elapsed = (end_time.to_f - start_time.to_f) * 1000000
47
+ elapsed = 1 if elapsed == 0
48
+
49
+ throughput = process_msg_count * 1000000 / elapsed
50
+ megabits = throughput * msg_size * 8 / 1000000
51
+ stats_buf << "====== [#{Process.pid}] transfer stats ======"
52
+ stats_buf << "message encoding: %s" % encoding
53
+ stats_buf << "message size: %i [B]" % msg_size
54
+ stats_buf << "message count: %i" % process_msg_count
55
+ stats_buf << "mean throughput: %i [msg/s]" % throughput
56
+ stats_buf << "mean throughput: %.3f [Mb/s]" % megabits
57
+ end
58
+
59
+ private
60
+ def register_signal_handlers
61
+ %w(INT TERM QUIT).each do |sig|
62
+ trap(sig){ stop }
63
+ end
64
+ end
65
+
66
+ def before_fork
67
+ sample_mem(:before)
68
+ end
69
+
70
+ def after_fork
71
+ sample_mem(:after)
72
+ stats_buf.each{|s| puts(s) }
73
+ end
74
+
75
+ def sample_mem(w)
76
+ stats_buf << "[#{$$}] Memory used #{w}: %dkb" % `ps -o rss= -p #{$$}`.to_i
77
+ end
78
+ end
79
+
80
+ class ProcessRunner < Runner
81
+ ENDPOINT = "tcp://127.0.0.1:5221"
82
+
83
+ def stop
84
+ Process.kill(:INT, @producer) rescue nil
85
+ @workers.each{|p| Process.kill(:INT, p) rescue nil }
86
+ end
87
+
88
+ private
89
+ def after_start
90
+ Process.waitpid(@producer, Process::WNOHANG)
91
+ @workers.each{|p| Process.waitpid(p) }
92
+ end
93
+
94
+ def fork_local(test)
95
+ @workers << fork do
96
+ before_fork
97
+ require File.join(File.dirname(__FILE__), test.to_s, 'local')
98
+ after_fork
99
+ end
100
+ end
101
+
102
+ def fork_remote(test)
103
+ @producer = fork do
104
+ before_fork
105
+ sleep 1
106
+ require File.join(File.dirname(__FILE__), test.to_s, 'remote')
107
+ after_fork
108
+ end
109
+ end
110
+ end
111
+
112
+ class ThreadRunner < Runner
113
+ ENDPOINT = "inproc://perf"
114
+
115
+ def stop
116
+ @producer.kill rescue nil
117
+ @workers.each{|t| t.kill rescue nil }
118
+ end
119
+
120
+ private
121
+ def after_start
122
+ @producer.join
123
+ @workers.each{|t| t.join }
124
+ end
125
+
126
+ def fork_local(test)
127
+ @workers << Thread.new do
128
+ before_fork
129
+ require File.join(File.dirname(__FILE__), test.to_s, 'local')
130
+ after_fork
131
+ end
132
+ end
133
+
134
+ def fork_remote(test)
135
+ @producer = Thread.new do
136
+ before_fork
137
+ sleep 1
138
+ require File.join(File.dirname(__FILE__), test.to_s, 'remote')
139
+ after_fork
140
+ end
141
+ end
142
+ end
data/rbczmq.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../lib/zmq/version', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rbczmq"
7
+ s.version = ZMQ::VERSION
8
+ s.summary = "Ruby extension for CZMQ - High-level C Binding for ØMQ (http://czmq.zeromq.org)"
9
+ s.description = "Ruby extension for CZMQ - High-level C Binding for ØMQ (http://czmq.zeromq.org)"
10
+ s.authors = ["Lourens Naudé", "James Tucker"]
11
+ s.email = ["lourens@methodmissing.com", "jftucker@gmail.com"]
12
+ s.homepage = "http://github.com/methodmissing/rbczmq"
13
+ s.date = Time.now.utc.strftime('%Y-%m-%d')
14
+ s.platform = Gem::Platform::RUBY
15
+ s.extensions = "ext/rbczmq/extconf.rb"
16
+ s.has_rdoc = true
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files test`.split("\n")
19
+ s.rdoc_options = ["--charset=UTF-8"]
20
+ s.require_paths = ["lib"]
21
+ s.add_development_dependency('rake-compiler', '~> 0.8.0')
22
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'test/unit'
4
+ require 'zmq'
5
+ require 'stringio'
6
+
7
+ Thread.abort_on_exception = true
8
+
9
+ class ZmqTestCase < Test::Unit::TestCase
10
+ undef_method :default_test if method_defined? :default_test
11
+
12
+ if ENV['STRESS_GC']
13
+ def setup
14
+ GC.stress = true
15
+ end
16
+
17
+ def teardown
18
+ GC.stress = false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestDealerSocket < ZmqTestCase
6
+ def test_behavior
7
+ ctx = ZMQ::Context.new
8
+ sock = ctx.socket(:DEALER)
9
+ assert_equal ZMQ::DEALER, sock.type
10
+ assert_equal "DEALER socket", sock.to_s
11
+ ensure
12
+ ctx.destroy
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestPairSocket < ZmqTestCase
6
+ def test_behavior
7
+ ctx = ZMQ::Context.new
8
+ sock = ctx.socket(:PAIR)
9
+ assert_equal ZMQ::PAIR, sock.type
10
+ assert_equal "PAIR socket", sock.to_s
11
+ ensure
12
+ ctx.destroy
13
+ end
14
+
15
+ def test_inproc_only_transport
16
+ ctx = ZMQ::Context.new
17
+ sock = ctx.socket(:PAIR)
18
+ assert_raises ZMQ::Error do
19
+ sock.bind("tcp://127.0.0.1:*")
20
+ end
21
+ ensure
22
+ ctx.destroy
23
+ end
24
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestPairSockets < ZmqTestCase
6
+ def test_flow
7
+ ctx = ZMQ::Context.new
8
+ a = ctx.bind(:PAIR, "inproc://test.pair-flow")
9
+ b = ctx.connect(:PAIR, "inproc://test.pair-flow")
10
+ a.send("a")
11
+ b.send("b")
12
+ assert_equal "b", a.recv
13
+ assert_equal "a", b.recv
14
+ ensure
15
+ ctx.destroy
16
+ end
17
+
18
+ def test_transfer
19
+ ctx = ZMQ::Context.new
20
+ a = ctx.bind(:PAIR, "inproc://test.pair-transfer")
21
+ b = ctx.connect(:PAIR, "inproc://test.pair-transfer")
22
+ a.send("message")
23
+ assert_equal "message", b.recv
24
+
25
+ a.sendm("me")
26
+ a.sendm("ss")
27
+ a.send("age")
28
+ assert_equal "me", b.recv
29
+ assert_equal "ss", b.recv
30
+ assert_equal "age", b.recv
31
+
32
+ a.send_frame ZMQ::Frame("frame")
33
+ assert_equal ZMQ::Frame("frame"), b.recv_frame
34
+
35
+ 5.times do |i|
36
+ frame = ZMQ::Frame("m#{i}")
37
+ a.send_frame(frame, ZMQ::Frame::MORE)
38
+ end
39
+ a.send_frame(ZMQ::Frame("m5"))
40
+ expected, frames = %w(m0 m1 m2 m3 m4 m5), []
41
+ 5.times do
42
+ frames << b.recv_frame.data
43
+ end
44
+ frames << b.recv_frame.data
45
+ assert_equal expected, frames
46
+
47
+ msg = ZMQ::Message.new
48
+ msg.push ZMQ::Frame("header")
49
+
50
+ assert_nil a.send_message(msg)
51
+
52
+ recvd_msg = b.recv_message
53
+ assert_instance_of ZMQ::Message, recvd_msg
54
+ assert_equal ZMQ::Frame("header"), recvd_msg.pop
55
+ ensure
56
+ ctx.destroy
57
+ end
58
+
59
+ def test_distribution
60
+ ctx = ZMQ::Context.new
61
+ a = ctx.bind(:PAIR, "inproc://test.pair-distribution")
62
+ thread = Thread.new do
63
+ b = ctx.connect(:PAIR, "inproc://test.pair-distribution")
64
+ frame = b.recv_frame
65
+ b.close
66
+ frame
67
+ end
68
+
69
+ a.send_frame ZMQ::Frame("message")
70
+ assert_equal ZMQ::Frame("message"), thread.value
71
+ ensure
72
+ ctx.destroy
73
+ end
74
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestPubSocket < ZmqTestCase
6
+ def test_behavior
7
+ ctx = ZMQ::Context.new
8
+ sock = ctx.socket(:PUB)
9
+ assert_equal ZMQ::PUB, sock.type
10
+ assert_equal "PUB socket", sock.to_s
11
+ assert_raises ZMQ::Error do
12
+ sock.recv
13
+ end
14
+ ensure
15
+ ctx.destroy
16
+ end
17
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestPubSubSockets < ZmqTestCase
6
+ def test_flow
7
+ ctx = ZMQ::Context.new
8
+ pub = ctx.bind(:PUB, "inproc://test.pub-sub-flow")
9
+ sub = ctx.connect(:SUB, "inproc://test.pub-sub-flow")
10
+ sub.subscribe("")
11
+ pub.send("a")
12
+ assert_equal "a", sub.recv
13
+ ensure
14
+ ctx.destroy
15
+ end
16
+
17
+ def test_transfer
18
+ ctx = ZMQ::Context.new
19
+ pub = ctx.bind(:PUB, "inproc://test.pub-sub-transfer")
20
+ sub = ctx.connect(:SUB, "inproc://test.pub-sub-transfer")
21
+ sub.subscribe("")
22
+ pub.send("message")
23
+ assert_equal "message", sub.recv
24
+
25
+ pub.sendm("me")
26
+ pub.sendm("ss")
27
+ pub.send("age")
28
+ assert_equal "me", sub.recv
29
+ assert_equal "ss", sub.recv
30
+ assert_equal "age", sub.recv
31
+
32
+ pub.send_frame ZMQ::Frame("frame")
33
+ assert_equal ZMQ::Frame("frame"), sub.recv_frame
34
+
35
+ 5.times do |i|
36
+ frame = ZMQ::Frame("m#{i}")
37
+ pub.send_frame(frame, ZMQ::Frame::MORE)
38
+ end
39
+ pub.send_frame(ZMQ::Frame("m5"))
40
+ expected, frames = %w(m0 m1 m2 m3 m4 m5), []
41
+ 5.times do
42
+ frames << sub.recv_frame.data
43
+ end
44
+ frames << sub.recv_frame.data
45
+ assert_equal expected, frames
46
+
47
+ msg = ZMQ::Message.new
48
+ msg.push ZMQ::Frame("header")
49
+
50
+ assert_nil pub.send_message(msg)
51
+
52
+ recvd_msg = sub.recv_message
53
+ assert_instance_of ZMQ::Message, recvd_msg
54
+ assert_equal ZMQ::Frame("header"), recvd_msg.pop
55
+ ensure
56
+ ctx.destroy
57
+ end
58
+
59
+ def test_distribution
60
+ ctx = ZMQ::Context.new
61
+ pub = ctx.bind(:PUB, "inproc://test.pub-sub-distribution")
62
+ threads = []
63
+ 5.times do |i|
64
+ threads << Thread.new do
65
+ sub = ctx.connect(:SUB, "inproc://test.pub-sub-distribution")
66
+ sub.subscribe("")
67
+ messages = []
68
+ 5.times do
69
+ messages << sub.recv
70
+ end
71
+ sub.close
72
+ messages
73
+ end
74
+ end
75
+
76
+ sleep 0.5 # "slow joiner" syndrome
77
+ messages = %w(a b c d e)
78
+ messages.each do |m|
79
+ pub.send m
80
+ end
81
+
82
+ threads.each{|t| t.join }
83
+ assert threads.all?{|t| t.value == messages }
84
+ ensure
85
+ ctx.destroy
86
+ end
87
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestPullSocket < ZmqTestCase
6
+ def test_behavior
7
+ ctx = ZMQ::Context.new
8
+ sock = ctx.socket(:PULL)
9
+ assert_equal ZMQ::PULL, sock.type
10
+ assert_equal "PULL socket", sock.to_s
11
+ assert_raises ZMQ::Error do
12
+ sock.send("message")
13
+ end
14
+ ensure
15
+ ctx.destroy
16
+ end
17
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'helper')
4
+
5
+ class TestPushPullSockets < ZmqTestCase
6
+ def test_flow
7
+ ctx = ZMQ::Context.new
8
+ push = ctx.bind(:PUSH, "inproc://test.push-pull-flow")
9
+ pull = ctx.connect(:PULL, "inproc://test.push-pull-flow")
10
+ push.send("a")
11
+ assert_equal "a", pull.recv
12
+ ensure
13
+ ctx.destroy
14
+ end
15
+
16
+ def test_transfer
17
+ ctx = ZMQ::Context.new
18
+ push = ctx.bind(:PUSH, "inproc://test.push-pull-transfer")
19
+ pull = ctx.connect(:PULL, "inproc://test.push-pull-transfer")
20
+ push.send("message")
21
+ assert_equal "message", pull.recv
22
+
23
+ push.sendm("me")
24
+ push.sendm("ss")
25
+ push.send("age")
26
+ assert_equal "me", pull.recv
27
+ assert_equal "ss", pull.recv
28
+ assert_equal "age", pull.recv
29
+
30
+ push.send_frame ZMQ::Frame("frame")
31
+ assert_equal ZMQ::Frame("frame"), pull.recv_frame
32
+
33
+ 5.times do |i|
34
+ frame = ZMQ::Frame("m#{i}")
35
+ push.send_frame(frame, ZMQ::Frame::MORE)
36
+ end
37
+ push.send_frame(ZMQ::Frame("m5"))
38
+ expected, frames = %w(m0 m1 m2 m3 m4 m5), []
39
+ 5.times do
40
+ frames << pull.recv_frame.data
41
+ end
42
+ frames << pull.recv_frame.data
43
+ assert_equal expected, frames
44
+
45
+ msg = ZMQ::Message.new
46
+ msg.push ZMQ::Frame("header")
47
+
48
+ assert_nil push.send_message(msg)
49
+
50
+ recvd_msg = pull.recv_message
51
+ assert_instance_of ZMQ::Message, recvd_msg
52
+ assert_equal ZMQ::Frame("header"), recvd_msg.pop
53
+ ensure
54
+ ctx.destroy
55
+ end
56
+
57
+ def test_distribution
58
+ ctx = ZMQ::Context.new
59
+ push = ctx.bind(:PUSH, "inproc://test.push-pull-distribution")
60
+ threads = []
61
+ 5.times do |i|
62
+ threads << Thread.new do
63
+ pull = ctx.connect(:PULL, "inproc://test.push-pull-distribution")
64
+ msg = pull.recv
65
+ pull.close
66
+ msg
67
+ end
68
+ end
69
+
70
+ sleep 0.5 # "slow joiner" syndrome
71
+ messages = %w(a b c d e f)
72
+ messages.each do |m|
73
+ push.send m
74
+ end
75
+
76
+ threads.each{|t| t.join }
77
+ assert threads.all?{|t| messages.include?(t.value) }
78
+ ensure
79
+ ctx.destroy
80
+ end
81
+ end