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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +31 -0
- data/.yardopts +1 -0
- data/AUTHORS +1 -0
- data/CHANGES.md +3 -0
- data/Gemfile +10 -0
- data/Guardfile +61 -0
- data/LICENSE +5 -0
- data/Procfile +3 -0
- data/README.md +408 -0
- data/Rakefile +6 -0
- data/bin/console +7 -0
- data/bin/setup +7 -0
- data/ci-scripts/install-deps +9 -0
- data/cztop.gemspec +36 -0
- data/examples/ruby_actor/actor.rb +100 -0
- data/examples/simple_req_rep/rep.rb +12 -0
- data/examples/simple_req_rep/req.rb +35 -0
- data/examples/taxi_system/.gitignore +2 -0
- data/examples/taxi_system/Makefile +2 -0
- data/examples/taxi_system/README.gsl +115 -0
- data/examples/taxi_system/README.md +276 -0
- data/examples/taxi_system/broker.rb +98 -0
- data/examples/taxi_system/client.rb +34 -0
- data/examples/taxi_system/generate_keys.rb +24 -0
- data/examples/taxi_system/start_broker.sh +2 -0
- data/examples/taxi_system/start_clients.sh +11 -0
- data/lib/cztop/actor.rb +308 -0
- data/lib/cztop/authenticator.rb +97 -0
- data/lib/cztop/beacon.rb +96 -0
- data/lib/cztop/certificate.rb +176 -0
- data/lib/cztop/config/comments.rb +66 -0
- data/lib/cztop/config/serialization.rb +82 -0
- data/lib/cztop/config/traversing.rb +157 -0
- data/lib/cztop/config.rb +119 -0
- data/lib/cztop/frame.rb +158 -0
- data/lib/cztop/has_ffi_delegate.rb +85 -0
- data/lib/cztop/message/frames.rb +74 -0
- data/lib/cztop/message.rb +191 -0
- data/lib/cztop/monitor.rb +102 -0
- data/lib/cztop/poller.rb +334 -0
- data/lib/cztop/polymorphic_zsock_methods.rb +24 -0
- data/lib/cztop/proxy.rb +149 -0
- data/lib/cztop/send_receive_methods.rb +35 -0
- data/lib/cztop/socket/types.rb +207 -0
- data/lib/cztop/socket.rb +106 -0
- data/lib/cztop/version.rb +3 -0
- data/lib/cztop/z85.rb +157 -0
- data/lib/cztop/zsock_options.rb +334 -0
- data/lib/cztop.rb +55 -0
- data/perf/README.md +79 -0
- data/perf/inproc_lat.rb +49 -0
- data/perf/inproc_thru.rb +42 -0
- data/perf/local_lat.rb +35 -0
- data/perf/remote_lat.rb +26 -0
- 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
|
+
```
|
data/perf/inproc_lat.rb
ADDED
@@ -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
|
+
|
data/perf/inproc_thru.rb
ADDED
@@ -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
|
data/perf/remote_lat.rb
ADDED
@@ -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
|