ffi-rzmq 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,21 @@
1
+ == 0.9.3 / 20111214
2
+ * Performance optimizations for #getsockopt.
3
+
4
+ * Fixed Message#copy and Message#move. They didn't work before.
5
+
6
+ * Cache LibZM::Msg.size in the ZMQ::Message class so that
7
+ initialization can skip recalculating what is effectively a
8
+ constant value. This speeds up ZMQ::Message instantiation by
9
+ 5 to 10%. Wow.
10
+
11
+ * Modified calls to #super to use explicit arguments (e.g. #super())
12
+ because otherwise the Ruby runtime has to (at runtime) dig out
13
+ the arguments that are expected to be passed up the chain. By
14
+ explicitly listing the args and using parentheses, the runtime
15
+ can avoid that work and dispatch directly. This effects all
16
+ Ruby runtimes, but it was through the work of Evan Phoenix that
17
+ I figured this out. Results in a 2-5% speedup on method dispatch.
18
+
1
19
  == 0.9.2 / 20111115
2
20
  * Removed all references to the version4 API.
3
21
 
@@ -21,7 +21,7 @@ MRI 1.9.x, Rubinius and JRuby.}
21
21
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
22
  s.require_paths = ["lib"]
23
23
 
24
- s.add_runtime_dependency "ffi", [">= 1.0.9"]
24
+ s.add_runtime_dependency "ffi"#, [">= 1.0.9"]
25
25
  s.add_development_dependency "rspec", ["~> 2.6"]
26
26
  s.add_development_dependency "rake"
27
27
  end
@@ -94,12 +94,10 @@ module ZMQ
94
94
  end
95
95
 
96
96
  def initialize message = nil
97
- @state = :uninitialized
98
-
99
97
  # allocate our own pointer so that we can tell it to *not* zero out
100
98
  # the memory; it's pointless work since the library is going to
101
99
  # overwrite it anyway.
102
- @pointer = FFI::MemoryPointer.new LibZMQ::Msg.size, 1, false
100
+ @pointer = FFI::MemoryPointer.new Message.msg_size, 1, false
103
101
 
104
102
  if message
105
103
  copy_in_string message
@@ -147,11 +145,11 @@ module ZMQ
147
145
  alias :pointer :address
148
146
 
149
147
  def copy source
150
- LibZMQ.zmq_msg_copy @pointer, source.address
148
+ LibZMQ.zmq_msg_copy @pointer, source
151
149
  end
152
150
 
153
151
  def move source
154
- LibZMQ.zmq_msg_move @pointer, source.address
152
+ LibZMQ.zmq_msg_move @pointer, source
155
153
  end
156
154
 
157
155
  # Provides the size of the data buffer for this +zmq_msg_t+ C struct.
@@ -193,6 +191,12 @@ module ZMQ
193
191
 
194
192
  rc
195
193
  end
194
+
195
+ # cache the msg size so we don't have to recalculate it when creating
196
+ # each new instance
197
+ @msg_size = LibZMQ::Msg.size
198
+
199
+ def self.msg_size() @msg_size; end
196
200
 
197
201
  end # class Message
198
202
 
@@ -228,7 +232,7 @@ module ZMQ
228
232
  # handles deallocation of the native memory buffer.
229
233
  #
230
234
  def copy_in_bytes bytes, len
231
- rc = super
235
+ rc = super(bytes, len)
232
236
 
233
237
  # make sure we have a way to deallocate this memory if the object goes
234
238
  # out of scope
@@ -240,7 +244,7 @@ module ZMQ
240
244
  # buffer.
241
245
  #
242
246
  def close
243
- rc = super
247
+ rc = super()
244
248
  remove_finalizer
245
249
  rc
246
250
  end
@@ -268,6 +272,11 @@ module ZMQ
268
272
  end
269
273
  end
270
274
 
275
+ # cache the msg size so we don't have to recalculate it when creating
276
+ # each new instance
277
+ # need to do this again because ivars are not inheritable
278
+ @msg_size = LibZMQ::Msg.size
279
+
271
280
  end # class ManagedMessage
