nn-core 0.1.5 → 0.1.6

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,3 +1,16 @@
1
+ 20130220 / 0.1.6
2
+ * Several fixes for tcp string handling have made it to nanomsg trunk,
3
+ so I can now re-enable those specs.
4
+
5
+ * For MRI Ruby, add @blocking=true before all function attachments to instruct
6
+ the FFI gem to release the GIL.
7
+
8
+ * Fixed a nn_recv spec to only read a specific number of bytes from a received
9
+ string. Must note that the library does not null terminate strings on its
10
+ own so we need to be very careful how many bytes are read from received
11
+ strings.
12
+
13
+
1
14
  20130215 / 0.1.5
2
15
  * libnanomsg has removed the nn_init and nn_term functions. Updated
3
16
  specs to remove those features.
@@ -0,0 +1,167 @@
1
+ begin
2
+ require 'nn-core'
3
+ rescue LoadError
4
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
5
+ retry
6
+ end
7
+
8
+
9
+ # Within a single process, we start up two threads. One thread has a REQ (request)
10
+ # socket and the second thread has a REP (reply) socket. We measure the
11
+ # *round-trip* latency between these sockets. Only *one* message is in flight at
12
+ # any given moment.
13
+ #
14
+ # % ruby roundtrip_latency.rb tcp://127.0.0.1:5555 1024 1_000_000
15
+ #
16
+ # % ruby roundtrip_latency.rb inproc://lm_sock 1024 1_000_000
17
+ #
18
+
19
+ if ARGV.length < 3
20
+ puts "usage: ruby roundtrip_latency.rb <connect-to> <message-size> <roundtrip-count>"
21
+ exit
22
+ end
23
+
24
+ link = ARGV[0]
25
+ message_size = ARGV[1].to_i
26
+ roundtrip_count = ARGV[2].to_i
27
+
28
+ def set_signal_handler(receiver, transmitter)
29
+ trap(:INT) do
30
+ puts "got ctrl-c"
31
+ receiver.terminate
32
+ transmitter.terminate
33
+ end
34
+ end
35
+
36
+ class Node
37
+ def initialize(endpoint, size, count)
38
+ @endpoint = endpoint
39
+ @size = size
40
+ @count = count
41
+ @msg = 'a' * @size
42
+
43
+ @rcv_buffer = FFI::MemoryPointer.new(@size)
44
+
45
+ allocate_socket
46
+ setup_socket
47
+ set_endpoint
48
+ end
49
+
50
+ def setup_socket
51
+ option = FFI::MemoryPointer.new(:int32)
52
+
53
+ # LINGER
54
+ option.write_int(100)
55
+ rc = NNCore::LibNanomsg.nn_setsockopt(@socket, NNCore::NN_SOL_SOCKET, NNCore::NN_LINGER, option, 4)
56
+ assert(rc)
57
+
58
+ # SNDBUF
59
+ option.write_int(131072)
60
+ rc = NNCore::LibNanomsg.nn_setsockopt(@socket, NNCore::NN_SOL_SOCKET, NNCore::NN_SNDBUF, option, 4)
61
+ assert(rc)
62
+
63
+ # RCVBUF
64
+ option.write_int(131072)
65
+ rc = NNCore::LibNanomsg.nn_setsockopt(@socket, NNCore::NN_SOL_SOCKET, NNCore::NN_RCVBUF, option, 4)
66
+ assert(rc)
67
+ end
68
+
69
+ def send_msg
70
+ nbytes = NNCore::LibNanomsg.nn_send(@socket, @msg, @size, 0)
71
+ assert(nbytes)
72
+ nbytes
73
+ end
74
+
75
+ def recv_msg
76
+ nbytes = NNCore::LibNanomsg.nn_recv(@socket, @rcv_buffer, @size, 0)
77
+ assert(nbytes)
78
+ nbytes
79
+ end
80
+
81
+ def terminate
82
+ assert(NNCore::LibNanomsg.nn_close(@socket))
83
+ end
84
+
85
+ def assert(rc)
86
+ raise "Last API call failed at #{caller(1)}" unless rc >= 0
87
+ end
88
+ end
89
+
90
+ class Receiver < Node
91
+ def allocate_socket
92
+ @socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_REP)
93
+ assert(@socket)
94
+ end
95
+
96
+ def set_endpoint
97
+ assert(NNCore::LibNanomsg.nn_bind(@socket, @endpoint))
98
+ end
99
+
100
+ def run
101
+ @count.times do
102
+ nbytes = recv_msg
103
+
104
+ raise "Message size doesn't match, expected [#{@size}] but received [#{string.size}]" if @size != nbytes
105
+
106
+ send_msg
107
+ end
108
+
109
+ terminate
110
+ end
111
+ end
112
+
113
+ class Transmitter < Node
114
+ def allocate_socket
115
+ @socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_REQ)
116
+ assert(@socket)
117
+ end
118
+
119
+ def set_endpoint
120
+ assert(NNCore::LibNanomsg.nn_connect(@socket, @endpoint))
121
+ end
122
+
123
+ def run
124
+ elapsed = elapsed_microseconds do
125
+ @count.times do
126
+ send_msg
127
+
128
+ nbytes = recv_msg
129
+
130
+ raise "Message size doesn't match, expected [#{@size}] but received [#{nbytes}]" if @size != nbytes
131
+ end
132
+ end
133
+
134
+ latency = elapsed / @count / 2
135
+
136
+ puts "message size: %i [B]" % @size
137
+ puts "roundtrip count: %i" % @count
138
+ puts "throughput (msgs/s): %i" % (@count / (elapsed / 1_000_000))
139
+ puts "mean latency: %.3f [us]" % latency
140
+ terminate
141
+ end
142
+
143
+ def elapsed_microseconds(&blk)
144
+ start = Time.now
145
+ yield
146
+ value = ((Time.now - start) * 1_000_000)
147
+ end
148
+ end
149
+
150
+ threads = []
151
+ receiver = transmitter = nil
152
+
153
+ threads << Thread.new do
154
+ receiver = Receiver.new(link, message_size, roundtrip_count)
155
+ receiver.run
156
+ end
157
+
158
+ sleep 1
159
+
160
+ threads << Thread.new do
161
+ transmitter = Transmitter.new(link, message_size, roundtrip_count)
162
+ transmitter.run
163
+ end
164
+
165
+ set_signal_handler(receiver, transmitter)
166
+
167
+ threads.each {|t| t.join}
@@ -33,25 +33,41 @@ module NNCore
33
33
  # Size_t not working properly on Windows
