uringmachine 0.29.2 → 0.31.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6151ac8411facd0ef37fa66a7cae623d2137f335bbe1e178529cb0a76c9f56c3
4
- data.tar.gz: 5918fde9ea4ba936760a3d402207bd6fd5806337b005cd3633ab1cf0f8584ed0
3
+ metadata.gz: 9c6af55ee77291dcf17471dde7dd9d68b731fd9a8dea4d1dccdcc09b325b9163
4
+ data.tar.gz: 516624d1a86287bbd0978d5aaf0cca540063ca7f6aa4cf2bab8cb9f23214d32d
5
5
  SHA512:
6
- metadata.gz: 0d77a7f37251930db32ec8023b1cb60e5595348544b279b175d39a528dbe782a703c75f6ebde5b2dd84379ec12ae83decf47f11f0b692e4975a36f146b4bc975
7
- data.tar.gz: 190d3d88d32f91241c3c9ed3fc674d5318fcf630e64d5d5fdecdc7a86b6e62f03786190a021f4828e6a40022ccbf301a3cffdf0311ff35bc747889d9f00fbb9b
6
+ metadata.gz: e9d845525499342080228b44afb5cabb84af6bb0cb14081cc5e4e2eb627ab638312c0df818f5d109ab99d6e34a299bb21da23711f131f4a9641d688cee5cf35e
7
+ data.tar.gz: d67d15b398bac118b85219be3669a1479eba68e5d93ceb2e3f598238ae2fbefd7cf83dcffa132fe12ed0b0385d675c15e7f89a05150290da6fbc4d8bc40a1431
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # 0.31.0 2026-03-31
2
+
3
+ - Rework `Stream` into `Connection` class:
4
+ - Rename modes, improve SSL detection
5
+ - Rename and enhance different read methods
6
+ - Add `#write` method
7
+ - Add `#resp_write` method
8
+
9
+ # 0.30.0 2026-03-23
10
+
11
+ - Add `Stream#each`
12
+ - Add `UM#splice`, `UM#tee`, `UM#fsync`
13
+ - Add `UM#tcp_listen`, `UM#tcp_connect`
14
+
1
15
  # 0.29.2 2026-03-15
2
16
 
3
17
  - Add `Stream#consumed`, `Stream#pending`
@@ -24,7 +38,7 @@
24
38
 
25
39
  # 0.28.2 2026-02-20
26
40
 
27
- - Fix `Stream#get_string`
41
+ - Fix `Stream#read`
28
42
 
29
43
  # 0.28.1 2026-02-20
30
44
 
@@ -163,9 +177,9 @@
163
177
 
164
178
  # 2025-06-03 Version 0.12
165
179
 
166
- - Add buffer, maxlen params to `Stream#get_line`
167
- - Add buffer param to `Stream#get_string`
168
- - Remove `Stream#resp_get_line`, `Stream#resp_get_string` methods
180
+ - Add buffer, maxlen params to `Stream#read_line`
181
+ - Add buffer param to `Stream#read`
182
+ - Remove `Stream#resp_read_line`, `Stream#resp_read` methods
169
183
 
170
184
  # 2025-06-02 Version 0.11.1
171
185
 
data/README.md CHANGED
@@ -37,7 +37,7 @@ implementation that allows integration with the entire Ruby ecosystem.
37
37
  - Excellent performance characteristics for concurrent I/O-bound applications.
38
38
  - `Fiber::Scheduler` implementation to automatically integrate with the Ruby
39
39
  ecosystem in a transparent fashion.