272
281
 
273
282
  end # module ZMQ
@@ -82,7 +82,9 @@ module ZMQ
82
82
  raise ContextError.new 'zmq_socket', 0, ETERM, "Context pointer was null"
83
83
  end
84
84
 
85
- @sockopt_cache = {}
85
+ @more_parts_array = []
86
+ @option_lookup = []
87
+ populate_option_lookup
86
88
 
87
89
  define_finalizer
88
90
  end
@@ -123,17 +125,17 @@ module ZMQ
123
125
  # ZMQ::Util.resultcode_ok?(rc) ? puts("succeeded") : puts("failed")
124
126
  #
125
127
  def setsockopt name, value, length = nil
126
- if long_long_option?(name)
128
+ if 1 == @option_lookup[name]
127
129
  length = 8
128
130
  pointer = LibC.malloc length
129
131
  pointer.write_long_long value
130
132
 
131
- elsif int_option?(name)
133
+ elsif 0 == @option_lookup[name]
132
134
  length = 4
133
135
  pointer = LibC.malloc length
134
136
  pointer.write_int value
135
137
 
136
- elsif string_option?(name)
138
+ elsif 2 == @option_lookup[name]
137
139
  length ||= value.size
138
140
 
139
141
  # note: not checking errno for failed memory allocations :(
@@ -166,10 +168,9 @@ module ZMQ
166
168
  # end
167
169
  #
168
170
  def more_parts?
169
- array = []
170
- rc = getsockopt ZMQ::RCVMORE, array
171
+ rc = getsockopt ZMQ::RCVMORE, @more_parts_array
171
172
 
172
- Util.resultcode_ok?(rc) ? array.at(0) : false
173
+ Util.resultcode_ok?(rc) ? @more_parts_array.at(0) : false
173
174
  end
174
175
 
175
176
  # Binds the socket to an +address+.
@@ -213,20 +214,22 @@ module ZMQ
213
214
  private
214
215
 
215
216
  def __getsockopt__ name, array
216
- value, length = sockopt_buffers name
217
+ # a small optimization so we only have to determine the option
218
+ # type a single time; gives approx 5% speedup to do it this way.
219
+ option_type = @option_lookup[name]
220
+
221
+ value, length = sockopt_buffers option_type
217
222
 
218
223
  rc = LibZMQ.zmq_getsockopt @socket, name, value, length
219
224
 
220
225
  if Util.resultcode_ok?(rc)
221
- result = if int_option?(name)
222
- value.read_int
223
- elsif long_long_option?(name)
226
+ array[0] = if 1 == option_type
224
227
  value.read_long_long
225
- elsif string_option?(name)
228
+ elsif 0 == option_type
229
+ value.read_int
230
+ elsif 2 == option_type
226
231
  value.read_string(length.read_int)
227
232
  end
228
-
229
- array << result
230
233
  end
231
234
 
232
235
  rc
@@ -235,28 +238,28 @@ module ZMQ
235
238
  # Calls to ZMQ.getsockopt require us to pass in some pointers. We can cache and save those buffers
236
239
  # for subsequent calls. This is a big perf win for calling RCVMORE which happens quite often.
237
240
  # Cannot save the buffer for the IDENTITY.
238
- def sockopt_buffers name
239
- if long_long_option?(name)
241
+ def sockopt_buffers option_type
242
+ if 1 == option_type
240
243
  # int64_t or uint64_t
241
- unless @sockopt_cache[:int64]
244
+ unless @longlong_cache
242
245
  length = FFI::MemoryPointer.new :size_t
243
246
  length.write_int 8
244
- @sockopt_cache[:int64] = [FFI::MemoryPointer.new(:int64), length]
247
+ @longlong_cache = [FFI::MemoryPointer.new(:int64), length]
245
248
  end
246
249
 
247
- @sockopt_cache[:int64]
250
+ @longlong_cache
248
251
 
249
- elsif int_option?(name)
252
+ elsif 0 == option_type
250
253
  # int, 0mq assumes int is 4-bytes
