cztop 1.1.2 → 1.2.1

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.
@@ -1,276 +0,0 @@
1
- # Taxi System
2
-
3
- Suppose you're running a taxi company. You have a set of taxi drivers
4
- working for you. You'd like to connect them to your central server, so they're
5
- ready to get service requests from customers who'd like to get picked up by a
6
- taxi from some place X. As soon as a customer sends his service request, the
7
- central server will send the closest taxi nearby that's available to the
8
- customer.
9
-
10
- Of course you want the communication between the broker and the taxi drivers to
11
- be secure, meaning you want encryption and authentication.
12
-
13
- You also want ping-pong heartbeating, as you want to have confidence you can
14
- get in touch with your taxi drivers any time you want. And if a service
15
- request can't be delivered to a particular taxi driver, you wanna know
16
- immediately.
17
-
18
- This solution is implemented using CLIENT/SERVER sockets and the CURVE
19
- security mechanism.
20
-
21
- ## Broker
22
-
23
- Here's a possible implementation of the broker. What you'll have to provide
24
- are the environment variables `BROKER_ADDRESS` (the public TCP endpoint),
25
- `BROKER_CERT` (path to the broker's secret+public keys), and `CLIENT_CERTS`
26
- (directory to taxi drivers' certificates, public keys only).
27
-
28
- After the start, the broker will just start listening for the drivers (CLIENT
29
- sockets) to connect. After a driver has connected, authenticated, and sent its
30
- `HELLO` message, the broker answers with a `WELCOME` or `WELCOMEBACK` message,
31
- depending if the driver was connected before (it might have reconnected and
32
- been assigned a new routing ID).
33
-
34
- The broker will present you with a Pry shell. Right before starting the shell,
35
- there's a small usage information, but it's not very well visible due to Pry's
36
- noisy start. It's simple, though. Inside that shell, you can use the method
37
- `#send_command(driver, command)`. Example:
38
-
39
- ```
40
- pry> send_command("driver1", "foobar")
41
- ```
42
-
43
- Depending on whether the driver is connected, it'll send the message or report
44
- that it cannot do so.
45
-
46
- ```ruby
47
- #!/usr/bin/env ruby
48
- require 'pry'
49
- require 'pathname'
50
- require 'cztop'
51
-
52
- endpoint = ENV["BROKER_ADDRESS"]
53
- broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # secret+public
54
- client_certs = ENV["CLIENT_CERTS"] # /path/to/client_certs/
55
- drivers = Pathname.new(client_certs).children.map(&:basename).map(&:to_s)
56
-
57
- authenticator = CZTop::Authenticator.new
58
- authenticator.verbose!
59
- authenticator.curve(client_certs)
60
-
61
- # create and bind socket
62
- @socket = CZTop::Socket::SERVER.new
63
- @socket.CURVE_server!(broker_cert)
64
- #socket.options.sndtimeo = 0
65
- @socket.options.heartbeat_ivl = 100#ms
66
- @socket.options.heartbeat_timeout = 300#ms
67
- @socket.bind(endpoint)
68
-
69
- puts ">>> Socket bound to #{endpoint.inspect}"
70
-
71
- # get and print socket events
72
- Thread.new do
73
- monitor = CZTop::Monitor.new(@socket)
74
- monitor.listen("ALL")
75
- monitor.start
76
- while msg = monitor.next
77
- puts ">>> Socket event: #{msg.inspect}"
78
- end
79
- end
80
-
81
- # receive messages from drivers
82
- @driver_map = {} # driver name => routing ID
83
- Thread.new do
84
-
85
- # CZTop::Loop (zloop) doesn't work with SERVER sockets :(
86
- poller = CZTop::Poller.new(@socket)
87
- while true
88
- puts "waiting for socket to become readable ..."
89
- socket = poller.wait
90
- puts "socket is readable"
91
- msg = socket.receive
92
- puts "got message"
93
- command, argument = msg[0].split("\t", 2)
94
-
95
- case command
96
- when "HELLO"
97
- driver = argument
98
- puts ">>> Driver #{driver.inspect} has connected."
99
- welcome = @driver_map.key?(driver) ? "WELCOMEBACK" : "WELCOME"
100
-
101
- # remember driver's assigned message routing ID
102
- @driver_map[driver] = msg.routing_id
103
-
104
- # send WELCOME or WELCOMEBACK
105
- rep = CZTop::Message.new(welcome)
106
- rep.routing_id = @driver_map[driver]
107
- socket << rep
108
- puts ">>> Sent #{welcome.inspect} to #{driver.inspect}"
109
- end
110
- end
111
- end
112
-
113
- def send_command(driver, command)
114
- if command.nil? || command.empty?
115
- puts "!!! No message given."
116
- return
117
- end
118
- if not @driver_map.key?(driver)
119
- puts "!!! Driver #{driver.inspect} has never connected."
120
- return
121
- end
122
- puts ">>> Sending message to #{driver.inspect} ..."
123
- msg = CZTop::Message.new(command)
124
- msg.routing_id = @driver_map[driver]
125
- @socket << msg
126
- rescue SocketError
127
- puts "!!! Driver #{driver.inspect} isn't connected anymore."
128
- end
129
-
130
- ##
131
- # REPL for user to play
132
- #
133
- puts <<MSG
134
- You can now send messages to the drivers yourself.
135
- The use the method #send_command, like this:
136
-
137
- pry> send_command("driver1", "PICKUP\t(8.541694,47.376887)")
138
-
139
- This should show something like this in the client.rb terminal:
140
-
141
- 03:17:01 driver1.1 | received message: "PICKUP\t(8.541694,47.376887)"
142
- MSG
143
-
144
- binding.pry
145
- ```
146
-
147
- ## Client
148
-
149
- Here you have to provide the environment variables `BROKER_ADDRESS` (ditto),
150
- `BROKER_CERT` (public key only), `CLIENT_CERT` (taxi driver's certificate
151
- containing the secret+public keys).
152
-
153
- After connecting to the broker and completing the security handshake, the
154
- client sends a `HELLO` message, after which it immediately expects some answer
155
- from the broker (see above). After that, it just listens for messages (service
156
- requests) and prints them into the terminal.
157
-
158
- ```ruby
159
- #!/usr/bin/env ruby
160
- require 'cztop'
161
-
162
- endpoint = ENV["BROKER_ADDRESS"]
163
- broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # public only
164
- client_cert = CZTop::Certificate.load ENV["CLIENT_CERT"]
165
-
166
- @socket = CZTop::Socket::CLIENT.new
167
- @socket.CURVE_client!(client_cert, broker_cert)
168
- @socket.options.sndtimeo = 2000#ms
169
-
170
- # heartbeating:
171
- # * send PING every 100ms
172
- # * close connection after 300ms of no life sign from broker
173
- # * tell broker to close connection after 500ms of no life sign from client
174
- @socket.options.heartbeat_ivl = 100#ms
175
- @socket.options.heartbeat_timeout = 300#ms
176
- @socket.options.heartbeat_ttl = 500#ms
177
-
178
- @socket.connect(endpoint)
179
- puts ">>> connected."
180
-
181
- # tell broker who we are
182
- @socket << "HELLO\t#{client_cert["driver_name"]}"
183
- puts ">>> sent HELLO."
184
- welcome = @socket.receive[0]
185
- puts ">>> got #{welcome}."
186
-
187
- poller = CZTop::Poller.new(@socket)
188
- while true
189
- socket = poller.wait
190
- message = socket.receive
191
- puts ">>> received message: #{message[0].inspect}"
192
- end
193
- ```
194
-
195
- ## How to run the example
196
-
197
- ### Generate broker's and drivers' keys
198
-
199
- Here's a simple script that'll create the broker's certificate and the taxi
200
- drivers' certificates. There are also public key only files so a minimum amount
201
- of information can be made available on one system, e.g. a taxi driver's system
202
- must not know the broker's secret key. Also, the broker doesn't necessarily
203
- need to know the clients' secret keys just to authenticate them.
204
-
205
- ```ruby
206
- #!/usr/bin/env ruby
207
- require 'cztop'
208
- require 'fileutils'
209
- FileUtils.cd(File.dirname(__FILE__))
210
- FileUtils.mkdir "public_keys"
211
- FileUtils.mkdir "public_keys/drivers"
212
- FileUtils.mkdir "secret_keys"
213
- FileUtils.mkdir "secret_keys/drivers"
214
- #FileUtils.mkdir "certs/drivers"
215
-
216
- DRIVERS = %w[ driver1 driver2 driver3 ]
217
-
218
- # broker certificate
219
- cert = CZTop::Certificate.new
220
- cert.save("secret_keys/broker")
221
- cert.save_public("public_keys/broker")
222
-
223
- # driver certificates
224
- DRIVERS.each do |driver_name|
225
- cert = CZTop::Certificate.new
226
- cert["driver_name"] = driver_name
227
- cert.save "secret_keys/drivers/#{driver_name}"
228
- cert.save_public "public_keys/drivers/#{driver_name}"
229
- end
230
-
231
- ```
232
- Run it as follows:
233
-
234
- ```
235
- ./generate_keys.rb
236
- ```
237
-
238
- ### Start broker
239
-
240
- Run this:
241
-
242
- ```
243
- ./start_broker.sh
244
- ```
245
-
246
- which will execute the following script:
247
-
248
- ```sh
249
- #!/bin/sh -x
250
- BROKER_ADDRESS=tcp://127.0.0.1:4455 BROKER_CERT=secret_keys/broker CLIENT_CERTS=public_keys/drivers ./broker.rb
251
- ```
252
-
253
- ### Start driver software instances
254
-
255
- Run this in another terminal:
256
-
257
- ```
258
- ./start_clients.sh
259
- ```
260
-
261
- which will execute the following script:
262
-
263
- ```sh
264
- #!/bin/sh -x
265
- export BROKER_ADDRESS=tcp://127.0.0.1:4455
266
- export BROKER_CERT=public_keys/broker
267
- CLIENT_CERT=secret_keys/drivers/driver1_secret ./client.rb &
268
- CLIENT_CERT=secret_keys/drivers/driver2_secret ./client.rb &
269
- CLIENT_CERT=secret_keys/drivers/driver3_secret ./client.rb &
270
- jobs
271
- jobs -p
272
- jobs -l
273
- trap 'kill $(jobs -p)' EXIT
274
- wait
275
- ```
276
-
@@ -1,97 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'pry'
3
- require 'pathname'
4
- require 'cztop'
5
-
6
- endpoint = ENV["BROKER_ADDRESS"]
7
- broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # secret+public
8
- client_certs = ENV["CLIENT_CERTS"] # /path/to/client_certs/
9
- drivers = Pathname.new(client_certs).children.map(&:basename).map(&:to_s)
10
-
11
- authenticator = CZTop::Authenticator.new
12
- authenticator.verbose!
13
- authenticator.curve(client_certs)
14
-
15
- # create and bind socket
16
- @socket = CZTop::Socket::SERVER.new
17
- @socket.CURVE_server!(broker_cert)
18
- #socket.options.sndtimeo = 0
19
- @socket.options.heartbeat_ivl = 100#ms
20
- @socket.options.heartbeat_timeout = 300#ms
21
- @socket.bind(endpoint)
22
-
23
- puts ">>> Socket bound to #{endpoint.inspect}"
24
-
25
- # get and print socket events
26
- Thread.new do
27
- monitor = CZTop::Monitor.new(@socket)
28
- monitor.listen("ALL")
29
- monitor.start
30
- while msg = monitor.next
31
- puts ">>> Socket event: #{msg.inspect}"
32
- end
33
- end
34
-
35
- # receive messages from drivers
36
- @driver_map = {} # driver name => routing ID
37
- Thread.new do
38
-
39
- poller = CZTop::Poller.new(@socket)
40
- while true
41
- puts "waiting for socket to become readable ..."
42
- socket = poller.simple_wait
43
- puts "socket is readable"
44
- msg = socket.receive
45
- puts "got message"
46
- command, argument = msg[0].split("\t", 2)
47
-
48
- case command
49
- when "HELLO"
50
- driver = argument
51
- puts ">>> Driver #{driver.inspect} has connected."
52
- welcome = @driver_map.key?(driver) ? "WELCOMEBACK" : "WELCOME"
53
-
54
- # remember driver's assigned message routing ID
55
- @driver_map[driver] = msg.routing_id
56
-
57
- # send WELCOME or WELCOMEBACK
58
- rep = CZTop::Message.new(welcome)
59
- rep.routing_id = @driver_map[driver]
60
- socket << rep
61
- puts ">>> Sent #{welcome.inspect} to #{driver.inspect}"
62
- end
63
- end
64
- end
65
-
66
- def send_command(driver, command)
67
- if command.nil? || command.empty?
68
- puts "!!! No message given."
69
- return
70
- end
71
- if not @driver_map.key?(driver)
72
- puts "!!! Driver #{driver.inspect} has never connected."
73
- return
74
- end
75
- puts ">>> Sending message to #{driver.inspect} ..."
76
- msg = CZTop::Message.new(command)
77
- msg.routing_id = @driver_map[driver]
78
- @socket << msg
79
- rescue SocketError
80
- puts "!!! Driver #{driver.inspect} isn't connected anymore."
81
- end
82
-
83
- ##
84
- # REPL for user to play
85
- #
86
- puts <<MSG
87
- You can now send messages to the drivers yourself.
88
- The use the method #send_command, like this:
89
-
90
- pry> send_command("driver1", "PICKUP\t(8.541694,47.376887)")
91
-
92
- This should show something like this in the client.rb terminal:
93
-
94
- 03:17:01 driver1.1 | received message: "PICKUP\t(8.541694,47.376887)"
95
- MSG
96
-
97
- binding.pry
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'cztop'
3
-
4
- endpoint = ENV["BROKER_ADDRESS"]
5
- broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # public only
6
- client_cert = CZTop::Certificate.load ENV["CLIENT_CERT"]
7
-
8
- @socket = CZTop::Socket::CLIENT.new
9
- @socket.CURVE_client!(client_cert, broker_cert)
10
- @socket.options.sndtimeo = 2000#ms
11
-
12
- # heartbeating:
13
- # * send PING every 100ms
14
- # * close connection after 300ms of no life sign from broker
15
- # * tell broker to close connection after 500ms of no life sign from client
16
- @socket.options.heartbeat_ivl = 100#ms
17
- @socket.options.heartbeat_timeout = 300#ms
18
- @socket.options.heartbeat_ttl = 500#ms
19
-
20
- @socket.connect(endpoint)
21
- puts ">>> connected."
22
-
23
- # tell broker who we are
24
- @socket << "HELLO\t#{client_cert["driver_name"]}"
25
- puts ">>> sent HELLO."
26
- welcome = @socket.receive[0]
27
- puts ">>> got #{welcome}."
28
-
29
- poller = CZTop::Poller.new(@socket)
30
- while true
31
- socket = poller.simple_wait
32
- message = socket.receive
33
- puts ">>> received message: #{message[0].inspect}"
34
- end
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'cztop'
3
- require 'fileutils'
4
- FileUtils.cd(File.dirname(__FILE__))
5
- FileUtils.mkdir "public_keys"
6
- FileUtils.mkdir "public_keys/drivers"
7
- FileUtils.mkdir "secret_keys"
8
- FileUtils.mkdir "secret_keys/drivers"
9
- #FileUtils.mkdir "certs/drivers"
10
-
11
- DRIVERS = %w[ driver1 driver2 driver3 ]
12
-
13
- # broker certificate
14
- cert = CZTop::Certificate.new
15
- cert.save("secret_keys/broker")
16
- cert.save_public("public_keys/broker")
17
-
18
- # driver certificates
19
- DRIVERS.each do |driver_name|
20
- cert = CZTop::Certificate.new
21
- cert["driver_name"] = driver_name
22
- cert.save "secret_keys/drivers/#{driver_name}"
23
- cert.save_public "public_keys/drivers/#{driver_name}"
24
- end
@@ -1,2 +0,0 @@
1
- #!/bin/sh -x
2
- BROKER_ADDRESS=tcp://127.0.0.1:4455 BROKER_CERT=secret_keys/broker CLIENT_CERTS=public_keys/drivers ./broker.rb
@@ -1,11 +0,0 @@
1
- #!/bin/sh -x
2
- export BROKER_ADDRESS=tcp://127.0.0.1:4455
3
- export BROKER_CERT=public_keys/broker
4
- CLIENT_CERT=secret_keys/drivers/driver1_secret ./client.rb &
5
- CLIENT_CERT=secret_keys/drivers/driver2_secret ./client.rb &
6
- CLIENT_CERT=secret_keys/drivers/driver3_secret ./client.rb &
7
- jobs
8
- jobs -p
9
- jobs -l
10
- trap 'kill $(jobs -p)' EXIT
11
- wait
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Weather update server, based on ZMQ's zguide.
4
- # Binds PUB socket to ipc:///tmp/weather_pubsub_example
5
- # Publishes random weather updates
6
- #
7
-
8
- require 'cztop'
9
-
10
- # create and bind socket
11
- socket = CZTop::Socket::PUB.new("ipc:///tmp/weather_pubsub_example")
12
- puts "<<< Socket bound to #{socket.last_endpoint.inspect}"
13
-
14
- while true
15
- # Generate values for zipcodes
16
- zipcode = rand(100000)
17
- temperature = rand(215) - 80
18
- relhumidity = rand(50) + 10
19
-
20
- update = "%05d %d %d" % [zipcode, temperature, relhumidity]
21
- puts update
22
-
23
- socket << update
24
- end
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # Weather update client, based on that from ZMQ's zguide.
4
- # Connects SUB socket to ipc:///tmp/weather_pubsub_example
5
- # Collects weather updates and finds avg temp in zipcode
6
- #
7
-
8
- require 'cztop'
9
-
10
- COUNT = 100
11
-
12
- # Create socket, connect to publisher.
13
- socket = CZTop::Socket::SUB.new("ipc:///tmp/weather_pubsub_example")
14
- puts ">>> Socket Connected"
15
-
16
- # Subscribe to zipcode. Default: Chicago - 60606
17
- filter = ARGV.size > 0 ? ARGV[0] : "60606"
18
- socket.subscribe(filter)
19
-
20
- # gather & process COUNT updates.
21
- print "Gathering #{COUNT} samples."
22
- total_temp = 0
23
- 1.upto(COUNT) do |update_nbr|
24
- msg = socket.receive
25
-
26
- zipcode, temperature, relhumidity = msg[0].split.map(&:to_i)
27
- total_temp += temperature
28
- # just to show that we're doing something...
29
- print "." if update_nbr % 5 == 0
30
- end
31
- print "\n"
32
-
33
- puts "Average temperatuer for zipcode #{filter} was #{total_temp / COUNT}F."
data/perf/README.md DELETED
@@ -1,80 +0,0 @@
1
- # Performance Measurement
2
-
3
- This directory contains simple performance measurement utilities:
4
-
5
- - `inproc_lat.rb` measures the latency of the inproc transport
6
- - `inproc_thru.rb` measures the throughput of the inproc transport
7
- - `local_lat.rb` and `remote_lat.rb` measure the latency of other transports
8
- - `local_thru.rb` and `remote_thru.rb` measure the throughput of other transports (TODO)
9
-
10
- ## Example Output
11
-
12
- On my laptop, it currently looks something like this:
13
-
14
- ### Latency
15
-
16
- over inproc, using 10k roundtrips of a repeatedly allocated 1kb message:
17
- ```
18
- $ bundle exec ./inproc_lat_reqrep.rb 1_000 10_000
19
- message size: 1000 [B]
20
- roundtrip count: 10000
21
- elapsed time: 0.469 [s]
22
- average latency: 23.439 [us]<Paste>
23
- ```
24
-
25
- over IPC, using 10k roundtrips of a repeatedly allocated 1kb message:
26
- ```
27
- $ bundle exec ./local_lat.rb ipc:///tmp/cztop-perf 1000 1000 & ./remote_lat.rb ipc:///tmp/cztop-perf 1000 1000
28
- [3] 58043
29
- message size: 1000 [B]
30
- roundtrip count: 1000
31
- elapsed time: 0.091 [s]
32
- average latency: 45.482 [us]
33
- [3] 58043 done ./local_lat.rb ipc:///tmp/cztop-perf 1000 1000
34
- ```
35
-
36
- over local TCP/IP stack, using 10k roundtrips of a repeatedly allocated
37
- 1kb message:
38
- ```
39
- $ bundle exec ./local_lat.rb tcp://127.0.0.1:55667 1000 1000 & ./remote_lat.rb tcp://127.0.0.1:55667 1000 1000
40
- [3] 58064
41
- message size: 1000 [B]
42
- roundtrip count: 1000
43
- elapsed time: 0.123 [s]
44
- average latency: 61.434 [us]
45
- [3] 58064 done ./local_lat.rb tcp://127.0.0.1:55667 1000 1000
46
- ```
47
-
48
- ### Throughput
49
-
50
- over inproc, with message sizes from 100 bytes to 100kb, 10,000 each:
51
-
52
- ```
53
- $ bundle exec ./inproc_thru.rb 100 10_000
54
- message size: 100 [B]
55
- message count: 10000
56
- elapsed time: 0.270 [s]
57
- mean throughput: 37093 [msg/s]
58
- mean throughput: 29.674 [Mb/s]
59
-
60
- $ bundle exec ./inproc_thru.rb 1_000 10_000
61
- message size: 1000 [B]
62
- message count: 10000
63
- elapsed time: 0.260 [s]
64
- mean throughput: 38498 [msg/s]
65
- mean throughput: 307.987 [Mb/s]
66
-
67
- $ bundle exec ./inproc_thru.rb 10_000 10_000
68
- message size: 10000 [B]
69
- message count: 10000
70
- elapsed time: 0.317 [s]
71
- mean throughput: 31501 [msg/s]
72
- mean throughput: 2520.102 [Mb/s]
73
-
74
- $ bundle exec ./inproc_thru.rb 100_000 10_000
75
- message size: 100000 [B]
76
- message count: 10000
77
- elapsed time: 0.906 [s]
78
- mean throughput: 11034 [msg/s]
79
- mean throughput: 8827.440 [Mb/s]
80
- ```
data/perf/inproc_lat.rb DELETED
@@ -1,49 +0,0 @@
1
- #! /usr/bin/env ruby
2
- require "cztop"
3
- require "benchmark"
4
- #require "ruby-prof"
5
-
6
- if ARGV.size != 2
7
- abort <<MSG
8
- Usage: #{$0} <message-size> <roundtrip-count>
9
- MSG
10
- end
11
-
12
- MSG_SIZE = Integer(ARGV[0]) # bytes
13
- ROUNDTRIP_COUNT = Integer(ARGV[1]) # round trips
14
- MSG = "X" * MSG_SIZE
15
-
16
- Thread.new do
17
- s = CZTop::Socket::PAIR.new("@inproc://perf")
18
- s.signal
19
- ROUNDTRIP_COUNT.times do
20
- msg = s.receive
21
- raise "wrong message size" if msg.content_size != MSG_SIZE
22
- s << msg
23
- end
24
- end
25
-
26
- s = CZTop::Socket::PAIR.new(">inproc://perf")
27
- s.wait
28
-
29
- #RubyProf.start
30
- tms = Benchmark.measure do
31
- ROUNDTRIP_COUNT.times do
32
- s << MSG
33
- msg = s.receive
34
- raise "wrong message size" if msg.content_size != MSG_SIZE
35
- end
36
- end
37
- #rubyprof_result = RubyProf.stop
38
-
39
- elapsed = tms.real
40
- latency = elapsed / (ROUNDTRIP_COUNT * 2) * 1_000_000
41
- puts "message size: #{MSG_SIZE} [B]"
42
- puts "roundtrip count: #{ROUNDTRIP_COUNT}"
43
- puts "elapsed time: %.3f [s]" % elapsed
44
- puts "average latency: %.3f [us]" % latency
45
-
46
- # print a flat profile to text
47
- #printer = RubyProf::FlatPrinter.new(rubyprof_result)
48
- #printer.print(STDOUT)
49
-
data/perf/inproc_thru.rb DELETED
@@ -1,42 +0,0 @@
1
- #! /usr/bin/env ruby
2
- require "cztop"
3
- require "benchmark"
4
-
5
- if ARGV.size != 2
6
- abort <<MSG
7
- Usage: #{$0} <message-size> <message-count>
8
- MSG
9
- end
10
-
11
- MSG_SIZE = Integer(ARGV[0]) # bytes
12
- MSG_COUNT = Integer(ARGV[1]) # number of messages
13
- MSG = "X" * MSG_SIZE
14
-
15
- Thread.new do
16
- s = CZTop::Socket::PAIR.new("@inproc://perf")
17
- s.signal
18
- MSG_COUNT.times do
19
- msg = s.receive
20
- raise "wrong message size" if msg.content_size != MSG_SIZE
21
- end
22
- end
23
-
24
- s = CZTop::Socket::PAIR.new(">inproc://perf")
25
- s.wait
26
-
27
- tms = Benchmark.measure do
28
- MSG_COUNT.times do
29
- s << MSG
30
- end
31
- end
32
-
33
- elapsed = tms.real
34
-
35
- throughput = MSG_COUNT / elapsed
36
- megabits = (throughput * MSG_SIZE * 8) / 1_000_000
37
-
38
- puts "message size: #{MSG_SIZE} [B]"
39
- puts "message count: #{MSG_COUNT}"
40
- puts "elapsed time: %.3f [s]" % elapsed
41
- puts "mean throughput: %d [msg/s]" % throughput
42
- puts "mean throughput: %.3f [Mb/s]" % megabits