34
34
  find_type(:size_t) rescue typedef(:ulong, :size_t)
35
35
 
36
+ @blocking = true
36
37
  attach_function :nn_version, [:pointer, :pointer, :pointer], :int
37
38
 
39
+ @blocking = true
38
40
  attach_function :nn_errno, [], :int
41
+ @blocking = true
39
42
  attach_function :nn_strerror, [:int], :string
43
+ @blocking = true
40
44
  attach_function :nn_socket, [:int, :int], :int
45
+ @blocking = true
41
46
  attach_function :nn_close, [:int], :int
42
47
 
48
+ @blocking = true
43
49
  attach_function :nn_getsockopt, [:int, :int, :int, :pointer, :pointer], :int
50
+ @blocking = true
44
51
  attach_function :nn_setsockopt, [:int, :int, :int, :pointer, :size_t], :int
52
+ @blocking = true
45
53
  attach_function :nn_bind, [:int, :string], :int
54
+ @blocking = true
46
55
  attach_function :nn_connect, [:int, :string], :int
56
+ @blocking = true
47
57
  attach_function :nn_shutdown, [:int, :int], :int
58
+ @blocking = true
48
59
  attach_function :nn_send, [:int, :pointer, :size_t, :int], :int
60
+ @blocking = true
49
61
  attach_function :nn_recv, [:int, :pointer, :size_t, :int], :int
50
62
 
51
63
  # functions for working with raw buffers
64
+ @blocking = true
52
65
  attach_function :nn_sendmsg, [:int, :pointer, :int], :int
66
+ @blocking = true
53
67
  attach_function :nn_recvmsg, [:int, :pointer, :int], :int
68
+ @blocking = true
54
69
  attach_function :nn_allocmsg, [:size_t, :int], :pointer
