[ruby-core:104582] [Ruby master Bug#17664] Behavior of sockets changed in Ruby 3.0 to non-blocking
From:
samuel@...
Date:
2021-07-12 00:54:19 UTC
List:
ruby-core #104582
Issue #17664 has been updated by ioquatix (Samuel Williams).
I rewrote the `uring` implementation to track the number of pending operations. I'm kind of surprised that the SQ doesn't do this.
```
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ------------------
26.59 0.049621 4 10575 close
24.85 0.046369 4 10335 write
17.34 0.032363 3 10338 3 accept4
13.77 0.025693 2 10727 79 read
11.82 0.022051 2 10727 9 newfstatat
5.31 0.009911 4 2079 mprotect
0.11 0.000207 1 192 mmap
0.09 0.000165 1 87 munmap
0.05 0.000087 1 48 brk
0.04 0.000083 1 83 1 io_uring_enter
```
Now for non-blocking sockets, we only see `io_uring_enter` count proportional to the number of `read` and `write` errors which makes more sense to me.
```
Running 30s test @ http://localhost:9090
4 threads and 128 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.87ms 1.36ms 90.28ms 98.60%
Req/Sec 11.16k 1.40k 26.84k 70.73%
1332172 requests in 30.04s, 58.44MB read
Requests/sec: 44341.92
Transfer/sec: 1.95MB
```
As you can imagine, with only 89 calls to `io_uring_enter`, whether or not it's done early or later has little impact on overall performance.
----------------------------------------
Bug #17664: Behavior of sockets changed in Ruby 3.0 to non-blocking
https://bugs.ruby-lang.org/issues/17664#change-92865
* Author: ciconia (Sharon Rosner)
* Status: Assigned
* Priority: Normal
* Assignee: ioquatix (Samuel Williams)
* ruby -v: 3.0.0
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN
----------------------------------------
I'm not sure this is a bug, but apparently a change was introduced in Ruby 3.0 that makes sockets non-blocking by default. This change was apparently introduced as part of the work on the [FiberScheduler interface](https://github.com/ruby/ruby/blame/78f188524f551c97b1a7a44ae13514729f1a21c7/ext/socket/init.c#L411-L434). This change of behaviour is not discussed in the Ruby 3.0.0 release notes.
This change complicates the implementation of an io_uring-based fiber scheduler, since io_uring SQE's on fd's with `O_NONBLOCK` can return `EAGAIN` just like normal syscalls. Using io_uring with non-blocking fd's defeats the whole purpose of using io_uring in the first place.
A workaround I have put in place in the Polyphony [io_uring backend](https://github.com/digital-fabric/polyphony/blob/d3c9cf3ddc1f414387948fa40e5f6a24f68bf045/ext/polyphony/backend_io_uring.c#L28-L47) is to make sure `O_NONBLOCK` is not set before attempting I/O operations on any fd.
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>