251
- unless @sockopt_cache[:int32]
254
+ unless @int_cache
252
255
  length = FFI::MemoryPointer.new :size_t
253
256
  length.write_int 4
254
- @sockopt_cache[:int32] = [FFI::MemoryPointer.new(:int32), length]
257
+ @int_cache = [FFI::MemoryPointer.new(:int32), length]
255
258
  end
256
259
 
257
- @sockopt_cache[:int32]
260
+ @int_cache
258
261
 
259
- elsif string_option?(name)
262
+ elsif 2 == option_type
260
263
  length = FFI::MemoryPointer.new :size_t
261
264
  # could be a string of up to 255 bytes
262
265
  length.write_int 255
@@ -264,50 +267,30 @@ module ZMQ
264
267
 
265
268
  else
266
269
  # uh oh, someone passed in an unknown option; use a slop buffer
267
- unless @sockopt_cache[:unknown]
270
+ unless @int_cache
268
271
  length = FFI::MemoryPointer.new :size_t
269
272
  length.write_int 4
270
- @sockopt_cache[:unknown] = [FFI::MemoryPointer.new(:int32), length]
273
+ @int_cache = [FFI::MemoryPointer.new(:int32), length]
271
274
  end
272
275
 
273
- @sockopt_cache[:unknown]
276
+ @int_cache
274
277
  end
275
278
  end
276
-
277
- def supported_option? name
278
- int_option?(name) || long_long_option?(name) || string_option?(name)
279
- end
280
-
281
- def int_option? name
282
- EVENTS == name ||
283
- LINGER == name ||
284
- RECONNECT_IVL == name ||
285
- FD == name ||
286
- TYPE == name ||
287
- BACKLOG == name
288
- end
289
-
290
- def string_option? name
291
- SUBSCRIBE == name ||
292
- UNSUBSCRIBE == name
293
- end
294
-
295
- def long_long_option? name
296
- RCVMORE == name ||
297
- AFFINITY == name
298
- end
299
-
300
- def unsupported_setsock_option? name
301
- RCVMORE == name
302
- end
303
-
304
- def unsupported_getsock_option? name
305
- UNSUBSCRIBE == name ||
306
- SUBSCRIBE == name
279
+
280
+ def populate_option_lookup
281
+ # integer options
282
+ [EVENTS, LINGER, RECONNECT_IVL, FD, TYPE, BACKLOG].each { |option| @option_lookup[option] = 0 }
283
+
284
+ # long long options
285
+ [RCVMORE, AFFINITY].each { |option| @option_lookup[option] = 1 }
286
+
287
+ # string options
288
+ [SUBSCRIBE, UNSUBSCRIBE].each { |option| @option_lookup[option] = 2 }
307
289
  end
308
290
 
309
291
  def release_cache
310
- @sockopt_cache.clear
292
+ @longlong_cache = nil
293
+ @int_cache = nil
311
294
  end
312
295
  end # module CommonSocketBehavior
313
296
 
@@ -330,11 +313,14 @@ module ZMQ
330
313
 
331
314
 
332
315
  private
333
-
334
- def string_option? name
335
- super ||
336
- IDENTITY == name
316
+
317
+ def populate_option_lookup
318
+ super()
319
+
320
+ # string options
321
+ [IDENTITY].each { |option| @option_lookup[option] = 2 }
337
322
  end
323
+
338
324
  end # module IdentitySupport
339
325
 
340
326
 
@@ -658,23 +644,16 @@ module ZMQ
658
644
  def noblock? flags
659
645
  (NOBLOCK & flags) == NOBLOCK
660
646
  end
647
+
648
+ def populate_option_lookup
649
+ super()
650
+
651
+ # integer options
652
+ [RECONNECT_IVL_MAX].each { |option| @option_lookup[option] = 0 }
661
653
 