70
+ @blocking = true
55
71
  attach_function :nn_freemsg, [:pointer], :int
56
72
  end
57
73
  end
@@ -1,3 +1,3 @@
1
1
  module NNCore
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -53,35 +53,28 @@ module NNCore
53
53
  LibNanomsg.nn_errno.should == EINVAL
54
54
  end
55
55
 
56
- # it "returns -1 for an invalid TCP address (missing port)" do
57
- # rc = LibNanomsg.nn_connect(@socket, "tcp://*:")
58
- # rc.should == -1
59
- # LibNanomsg.nn_errno.should == EINVAL
60
- # end
61
- #
62
- # it "returns -1 for an invalid TCP address (non-numeric port)" do
63
- # rc = LibNanomsg.nn_connect(@socket, "tcp://192.168.0.1:port")
64
- # rc.should == -1
65
- # LibNanomsg.nn_errno.should == EINVAL
66
- # end
67
- #
68
- # it "returns -1 for an invalid TCP address (port number is out of range)" do
69
- # rc = LibNanomsg.nn_connect(@socket, "tcp://192.168.0.1:65536")
70
- # rc.should == -1
71
- # LibNanomsg.nn_errno.should == EINVAL
72
- # end
56
+ it "returns -1 for an invalid TCP address (missing port)" do
57
+ rc = LibNanomsg.nn_connect(@socket, "tcp://*:")
58
+ rc.should == -1
59
+ LibNanomsg.nn_errno.should == EINVAL
60
+ end
73
61
 
74
- it "returns -1 for an unsupported transport protocol" do
75
- rc = LibNanomsg.nn_connect(@socket, "zmq://192.168.0.1:65536")
62
+ it "returns -1 for an invalid TCP address (non-numeric port)" do
63
+ rc = LibNanomsg.nn_connect(@socket, "tcp://192.168.0.1:port")
76
64
  rc.should == -1
77
- LibNanomsg.nn_errno.should == EPROTONOSUPPORT
65
+ LibNanomsg.nn_errno.should == EINVAL
66
+ end
67
+
68
+ it "returns -1 for an invalid TCP address (port number is out of range)" do
69
+ rc = LibNanomsg.nn_connect(@socket, "tcp://192.168.0.1:65536")
70
+ rc.should == -1
71
+ LibNanomsg.nn_errno.should == EINVAL
78
72
  end
79
73
 
80
- it "returns -1 for specifying a non-existent device using TCP transport" do
81
- pending # currently fails
82
- rc = LibNanomsg.nn_connect(@socket, "tcp://doesntexist:5555")
74
+ it "returns -1 for an unsupported transport protocol" do
75
+ rc = LibNanomsg.nn_connect(@socket, "zmq://192.168.0.1:65536")
83
76
  rc.should == -1
84
- LibNanomsg.nn_errno.should == ENODEV
77
+ LibNanomsg.nn_errno.should == EPROTONOSUPPORT
85
78
  end
86
79
 
87
80
  it "returns 2 when connecting twice to an existing endpoint" do
@@ -40,7 +40,10 @@ module NNCore
40
40
  buffer = FFI::MemoryPointer.new(:pointer)
41
41
  nbytes = LibNanomsg.nn_recv(@socket, buffer, NN_MSG, 0)
42
42
  nbytes.should == 3
43
- buffer.get_pointer(0).read_string.should == string
43
+
44
+ # important to pass +nbytes+ to #read_string since the sent string
45
+ # is not null-terminated
46
+ buffer.get_pointer(0).read_string(nbytes).should == string
44
47
  end
45
48
  end
46
49
  end
@@ -33,11 +33,10 @@ module NNCore
33
33
  end
34
34
 
35
35
  context "given an unsupported address family" do
36
-
37
- # it "nn_socket returns -1 and sets nn_errno to EAFNOSUPPORT" do
38
- # LibNanomsg.nn_socket(0, NN_PUB).should == -1
39
- # LibNanomsg.nn_errno.should == EAFNOSUPPORT
40
- # end
36
+ it "nn_socket returns -1 and sets nn_errno to EAFNOSUPPORT" do
37
+ LibNanomsg.nn_socket(0, NN_PUB).should == -1
38
+ LibNanomsg.nn_errno.should == EAFNOSUPPORT
39
+ end
41
40
  end
