cztop 0.1.0

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +31 -0
  5. data/.yardopts +1 -0
  6. data/AUTHORS +1 -0
  7. data/CHANGES.md +3 -0
  8. data/Gemfile +10 -0
  9. data/Guardfile +61 -0
  10. data/LICENSE +5 -0
  11. data/Procfile +3 -0
  12. data/README.md +408 -0
  13. data/Rakefile +6 -0
  14. data/bin/console +7 -0
  15. data/bin/setup +7 -0
  16. data/ci-scripts/install-deps +9 -0
  17. data/cztop.gemspec +36 -0
  18. data/examples/ruby_actor/actor.rb +100 -0
  19. data/examples/simple_req_rep/rep.rb +12 -0
  20. data/examples/simple_req_rep/req.rb +35 -0
  21. data/examples/taxi_system/.gitignore +2 -0
  22. data/examples/taxi_system/Makefile +2 -0
  23. data/examples/taxi_system/README.gsl +115 -0
  24. data/examples/taxi_system/README.md +276 -0
  25. data/examples/taxi_system/broker.rb +98 -0
  26. data/examples/taxi_system/client.rb +34 -0
  27. data/examples/taxi_system/generate_keys.rb +24 -0
  28. data/examples/taxi_system/start_broker.sh +2 -0
  29. data/examples/taxi_system/start_clients.sh +11 -0
  30. data/lib/cztop/actor.rb +308 -0
  31. data/lib/cztop/authenticator.rb +97 -0
  32. data/lib/cztop/beacon.rb +96 -0
  33. data/lib/cztop/certificate.rb +176 -0
  34. data/lib/cztop/config/comments.rb +66 -0
  35. data/lib/cztop/config/serialization.rb +82 -0
  36. data/lib/cztop/config/traversing.rb +157 -0
  37. data/lib/cztop/config.rb +119 -0
  38. data/lib/cztop/frame.rb +158 -0
  39. data/lib/cztop/has_ffi_delegate.rb +85 -0
  40. data/lib/cztop/message/frames.rb +74 -0
  41. data/lib/cztop/message.rb +191 -0
  42. data/lib/cztop/monitor.rb +102 -0
  43. data/lib/cztop/poller.rb +334 -0
  44. data/lib/cztop/polymorphic_zsock_methods.rb +24 -0
  45. data/lib/cztop/proxy.rb +149 -0
  46. data/lib/cztop/send_receive_methods.rb +35 -0
  47. data/lib/cztop/socket/types.rb +207 -0
  48. data/lib/cztop/socket.rb +106 -0
  49. data/lib/cztop/version.rb +3 -0
  50. data/lib/cztop/z85.rb +157 -0
  51. data/lib/cztop/zsock_options.rb +334 -0
  52. data/lib/cztop.rb +55 -0
  53. data/perf/README.md +79 -0
  54. data/perf/inproc_lat.rb +49 -0
  55. data/perf/inproc_thru.rb +42 -0
  56. data/perf/local_lat.rb +35 -0
  57. data/perf/remote_lat.rb +26 -0
  58. metadata +297 -0