662
- def int_option? name
663
- super ||
664
- RECONNECT_IVL_MAX == name
665
- end
666
-
667
- def long_long_option? name
668
- super ||
669
- HWM == name ||
670
- SWAP == name ||
671
- RATE == name ||
672
- RECOVERY_IVL == name ||
673
- RECOVERY_IVL_MSEC == name ||
674
- MCAST_LOOP == name ||
675
- SNDBUF == name ||
676
- RCVBUF == name
677
- end
654
+ # long long options
655
+ [HWM, SWAP, RATE, RECOVERY_IVL, RECOVERY_IVL_MSEC, MCAST_LOOP, SNDBUF, RCVBUF].each { |option| @option_lookup[option] = 1 }
656
+ end
678
657
 
679
658
  # these finalizer-related methods cannot live in the CommonSocketBehavior
680
659
  # module; they *must* be in the class definition directly
@@ -986,7 +965,7 @@ module ZMQ
986
965
  alias :noblock? :dontwait?
987
966
 
988
967
  def int_option? name
989
- super ||
968
+ super(name) ||
990
969
  RECONNECT_IVL_MAX == name ||
991
970
  RCVHWM == name ||
992
971
  SNDHWM == name ||
@@ -995,6 +974,13 @@ module ZMQ
995
974
  SNDBUF == name ||
996
975
  RCVBUF == name
997
976
  end
977
+
978
+ def populate_option_lookup
979
+ super()
980
+
981
+ # integer options
982
+ [RECONNECT_IVL_MAX, RCVHWM, SNDHWM, RATE, RECOVERY_IVL, SNDBUF, RCVBUF].each { |option| @option_lookup[option] = 0 }
983
+ end
998
984
 
999
985
  # these finalizer-related methods cannot live in the CommonSocketBehavior
1000
986
  # module; they *must* be in the class definition directly
@@ -1,3 +1,3 @@
1
1
  module ZMQ
2
- VERSION = "0.9.2"
2
+ VERSION = "0.9.3"
3
3
  end
@@ -366,12 +366,22 @@ module ZMQ
366
366
  array[0].should == value
367
367
  end
368
368
 
369
- it "should default to a value of -1" do
370
- value = -1
371
- array = []
372
- rc = socket.getsockopt(ZMQ::LINGER, array)
373
- rc.should == 0
374
- array[0].should == value
369
+ if ZMQ::SUB == socket_type || ZMQ::XSUB == socket_type
370
+ it "should default to a value of 0" do
371
+ value = 0
372
+ array = []
373
+ rc = socket.getsockopt(ZMQ::LINGER, array)
374
+ rc.should == 0
375
+ array[0].should == value
376
+ end
377
+ else
378
+ it "should default to a value of -1" do
379
+ value = -1
380
+ array = []
381
+ rc = socket.getsockopt(ZMQ::LINGER, array)
382
+ rc.should == 0
383
+ array[0].should == value
384
+ end
375
385
  end
376
386
  end # context using option ZMQ::LINGER
377
387
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ffi-rzmq
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.9.2
5
+ version: 0.9.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Chuck Remes
@@ -10,8 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-11-30 00:00:00 -06:00
14
- default_executable:
13
+ date: 2011-12-20 00:00:00 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: ffi
@@ -21,7 +20,7 @@ dependencies:
21
20
  requirements:
22
21
  - - ">="
23
22
  - !ruby/object:Gem::Version
24
- version: 1.0.9
23
+ version: "0"
25
24
  type: :runtime
26
25
  version_requirements: *id001
27
26
  - !ruby/object:Gem::Dependency
@@ -115,7 +114,6 @@ files:
115
114
  - spec/reqrep_spec.rb
116
115
  - spec/socket_spec.rb
117
116
  - spec/spec_helper.rb
118
- has_rdoc: true
119
117
  homepage: http://github.com/chuckremes/ffi-rzmq
120
118
  licenses: []
121
119
 
@@ -139,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
137
  requirements: []
140
138
 
141
139
  rubyforge_project: ffi-rzmq
142
- rubygems_version: 1.5.1
140
+ rubygems_version: 1.8.9
143
141
  signing_key:
144
142
  specification_version: 3
145
143
  summary: This gem wraps the ZeroMQ (0mq) networking library using Ruby FFI (foreign function interface).