42
41
 
43
42
  context "given an unsupported protocol and a supported address family" do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module NNCore
4
- describe "nn_bind" do
4
+ describe "nn_version" do
5
5
 
6
6
  context "given an initialized library" do
7
7
 
@@ -6,7 +6,7 @@ module NNCore
6
6
  :NN_LINGER => NN_LINGER,
7
7
  :NN_SNDBUF => NN_SNDBUF,
8
8
  :NN_RCVBUF => NN_RCVBUF,
9
- :NN_SENDTIMEO => NN_SNDTIMEO,
9
+ :NN_SNDTIMEO => NN_SNDTIMEO,
10
10
  :NN_RCVTIMEO => NN_RCVTIMEO,
11
11
  :NN_RECONNECT_IVL => NN_RECONNECT_IVL,
12
12
  :NN_RECONNECT_IVL_MAX => NN_RECONNECT_IVL_MAX,
metadata CHANGED
@@ -1,64 +1,64 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nn-core
3
3
  version: !ruby/object:Gem::Version
4
+ version: 0.1.6
4
5
  prerelease:
5
- version: 0.1.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Chuck Remes
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-15 00:00:00.000000000 Z
12
+ date: 2013-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- prerelease: false
16
- requirement: !ruby/object:Gem::Requirement
15
+ version_requirements: !ruby/object:Gem::Requirement
17
16
  requirements:
18
17
  - - ! '>='
19
18
  - !ruby/object:Gem::Version
20
19
  version: '0'
21
20
  none: false
22
21
  type: :runtime
23
- version_requirements: !ruby/object:Gem::Requirement
22
+ name: ffi
23
+ prerelease: false
24
+ requirement: !ruby/object:Gem::Requirement
24
25
  requirements:
25
26
  - - ! '>='
26
27
  - !ruby/object:Gem::Version
27
28
  version: '0'
28
29
  none: false
29
- name: ffi
30
30
  - !ruby/object:Gem::Dependency
31
- prerelease: false
32
- requirement: !ruby/object:Gem::Requirement
31
+ version_requirements: !ruby/object:Gem::Requirement
33
32
  requirements:
34
33
  - - ~>
35
34
  - !ruby/object:Gem::Version
36
35
  version: '2.6'
37
36
  none: false
38
37
  type: :development
39
- version_requirements: !ruby/object:Gem::Requirement
38
+ name: rspec
39
+ prerelease: false
40
+ requirement: !ruby/object:Gem::Requirement
40
41
  requirements:
41
42
  - - ~>
42
43
  - !ruby/object:Gem::Version
43
44
  version: '2.6'
44
45
  none: false
45
- name: rspec
46
46
  - !ruby/object:Gem::Dependency
47
- prerelease: false
48
- requirement: !ruby/object:Gem::Requirement
47
+ version_requirements: !ruby/object:Gem::Requirement
49
48
  requirements:
50
49
  - - ! '>='
51
50
  - !ruby/object:Gem::Version
52
51
  version: '0'
53
52
  none: false
54
53
  type: :development
55
- version_requirements: !ruby/object:Gem::Requirement
54
+ name: rake
55
+ prerelease: false
56
+ requirement: !ruby/object:Gem::Requirement
56
57
  requirements:
57
58
  - - ! '>='
58
59
  - !ruby/object:Gem::Version
59
60
  version: '0'
60
61
  none: false
61
- name: rake
62
62
  description: ! 'Wraps the nanomsg networking library using the ruby FFI (foreign
63
63
 
64
64
  function interface). It only exposes the native C API to Ruby. Other gems should
@@ -85,6 +85,8 @@ files:
85
85
  UkVBRE1FLm1k
86
86
  - !binary |-
87
87
  UmFrZWZpbGU=
88
+ - !binary |-
89
+ ZXhhbXBsZXMvcm91bmR0cmlwX2xhdGVuY3kucmI=
88
90
  - !binary |-
89
91
  bGliL25uLWNvcmUucmI=
90
92
  - !binary |-