@@ -0,0 +1,334 @@
1
+ module CZTop
2
+ # This module adds the ability to access options of a {Socket} or an
3
+ # {Actor}.
4
+ #
5
+ # @note Most socket options only take effect for subsequent bind/connects.
6
+ #
7
+ # @see http://api.zeromq.org/4-1:zmq-setsockopt
8
+ # @see http://api.zeromq.org/4-1:zmq-getsockopt
9
+ # @see http://api.zeromq.org/czmq3-0:zsock-option
10
+ #
11
+ module ZsockOptions
12
+ # Access to the options of this socket.
13
+ # @return [OptionsAccessor]
14
+ def options
15
+ OptionsAccessor.new(self)
16
+ end
17
+
18
+ # Used to access the options of a {Socket} or {Actor}.
19
+ class OptionsAccessor
20
+ # @return [Socket, Actor] whose options this {OptionsAccessor} instance
21
+ # is accessing
22
+ attr_reader :zocket
23
+
24
+ # @param zocket [Socket, Actor]
25
+ def initialize(zocket)
26
+ @zocket = zocket
27
+ end
28
+
29
+ # Fuzzy option getter. This is to make it easier when porting
30
+ # applications from CZMQ libraries to CZTop.
31
+ # @param option_name [Symbol, String] case insensitive option name
32
+ # @raise [NoMethodError] if option name can't be recognized
33
+ def [](option_name)
34
+ # NOTE: beware of predicates, especially #CURVE_server? & friends
35
+ m = public_methods.reject { |m| m =~ /=$/ }
36
+ .find { |m| m =~ /^#{option_name}\??$/i }
37
+ raise NoMethodError, option_name if m.nil?
38
+ __send__(m)
39
+ end
40
+
41
+ # Fuzzy option setter. This is to make it easier when porting
42
+ # applications from CZMQ libraries to CZTop.
43
+ # @param option_name [Symbol, String] case insensitive option name
44
+ # @param new_value [String, Integer] new value
45
+ # @raise [NoMethodError] if option name can't be recognized
46
+ def []=(option_name, new_value)
47
+ m = public_methods.find { |m| m =~ /^#{option_name}=$/i }
48
+ raise NoMethodError, option_name if m.nil?
49
+ __send__(m, new_value)
50
+ end
51
+
52
+ include CZMQ::FFI
53
+
54
+ # @!group High Water Marks
55
+
56
+ # @return [Integer] the send high water mark
57
+ def sndhwm() Zsock.sndhwm(@zocket) end
58
+ # @param value [Integer] the new send high water mark.
59
+ def sndhwm=(value) Zsock.set_sndhwm(@zocket, value) end
60
+ # @return [Integer] the receive high water mark
61
+ def rcvhwm() Zsock.rcvhwm(@zocket) end
62
+ # @param value [Integer] the new receive high water mark
63
+ def rcvhwm=(value) Zsock.set_rcvhwm(@zocket, value) end
64
+
65
+ # @!endgroup
66
+
67
+ # @!group (CURVE) Security
68
+
69
+ # @return [Boolean] whether this zocket is a CURVE server
70
+ def CURVE_server?() Zsock.curve_server(@zocket) > 0 end
71
+
72
+ # Make this zocket a CURVE server.
73
+ # @param bool [Boolean]
74
+ # @note You'll have to use a {CZTop::Authenticator}.
75
+ def CURVE_server=(bool)
76
+ Zsock.set_curve_server(@zocket, bool ? 1 : 0)
77
+ end
78
+
79
+ # @return [String] Z85 encoded server key set
80
+ # @return [nil] if the current mechanism isn't CURVE or CURVE isn't
81
+ # supported
82
+ def CURVE_serverkey
83
+ CURVE_key(:curve_serverkey)
84
+ end
85
+
86
+ # Get one of the CURVE keys.
87
+ # @param key_name [Symbol] something like +:curve_serverkey+
88
+ # @return [String, nil] key, if CURVE is supported and active, or nil
89
+ def CURVE_key(key_name)
90
+ return nil if mechanism != :CURVE
91
+ ptr = Zsock.__send__(key_name, @zocket)
92
+ return nil if ptr.null?
93
+ ptr.read_string
94
+ end
95
+ private :CURVE_key
96
+
97
+ # Sets the server's public key, so the zocket can authenticate the
98
+ # remote server.
99
+ # @param key [String] Z85 (40 bytes) or binary (32 bytes) server key
100
+ # @raise [ArgumentError] if key has wrong size
101
+ def CURVE_serverkey=(key)
102
+ case key.bytesize
103
+ when 40
104
+ Zsock.set_curve_serverkey(@zocket, key)
105
+ when 32
106
+ ptr = ::FFI::MemoryPointer.from_string(key)
107
+ Zsock.set_curve_serverkey_bin(@zocket, ptr)
108
+ else
109
+ raise ArgumentError, "invalid server key: %p" % key
110
+ end
111
+ end
112
+
113
+ # supported security mechanisms and their macro value equivalent
114
+ MECHANISMS = {
115
+ 0 => :NULL, # ZMQ_NULL
116
+ 1 => :PLAIN, # ZMQ_PLAIN
117
+ 2 => :CURVE, # ZMQ_CURVE
118
+ 3 => :GSSAPI # ZMQ_GSSAPI
119
+ }
120
+
121
+ # @return [Symbol] the current security mechanism in use
122
+ # @note This is automatically set through the use of CURVE certificates,
123
+ # etc
124
+ def mechanism
125
+ #int zsock_mechanism (void *self);
126
+ code = Zsock.mechanism(@zocket)
127
+ MECHANISMS[code] or
128
+ raise "unknown ZMQ security mechanism code: %i" % code
129
+ end
130
+
131
+ # @return [String] Z85 encoded secret key set
132
+ # @return [nil] if the current mechanism isn't CURVE or CURVE isn't
133
+ # supported
134
+ def CURVE_secretkey
135
+ CURVE_key(:curve_secretkey)
136
+ end
137
+
138
+ # @return [String] Z85 encoded public key set
139
+ # @return [nil] if the current mechanism isn't CURVE or CURVE isn't
140
+ # supported
141
+ def CURVE_publickey
142
+ CURVE_key(:curve_publickey)
143
+ end
144
+
145
+ # Gets the ZAP domain used for authentication.
146
+ # @see http://rfc.zeromq.org/spec:27
147
+ # @return [String]
148
+ def zap_domain
149
+ Zsock.zap_domain(@zocket).read_string
150
+ end
151
+ # Sets the ZAP domain used for authentication.
152
+ # @param domain [String] the new ZAP domain
153
+ def zap_domain=(domain)
154
+ raise ArgumentError, "domain too long" if domain.bytesize > 254
155
+ Zsock.set_zap_domain(@zocket, domain)
156
+ end
157
+
158
+ # @return [Boolean] whether this zocket is a PLAIN server
159
+ def PLAIN_server?() Zsock.plain_server(@zocket) > 0 end
160
+
161
+ # Make this zocket a PLAIN server.
162
+ # @param bool [Boolean]
163
+ # @note You'll have to use a {CZTop::Authenticator}.
164
+ def PLAIN_server=(bool)
165
+ Zsock.set_plain_server(@zocket, bool ? 1 : 0)
166
+ end
167
+
168
+ # @return [String] username set for PLAIN mechanism
169
+ # @return [nil] if the current mechanism isn't PLAIN
170
+ def PLAIN_username
171
+ return nil if mechanism != :PLAIN
172
+ Zsock.plain_username(@zocket).read_string
173
+ end
174
+ # @param username [String] username for PLAIN mechanism
175
+ # @note You'll have to use a {CZTop::Authenticator}.
176
+ def PLAIN_username=(username)
177
+ Zsock.set_plain_username(@zocket, username)
178
+ end
179
+ # @return [String] password set for PLAIN mechanism
180
+ # @return [nil] if the current mechanism isn't PLAIN
181
+ def PLAIN_password
182
+ return nil if mechanism != :PLAIN
183
+ Zsock.plain_password(@zocket).read_string
184
+ end
185
+ # @param password [String] password for PLAIN mechanism
186
+ def PLAIN_password=(password)
187
+ Zsock.set_plain_password(@zocket, password)
188
+ end
189
+
190
+ # @!endgroup
191
+
192
+ # @!group Send and Receive Timeouts
193
+
194
+ # @return [Integer] the timeout when receiving a message
195
+ # @see Message.receive_from
196
+ def rcvtimeo() Zsock.rcvtimeo(@zocket) end
197
+ # @param timeout [Integer] new timeout
198
+ # @see Message.receive_from
199
+ def rcvtimeo=(timeout) Zsock.set_rcvtimeo(@zocket, timeout) end
200
+
201
+ # @return [Integer] the timeout when sending a message
202
+ # @see Message#send_to
203
+ def sndtimeo() Zsock.sndtimeo(@zocket) end
204
+ # @param timeout [Integer] new timeout
205
+ # @see Message#send_to
206
+ def sndtimeo=(timeout) Zsock.set_sndtimeo(@zocket, timeout) end
207
+
208
+ # @!endgroup
209
+
210
+ # Accept only routable messages on ROUTER sockets. Default is off.
211
+ # @param bool [Boolean] whether to error if a message isn't routable
212
+ # (either if the that peer isn't connected or its SNDHWM is reached)
213
+ def router_mandatory=(bool)
214
+ Zsock.set_router_mandatory(@zocket, bool ? 1 : 0)
215
+ end
216
+
217
+ # @return [String] current socket identity
218
+ def identity() Zsock.identity(@zocket).read_string end
219
+ # @param identity [String] new socket identity
220
+ def identity=(identity) Zsock.set_identity(@zocket, identity) end
221
+
222
+ # @return [Integer] current value of Type of Service
223
+ def tos() Zsock.tos(@zocket) end
224
+ # @param new_value [Integer] new value for Type of Service
225
+ def tos=(new_value)
226
+ raise ArgumentError, "invalid TOS" unless new_value >= 0
227
+ Zsock.set_tos(@zocket, new_value)
228
+ end
229
+
230
+ # @return [Integer] current value of Heartbeat IVL
231
+ def heartbeat_ivl() Zsock.heartbeat_ivl(@zocket) end
232
+ # @param new_value [Integer] new value for Heartbeat IVL
233
+ def heartbeat_ivl=(new_value)
234
+ raise ArgumentError, "invalid IVL" unless new_value >= 0
235
+ Zsock.set_heartbeat_ivl(@zocket, new_value)
236
+ end
237
+
238
+ # @return [Integer] current value of Heartbeat TTL, in milliseconds
239
+ def heartbeat_ttl() Zsock.heartbeat_ttl(@zocket) end
240
+ # @param new_value [Integer] new value for Heartbeat TTL, in
241
+ # milliseconds
242
+ # @note The value will internally be rounded to the nearest decisecond.
243
+ # So a value of less than 100 will have no effect.
244
+ def heartbeat_ttl=(new_value)
245
+ unless new_value.is_a? Integer
246
+ raise ArgumentError, "invalid TTL: #{new_value}"
247
+ end
248
+ unless (0..65536).include? new_value
249
+ raise ArgumentError, "TTL out of range: #{new_value}"
250
+ end
251
+ Zsock.set_heartbeat_ttl(@zocket, new_value)
252
+ end
253
+
254
+ # @return [Integer] current value of Heartbeat Timeout
255
+ def heartbeat_timeout() Zsock.heartbeat_timeout(@zocket) end
256
+ # @param new_value [Integer] new value for Heartbeat Timeout
257
+ def heartbeat_timeout=(new_value)
258
+ raise ArgumentError, "invalid timeout" unless new_value >= 0
259
+ Zsock.set_heartbeat_timeout(@zocket, new_value)
260
+ end
261
+
262
+ # @return [Integer] current value of LINGER
263
+ def linger() Zsock.linger(@zocket) end
264
+ # This defines the number of milliseconds to wait while
265
+ # closing/disconnecting a socket if there are outstanding messages to
266
+ # send.
267
+ #
268
+ # Default is 0, which means to not wait at all. -1 means to wait
269
+ # indefinitely
270
+ #
271
+ # @param new_value [Integer] new value for LINGER
272
+ def linger=(new_value)
273
+ Zsock.set_linger(@zocket, new_value)
274
+ end
275
+
276
+ # TODO: a reasonable subset of these
277
+ #// Get socket options
278
+ #int zsock_gssapi_server (void *self);
279
+ #int zsock_gssapi_plaintext (void *self);
280
+ #char * zsock_gssapi_principal (void *self);
281
+ #char * zsock_gssapi_service_principal (void *self);
282
+ #int zsock_ipv6 (void *self);
283
+ #int zsock_immediate (void *self);
284
+ #int zsock_type (void *self);
285
+ #int zsock_affinity (void *self);
286
+ #int zsock_rate (void *self);
287
+ #int zsock_recovery_ivl (void *self);
288
+ #int zsock_sndbuf (void *self);
289
+ #int zsock_rcvbuf (void *self);
290
+ #int zsock_reconnect_ivl (void *self);
291
+ #int zsock_reconnect_ivl_max (void *self);
292
+ #int zsock_backlog (void *self);
293
+ #int zsock_maxmsgsize (void *self);
294
+ #int zsock_multicast_hops (void *self);
295
+ #int zsock_tcp_keepalive (void *self);
296
+ #int zsock_tcp_keepalive_idle (void *self);
297
+ #int zsock_tcp_keepalive_cnt (void *self);
298
+ #int zsock_tcp_keepalive_intvl (void *self);
299
+ #int zsock_rcvmore (void *self);
300
+ #SOCKET zsock_fd (void *self);
301
+ #int zsock_events (void *self);
302
+ #char * zsock_last_endpoint (void *self);
303
+ #
304
+ #// Set socket options
305
+ #void zsock_set_router_handover (void *self, int router_handover);
306
+ #void zsock_set_probe_router (void *self, int probe_router);
307
+ #void zsock_set_req_relaxed (void *self, int req_relaxed);
308
+ #void zsock_set_req_correlate (void *self, int req_correlate);
309
+ #void zsock_set_conflate (void *self, int conflate);
310
+ #void zsock_set_gssapi_server (void *self, int gssapi_server);
311
+ #void zsock_set_gssapi_plaintext (void *self, int gssapi_plaintext);
312
+ #void zsock_set_gssapi_principal (void *self, const char * gssapi_principal);
313
+ #void zsock_set_gssapi_service_principal (void *self, const char * gssapi_service_principal);
314
+ #void zsock_set_ipv6 (void *self, int ipv6);
315
+ #void zsock_set_immediate (void *self, int immediate);
316
+ #void zsock_set_delay_attach_on_connect (void *self, int delay_attach_on_connect);
317
+ #void zsock_set_affinity (void *self, int affinity);
318
+ #void zsock_set_rate (void *self, int rate);
319
+ #void zsock_set_recovery_ivl (void *self, int recovery_ivl);
320
+ #void zsock_set_sndbuf (void *self, int sndbuf);
321
+ #void zsock_set_rcvbuf (void *self, int rcvbuf);
322
+ #void zsock_set_reconnect_ivl (void *self, int reconnect_ivl);
323
+ #void zsock_set_reconnect_ivl_max (void *self, int reconnect_ivl_max);
324
+ #void zsock_set_backlog (void *self, int backlog);
325
+ #void zsock_set_maxmsgsize (void *self, int maxmsgsize);
326
+ #void zsock_set_multicast_hops (void *self, int multicast_hops);
327
+ #void zsock_set_xpub_verbose (void *self, int xpub_verbose);
328
+ #void zsock_set_tcp_keepalive (void *self, int tcp_keepalive);
329
+ #void zsock_set_tcp_keepalive_idle (void *self, int tcp_keepalive_idle);
330
+ #void zsock_set_tcp_keepalive_cnt (void *self, int tcp_keepalive_cnt);
331
+ #void zsock_set_tcp_keepalive_intvl (void *self, int tcp_keepalive_intvl);
332
+ end
333
+ end
334
+ end
data/lib/cztop.rb ADDED
@@ -0,0 +1,55 @@
1
+ require 'czmq-ffi-gen'
2
+ require_relative 'cztop/version'
3
+
4
+ # CZTop tries to provide a complete CZMQ binding with a nice, Ruby-like API.
5
+ module CZTop
6
+ end
7
+
8
+ # modules
9
+ require_relative 'cztop/has_ffi_delegate'
10
+ require_relative 'cztop/zsock_options'
11
+ require_relative 'cztop/send_receive_methods'
12
+ require_relative 'cztop/polymorphic_zsock_methods'
13
+
14
+ # CZMQ classes
15
+ require_relative 'cztop/actor'
16
+ require_relative 'cztop/authenticator'
17
+ require_relative 'cztop/beacon'
18
+ require_relative 'cztop/certificate'
19
+ require_relative 'cztop/config'
20
+ require_relative 'cztop/frame'
21
+ require_relative 'cztop/message'
22
+ require_relative 'cztop/monitor'
23
+ require_relative 'cztop/poller'
24
+ require_relative 'cztop/proxy'
25
+ require_relative 'cztop/socket'
26
+ require_relative 'cztop/z85'
27
+
28
+ # additional
29
+ require_relative 'cztop/config/comments'
30
+ require_relative 'cztop/config/traversing'
31
+ require_relative 'cztop/config/serialization'
32
+ require_relative 'cztop/message/frames'
33
+ require_relative 'cztop/socket/types'
34
+
35
+
36
+ # make Ctrl-C work in case a low-level call hangs
37
+ CZMQ::FFI::Signals.disable_default_handling
38
+
39
+ ##
40
+ # Probably useless in this Ruby binding:
41
+ #
42
+ # * CertificateStore
43
+ # * UUID
44
+ # * Dir
45
+ # * DirPatch
46
+ # * File
47
+ # * HashX
48
+ # * String
49
+ # * Trie
50
+ # * Hash
51
+ # * List
52
+
53
+ # Implemented before, but removed because useless:
54
+ #
55
+ # * Loop
data/perf/README.md ADDED
@@ -0,0 +1,79 @@
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_thr.rb` measures the throughput of the inproc transport
7
+ - `local_lat.rb` and `remote_lat.rb` measure the latency other transports
8
+ - `local_thr.rb` and `remote_thr.rb` measure the throughput other transports
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
+ $ ./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
+ $ ./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
+ [3] 58064
40
+ message size: 1000 [B]
41
+ roundtrip count: 1000
42
+ elapsed time: 0.123 [s]
43
+ average latency: 61.434 [us]
44
+ [3] 58064 done ./local_lat.rb tcp://127.0.0.1:55667 1000 1000
45
+ ```
46
+
47
+ ### Throughput
48
+
49
+ over inproc, with message sizes from 100 bytes to 100kb, 10,000 each:
50
+
51
+ ```
52
+ $ ./inproc_thru.rb 100 10_000
53
+ message size: 100 [B]
54
+ message count: 10000
55
+ elapsed time: 0.270 [s]
56
+ mean throughput: 37093 [msg/s]
57
+ mean throughput: 29.674 [Mb/s]
58
+
59
+ $ ./inproc_thru.rb 1_000 10_000
60
+ message size: 1000 [B]
61
+ message count: 10000
62
+ elapsed time: 0.260 [s]
63
+ mean throughput: 38498 [msg/s]
64
+ mean throughput: 307.987 [Mb/s]
65
+
66
+ $ ./inproc_thru.rb 10_000 10_000
67
+ message size: 10000 [B]
68
+ message count: 10000
69
+ elapsed time: 0.317 [s]
70
+ mean throughput: 31501 [msg/s]
71
+ mean throughput: 2520.102 [Mb/s]
72
+
73
+ $ ./inproc_thru.rb 100_000 10_000
74
+ message size: 100000 [B]
75
+ message count: 10000
76
+ elapsed time: 0.906 [s]
77
+ mean throughput: 11034 [msg/s]
78
+ mean throughput: 8827.440 [Mb/s]
79
+ ```
@@ -0,0 +1,49 @@
1
+ #! /usr/bin/env ruby
2
+ require_relative "../lib/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
+
@@ -0,0 +1,42 @@
1
+ #! /usr/bin/env ruby
2
+ require_relative "../lib/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
data/perf/local_lat.rb ADDED
@@ -0,0 +1,35 @@
1
+ #! /usr/bin/env ruby
2
+ require_relative "../lib/cztop"
3
+ require "benchmark"
4
+
5
+ if ARGV.size != 3
6
+ abort <<MSG
7
+ Usage: #{$0} <bind-to> <message-size> <roundtrip-count>
8
+ MSG
9
+ end
10
+
11
+ ENDPOINT = ARGV[0]
12
+ MSG_SIZE = Integer(ARGV[1]) # bytes
13
+ ROUNDTRIP_COUNT = Integer(ARGV[2]) # round trips
14
+ MSG = "X" * MSG_SIZE
15
+
16
+ s = CZTop::Socket::REP.new(ENDPOINT)
17
+
18
+ # synchronize
19
+ s.wait
20
+ s.signal
21
+
22
+ tms = Benchmark.measure do
23
+ ROUNDTRIP_COUNT.times do
24
+ msg = s.receive
25
+ raise "wrong message size" if msg.content_size != MSG_SIZE
26
+ s << msg
27
+ end
28
+ end
29
+
30
+ elapsed = tms.real
31
+ latency = elapsed / (ROUNDTRIP_COUNT * 2) * 1_000_000
32
+ puts "message size: #{MSG_SIZE} [B]"
33
+ puts "roundtrip count: #{ROUNDTRIP_COUNT}"
34
+ puts "elapsed time: %.3f [s]" % elapsed
35
+ puts "average latency: %.3f [us]" % latency
@@ -0,0 +1,26 @@
1
+ #! /usr/bin/env ruby
2
+ require_relative "../lib/cztop"
3
+ require "benchmark"
4
+
5
+ if ARGV.size != 3
6
+ abort <<MSG
7
+ Usage: #{$0} <connect-to> <message-size> <roundtrip-count>
8
+ MSG
9
+ end
10
+
11
+ ENDPOINT = ARGV[0]
12
+ MSG_SIZE = Integer(ARGV[1]) # bytes
13
+ ROUNDTRIP_COUNT = Integer(ARGV[2]) # round trips
14
+ MSG = "X" * MSG_SIZE
15
+
16
+ s = CZTop::Socket::REQ.new(ENDPOINT)
17
+
18
+ # synchronize
19
+ s.signal
20
+ s.wait
21
+
22
+ ROUNDTRIP_COUNT.times do
23
+ s << MSG
24
+ msg = s.receive
25
+ raise "wrong message size" if msg.content_size != MSG_SIZE
26
+ end