40
- - Read streams with automatic buffer management.
40
+ - [Connection](#connections) class with automatic buffer management for reading.
41
41
  - Optimized I/O for encrypted SSL connections.
42
42
 
43
43
  ## Design
@@ -286,64 +286,70 @@ fiber = Fiber.schedule do
286
286
  end
287
287
  ```
288
288
 
289
- ## Read Streams
289
+ ## Connections
290
290
 
291
- A UringMachine stream is used to efficiently read from a socket or other file
292
- descriptor. Streams are ideal for implementing the read side of protocols, and
293
- provide an API that is useful for both line-based protocols and binary
294
- (frame-based) protocols.
291
+ `UringMachine::Connection` is a class designed for efficiently read from and
292
+ write to a socket or other file descriptor. Connections are ideal for
293
+ implementing the read side of protocols, and provide an API that is useful for
294
+ both line-based protocols and binary (frame-based) protocols.
295
295
 
296
- A stream is associated with a UringMachine instance and a target file descriptor
297
- (see also [stream modes](#stream-modes) below). Behind the scenes, streams take
298
- advantage of io_uring's registered buffers feature, and more recently, the
299
- introduction of [incremental buffer
296
+ A connection is associated with a UringMachine instance and a target file
297
+ descriptor (or SSL socket, see also [connection modes](#connection-modes)
298
+ below). Behind the scenes, connections take advantage of io_uring's registered
299
+ buffers feature, and more recently, the introduction of [incremental buffer
300
300
  consumption](https://github.com/axboe/liburing/wiki/What's-new-with-io_uring-in-6.11-and-6.12#incremental-provided-buffer-consumption).
301
301
 
302
- When streams are used, UringMachine automatically manages the buffers it
302
+ When connections are used, UringMachine automatically manages the buffers it
303
303
  provides to the kernel, maximizing buffer reuse and minimizing allocations.
304
304
  UringMachine also responds to stress conditions (increased incoming traffic) by
305
305
  automatically provisioning additional buffers.
306
306
 
307
- To create a stream for a given fd, use `UM#stream`:
307
+ To create a connection for a given fd, use `UM#connection`:
308
308
 
309
309
  ```ruby
310
- stream = machine.stream(fd)
310
+ conn = machine.connection(fd)
311
311
 
312
- # you can also provide a block that will be passed the stream instance:
313
- machine.stream(fd) { |s| do_something_with(s) }
312
+ # you can also provide a block that will be passed the connection instance:
313
+ machine.connection(fd) { |c| do_something_with(c) }
314
314
 
315
- # you can also instantiate a stream directly:
316
- stream = UM::Stream.new(machine, fd)
315
+ # you can also instantiate a connection directly:
316
+ conn = UM::Connection.new(machine, fd)
317
317
  ```
318
318
 
319
- The following API is used to interact with the stream:
319
+ The following API is used to interact with the connection:
320
320
 
321
321
  ```ruby
322
322
  # Read until a newline character is encountered:
323
- line = stream.get_line(0)
323
+ line = conn.read_line(0)
324
324
 
325
325
  # Read line with a maximum length of 13 bytes:
326
- line = stream.get_line(13)
326
+ line = conn.read_line(13)
327
327
 
328
328
  # Read all data:
329
- buf = stream.get_string(0)
329
+ buf = conn.read(0)
330
330
 
331
331
  # Read exactly 13 bytes:
332
- buf = stream.get_string(13)
332
+ buf = conn.read(13)
333
333
 
334
334
  # Read up to 13 bytes:
335
- buf = stream.get_string(-13)
335
+ buf = conn.read(-13)
336
+
337
+ # Read continuously until EOF
338
+ conn.read_each { |data| ... }
336
339
 
337
340
  # Skip 3 bytes:
338
- stream.skip(3)
341
+ conn.skip(3)
342
+
343
+ # Write
344
+ conn.write('foo', 'bar', 'baz')
339
345
  ```
340
346
 
341
347
  Here's an example of a how a basic HTTP request parser might be implemented
342
- using a stream:
348
+ using a connection:
343
349
 
344
350
  ```ruby
345
- def parse_http_request_headers(stream)
346
- request_line = stream.get_line(0)
351
+ def parse_http_request_headers(conn)
352
+ request_line = conn.read_line(0)
347
353
  m = request_line.match(REQUEST_LINE_RE)
348
354
  return nil if !m
349
355
 
@@ -354,7 +360,7 @@ def parse_http_request_headers(stream)
354
360
  }
355
361
 
356
362
  while true
357
- line = stream.get_line(0)
363
+ line = conn.read_line(0)
358
364
  break if !line || line.empty?
359
365
 
360
366
  m = line.match(HEADER_RE)
@@ -364,24 +370,26 @@ def parse_http_request_headers(stream)
364
370
  end
365
371
  ```
366
372
 
367
- ### Stream modes
373
+ ### Connection modes
368
374
 
369
- Stream modes allow streams to be transport agnostic. Currently streams support
370
- three modes:
375
+ Connection modes allow connections to be transport agnostic. Currently
376
+ connections support three modes:
371
377
 
372
- - `:bp_read` - use the buffer pool, read data using multishot read
378
+ - `:fd` - use the buffer pool, read data using multishot read
373
379
  (this is the default mode).
374
- - `:bp_recv` - use the buffer pool, read data using multishot recv.
380
+ - `:socket` - use the buffer pool, read data using multishot recv.
375
381
  - `:ssl` - read from an `SSLSocket` object.
376
382
 
377
- The mode is specified as an additional argument to `Stream.new`:
383
+ The mode is specified as an additional argument to `Connection.new`:
378
384
 
379
385
  ```ruby
380
- # stream using recv:
381
- stream = machine.stream(fd, :bp_recv)
386
+ # using recv/send:
387
+ conn = machine.connection(fd, :socket)
382
388
 
383
- # stream on an SSL socket:
384
- stream = machine.stream(ssl, :ssl)
389
+ # SSL I/O:
390
+ conn = machine.connection(ssl, :ssl)
391
+ # or simply:
392
+ conn = machine.connection(ssl)
385
393
  ```
386
394
 
387
395
  ## Performance
data/TODO.md CHANGED
@@ -1,67 +1,64 @@
1
1
  ## immediate
2
2
 
3
- - Add support for returning a value on timeout
4
-
5
- Since to do this safely we need to actually raise an exception that wraps the
6
- value, rescue it and return the value, we might want a separate method that
7
- wraps `#timeout`:
8
-
9
- ```ruby
10
- TimeoutValueError < StandardError
11
-
12
- def timeout_with_value(interval, value, &block)
13
- timeout_error = TimeoutValueError
14
- timeout(interval, timeout_error, &block)
15
- rescue TimeoutValueError => e
16
- raise if e != timeout_error
17
-
18
- value
19
- end
20
- ```
21
-
22
3
  - Add tests for support for Set in `machine#await`
23
4
  - Add tests for support for Set, Array in `machine#join`
24
- - Add `#read_file` for reading entire file
25
- - Add `#write_file` for writing entire file
5
+ - Add `UM#read_file` for reading entire file
6
+ - Add `UM#write_file` for writing entire file
7
+ - Rename stream methods: `:fd`, `:socket`, `:ssl`
26
8
 
27
- - (?) Fix all futex value (Queue, Mutex) to be properly aligned
9
+ ## Improving streams
28
10
 
29
- <<<<<<< HEAD
30
- =======
31
- ## Buffer rings - automatic management
11
+ One wart of the stream API is that it's only for reading, so if we want to
12
+ implement a protocol where we read and write to a target fd, we also need to
13
+ keep the fd around or call `stream.target` every time we want to write to it,
14
+ *and* we don't have a transport-agnostic write op.
32
15
 
33
- - Take the buffer_pool branch, rewrite it
34
- - Allow multiple stream modes:
35
- - :buffer_pool - uses buffer rings
36
- - :ssl - read from an SSL connection (`SSLSocket`)
37
- - :io - read from an `IO`
38
-
39
- The API will look something like:
16
+ What if instead of `Stream` we had something called `Link`, which serves for
17
+ both reading and writing:
40
18
 
41
19
  ```ruby
42
- # The mode is selected automatically according to the given target
43
-
44
- stream = UM::Stream.new(machine, fd) # buffer_pool mode (read)
45
- stream = UM::Stream.new(machine, fd, :recv) # buffer_pool mode (recv)
46
- stream = UM::Stream.new(machine, ssl_sock) # SSLSocket mode
47
- stream = UM::Stream.new(machine, conn) # IO mode
48
- stream = UM::Stream.new(machine, str) # string mode
49
- stream = UM::Stream.new(machine, io_buf) # IO:Buffer mode
20
+ conn = machine.connection(fd)
21
+ while l = conn.read_line
22
+ conn.write(l, '\n')
23
+ end
24
+ # or:
25
+ buf = conn.read(42)
50
26
  ```
51
27
 
52
- This can be very useful in testing of stuff such as protocol implementations:
28
+ RESP:
53
29
 
54
30
  ```ruby
55
- stream = UM::Stream.new(machine, "GET /foo HTTP/1.1\r\nHost: bar.com\r\n")
31
+ conn.resp_write(['foo', 'bar'])
32
+ reply = conn.resp_read
56
33
  ```
57
34
 
58
- So basically the stream is tied to a machine, and that means it can only be used
59
- on the thread with which the machine is associated. It is not thread-safe. (This
60
- is incidentally true also for most of the UringMachine instance methods!)
35
+ HTTP:
36
+
37
+ ```ruby
38
+ r = conn.http_read_request
39
+ conn.http_write_response({ ':status' => 200 }, 'foo')
61
40
 
62
- Continued discussion in docs/design/buffer_pool.md
41
+ # or:
42
+ conn.http_write_request({ ':method' => 'GET', ':path' => '/foo' }, nil)
43
+ ```
44
+
45
+ Plan of action:
46
+
47
+ - Rename methods:
48
+ - [v] rename `#read_line` to `#read_line`
49
+ - [v] rename `#read` to `#read`
50
+ - [v] rename `#read_to_delim` to `#read_to_delim`
51
+ - [v] rename `#each` to `#read_each`
52
+ - [v] rename `#resp_decode` to `#resp_read`
53
+ - Rename modes:
54
+ - [v] :fd to :fd
55
+ - [v] :socket to :socket
56
+ - [v] auto detect SSL
57
+ - Rename `Stream` to `Connection`
58
+ - Add methods:
59
+ - `#write(*bufs)`
60
+ - `#resp_write(obj)`
63
61
 
64
- >>>>>>> 04d9eb7 (Docs)
65
62
  ## Balancing I/O with the runqueue
66
63
 
67
64
  - in some cases where there are many entries in the runqueue, this can
@@ -89,6 +86,8 @@ Continued discussion in docs/design/buffer_pool.md
89
86
  debouncer = machine.debounce { }
90
87
  ```
91
88
 
89
+ - happy eyeballs algo for TCP connect
90
+
92
91
  - read multiple files
93
92
 
94
93
  ```ruby
@@ -99,12 +98,31 @@ Continued discussion in docs/design/buffer_pool.md
99
98
  machine.read_files(*fns) #=> { fn1:, fn2:, fn3:, ...}
100
99
  ```
101
100
 
101
+ - more generally, a DSL for expressing batch operations:
102
+
103
+ ```ruby
104
+ result = machine.batch do |b|
105
+ fns.each { b[it] = read_file(b, it) }
106
+ end
107
+ #=> { fn1 => data1, fn2 => data2, ... }
108
+
109
+ # we can also imagine performing operations in sequence using linking:
110
+ result = machine.batch {
111
+ m.
112
+ }
113
+
114
+ end
115
+ ```
116
+
102
117
  ## polyvalent select
103
118
 
104
119
  - select on multiple queues (ala Go)
105
120
  - select on mixture of queues and fds
121
+ - select on fibers:
122
+ - select fibers that are done
123
+ - select first done fiber
106
124
 
107
- ## ops
125
+ ## ops still not implemented
108
126
 
109
127
  - splice / - tee
110
128
  - sendto
@@ -123,31 +141,7 @@ Continued discussion in docs/design/buffer_pool.md
123
141
  When doing a `call`, we need to provide a mailbox for the response. can this be
124
142
  automatic?
125
143
 
126
- ## streams
127
-
128
- We're still missing:
129
-
130
- - limit on line length in `get_line`
131
- - ability to supply buffer to `get_line` and `get_string`
132
- - allow read to eof, maybe with `read_to_eof`
133
-
134
- For the sake of performance, simplicity and explicitness, we change the API as
135
- follows:
136
-
137
- ```ruby
138
- stream.get_line(buf, limit)
139
- # the defaults:
140
- stream.get_line(nil, -1)
141
-
142
- stream.get_string(len, buf)
143
- # defaults:
144
- stream.get_string(len, nil)
145
-
146
- # and
147
- stream.read_to_eof(buf)
148
- # defaults:
149
- stream.read_to_eof(nil)
150
- ```
144
+ ##
151
145
 
152
146
  ## Syntax / pattern for launching/supervising multiple operations
153
147
 
@@ -166,6 +160,5 @@ machine.shift_select(*queues) #=> [result, queue]
166
160
  ```ruby
167
161
  # addrs: [['1.1.1.1', 80], ['2.2.2.2', 80]]
168
162
  # ['1.1.1.1:80', '2.2.2.2:80']
169
- tcp_connect_happy_eyeballs(*addrs)
163
+ tcp_connect_he(*addrs)
170
164
  ```
171
-
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './common'
4
+ require 'socket'
5
+ require 'openssl'
6
+ require 'localhost/authority'
7
+
8
+ GROUPS = 48
9
+ ITERATIONS = 5000
10
+
11
+ SIZE = 1 << 14
12
+ DATA = '*' * SIZE
13
+
14
+ class UMBenchmark
15
+ def server_ctx
16
+ @server_ctx ||= Localhost::Authority.fetch.server_context
17
+ end
18
+
19
+ def ssl_wrap(sock, ctx)
20
+ OpenSSL::SSL::SSLSocket.new(sock, ctx).tap { it.sync_close = true }
21
+ end
22
+
23
+ def ssl_socketpair(machine)
24
+ sock1, sock2 = Socket.socketpair(:AF_UNIX, :SOCK_STREAM, 0)
25
+ ssl1 = ssl_wrap(sock1, server_ctx)
26
+ ssl2 = ssl_wrap(sock2, OpenSSL::SSL::SSLContext.new)
27
+
28
+ if !machine
29
+ t = Thread.new { ssl1.accept rescue nil }
30
+ ssl2.connect
31
+ t.join
32
+ else
33
+ machine.ssl_set_bio(ssl1)
34
+ machine.ssl_set_bio(ssl2)
35
+ f = machine.spin { ssl1.accept rescue nil }
36
+ ssl2.connect
37
+ machine.join(f)
38
+ end
39
+ [ssl1, ssl2]
40
+ end
41
+
42
+ def do_threads(threads, ios)
43
+ GROUPS.times do
44
+ r, w = ssl_socketpair(nil)
45
+ threads << Thread.new do
46
+ ITERATIONS.times { w.write(DATA) }
47
+ w.close
48
+ end
49
+ threads << Thread.new do
50
+ ITERATIONS.times { r.readpartial(SIZE) }
51
+ r.close
52
+ end
53
+ end
54
+ end
55
+
56
+ def do_thread_pool(thread_pool, ios)
57
+ GROUPS.times do
58
+ r, w = ssl_socketpair(nil)
59
+ r.sync = true
60
+ w.sync = true
61
+ ios << r << w
62
+ ITERATIONS.times {
63
+ thread_pool.queue { w.write(DATA) }
64
+ thread_pool.queue { r.readpartial(SIZE) }
65
+ }
66
+ end
67
+ end
68
+
69
+ def do_scheduler(scheduler, ios)
70
+ GROUPS.times do
71
+ r, w = ssl_socketpair(nil)
72
+ r.sync = true
73
+ w.sync = true
74
+ Fiber.schedule do
75
+ ITERATIONS.times { w.write(DATA) }
76
+ w.close
77
+ end
78
+ Fiber.schedule do
79
+ ITERATIONS.times { r.readpartial(SIZE) }
80
+ r.close
81
+ end
82
+ end
83
+ end
84
+
85
+ def do_scheduler_x(div, scheduler, ios)
86
+ (GROUPS/div).times do
87
+ r, w = ssl_socketpair(nil)
88
+ r.sync = true
89
+ w.sync = true
90
+ Fiber.schedule do
91
+ ITERATIONS.times { w.write(DATA) }
92
+ w.close
93
+ end
94
+ Fiber.schedule do
95
+ ITERATIONS.times { r.readpartial(SIZE) }
96
+ r.close
97
+ end
98
+ end
99
+ end
100
+
101
+ def do_um(machine, fibers, fds)
102
+ GROUPS.times do
103
+ r, w = ssl_socketpair(machine)
104
+ fibers << machine.spin do
105
+ ITERATIONS.times { machine.ssl_write(w, DATA, SIZE) }
106
+ machine.close_async(w)
107
+ end
108
+ fibers << machine.spin do
109
+ ITERATIONS.times { machine.ssl_read(r, +'', SIZE) }
110
+ machine.close_async(r)
111
+ end
112
+ end
113
+ end
114
+
115
+ def do_um_x(div, machine, fibers, fds)
116
+ (GROUPS/div).times do
117
+ r, w = ssl_socketpair(machine)
118
+ fibers << machine.spin do
119
+ ITERATIONS.times { machine.ssl_write(w, DATA, SIZE) }
120
+ machine.close_async(w)
121
+ end
122
+ fibers << machine.spin do
123
+ ITERATIONS.times { machine.ssl_read(r, +'', SIZE) }
124
+ machine.close_async(r)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './common'
4
+ require 'securerandom'
5
+
6
+ C = ENV['C']&.to_i || 50
7
+ I = 10
8
+ puts "C=#{C}"
9
+
10
+ class UMBenchmark
11
+ CONTAINER_NAME = "redis-#{SecureRandom.hex}"
12
+
13
+ def start_redis_server
14
+ `docker run --name #{CONTAINER_NAME} -d -p 6379:6379 redis:latest`
15
+ end
16
+
17
+ def stop_redis_server
18
+ `docker stop #{CONTAINER_NAME}`
19
+ end
20
+
21
+ def create_redis_conn(retries = 0)
22
+ Redis.new
23
+ rescue
24
+ if retries < 3
25
+ sleep 0.5
26
+ create_redis_conn(retries + 1)
27
+ else
28
+ raise
29
+ end
30
+ end
31
+
32
+ def query_redis(conn)
33
+ conn.set('abc', 'def')
34
+ p conn.get('abc')
35
+ end
36
+
37
+ def with_container
38
+ start_redis_server
39
+ sleep 0.5
40
+ yield
41
+ rescue Exception => e
42
+ p e
43
+ p e.backtrace
44
+ ensure
45
+ stop_redis_server
46
+ end
47
+
48
+ def benchmark
49
+ with_container {
50
+ Benchmark.bm { run_benchmarks(it) }
51
+ }
52
+ end
53
+
54
+ # def do_threads(threads, ios)
55
+ # C.times.map do
56
+ # threads << Thread.new do
57
+ # conn = create_redis_conn
58
+ # I.times { query_redis(conn) }
59
+ # ensure
60
+ # conn.close
61
+ # end
62
+ # end
63
+ # end
64
+
65
+ def do_scheduler(scheduler, ios)
66
+ return if !scheduler.is_a?(UM::FiberScheduler)
67
+ C.times do
68
+ Fiber.schedule do
69
+ conn = create_redis_conn
70
+ I.times { query_redis(conn) }
71
+ ensure
72
+ conn.close
73
+ end
74
+ end
75
+ end
76
+ end
data/benchmark/common.rb CHANGED
@@ -9,6 +9,7 @@ gemfile do
9
9
  gem 'io-event'
10
10
  gem 'async'
11
11
  gem 'pg'
12
+ gem 'redis'
12
13
  gem 'gvltools'
13
14
  gem 'openssl'
14
15
  gem 'localhost'
data/benchmark/gets.rb CHANGED
@@ -34,16 +34,16 @@ def um_read
34
34
  end
35
35
  end
36
36
 
37
- @fd_stream = @machine.open('/dev/random', UM::O_RDONLY)
38
- @stream = UM::Stream.new(@machine, @fd_stream)
39
- def um_stream_get_line
40
- @stream.get_line(0)
37
+ @fd_connection = @machine.open('/dev/random', UM::O_RDONLY)
38
+ @conn = UM::Connection.new(@machine, @fd_connection)
39
+ def um_connection_read_line
40
+ @conn.read_line(0)
41
41
  end
42
42
 
43
43
  Benchmark.ips do |x|
44
- x.report('IO#gets') { io_gets }
45
- x.report('UM#read+buf') { um_read }
46
- x.report('UM::Stream') { um_stream_get_line }
44
+ x.report('IO#gets') { io_gets }
45
+ x.report('UM#read+buf') { um_read }
46
+ x.report('UM::Connection') { um_connection_read_line }
47
47
 
48
48
  x.compare!(order: :baseline)
49
49
  end
@@ -83,40 +83,40 @@ ensure
83
83
  stop_server
84
84
  end
85
85
 
86
- @total_stream = 0
87
- def um_stream_do
86
+ @total_connection = 0
87
+ def um_connection_do
88
88
  # fd = @machine.open('/dev/random', UM::O_RDONLY)
89
89
  fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
90
90
  @machine.connect(fd, '127.0.0.1', 1234)
91
- stream = UM::Stream.new(@machine, fd)
92
- N.times { @total_stream += stream.get_line(0)&.bytesize || 0 }
91
+ conn = UM::Connection.new(@machine, fd)
92
+ N.times { @total_connection += conn.read_line(0)&.bytesize || 0 }
93
93
  rescue => e
94
94
  p e
95
95
  p e.backtrace
96
96
  ensure
97
- stream.clear
97
+ conn.clear
98
98
  @machine.close(fd)
99
99
  end
100
100
 
101
- def um_stream
101
+ def um_connection
102
102
  start_server
103
103
  ff = C.times.map {
104
104
  @machine.snooze
105
- @machine.spin { um_stream_do }
105
+ @machine.spin { um_connection_do }
106
106
  }
107
107
  @machine.await(ff)
108
- pp total: @total_stream
108
+ pp total: @total_connection
109
109
  ensure
110
110
  stop_server
111
111
  end
112
112
 
113
113
  p(C:, N:)
114
- um_stream
114
+ um_connection
115
115
  pp @machine.metrics
116
116
  exit
117
117
 
118
118
  Benchmark.bm do
119
119
  it.report('Thread/IO#gets') { io_gets }
120
120
  it.report('Fiber/UM#read+buf') { um_read }
121
- it.report('Fiber/UM::Stream') { um_stream }
121
+ it.report('Fiber/UM::Stream') { um_connection }
122
122
  end