evt 0.3.6 → 0.4.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 +4 -4
- data/README.md +47 -9
- data/evt.gemspec +1 -1
- data/ext/evt/epoll.h +13 -15
- data/lib/evt/backends/epoll.rb +50 -0
- data/lib/evt/backends/select.rb +3 -0
- data/lib/evt/backends/uring.rb +8 -7
- data/lib/evt/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3275dc2e231b57c3e740671f2d431ede41ca23339ba799b280edeed1c7be8d2c
|
4
|
+
data.tar.gz: 4107ecb57ec3ff7e566187013348a056773ac654eb2b369b7fa8bb057675750e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db3172fe0ee6776480a64ee036aedb03b09ee5d5c8a5088fe68e4a969d7058964e8c55b004bb69962f61bffdb13a1c6c28ce49d339f8194e616ae44d877a9616
|
7
|
+
data.tar.gz: 94e287ddb35ae5f99e15ebf27ef76ce54ce3272008fe7c535483706111a8a39ff3168d2289135a027934d45c4382b51527c240fc9d7fbf6b9ce13f2ca7b016e3
|
data/README.md
CHANGED
@@ -19,30 +19,59 @@ The Event Library that designed for Ruby 3.0 Fiber Scheduler.
|
|
19
19
|
| epoll | ✅ (See 2) | ❌ | ❌ | ❌ |
|
20
20
|
| kqueue | ❌ | ❌ | ✅ (⚠️ See 5) | ✅ |
|
21
21
|
| IOCP | ❌ | ❌ (⚠️See 3) | ❌ | ❌ |
|
22
|
-
| Ruby (`IO.select`) | ✅
|
22
|
+
| Ruby (`IO.select`) | ✅ (See 6) | ✅ (⚠️See 4) | ✅ (See 6) | ✅ (See 6) |
|
23
23
|
|
24
24
|
1. when liburing is installed. (Currently fixing)
|
25
25
|
2. when kernel version >= 2.6.9
|
26
26
|
3. WOULD NOT WORK until `FILE_FLAG_OVERLAPPED` is included in I/O initialization process.
|
27
|
-
4. Some I/Os are not able to be nonblock under Windows. See [Scheduler Docs](https://docs.ruby-lang.org/en/master/doc/scheduler_md.html#label-IO).
|
27
|
+
4. Some I/Os are not able to be nonblock under Windows. Using POSIX select, **SLOW**. See [Scheduler Docs](https://docs.ruby-lang.org/en/master/doc/scheduler_md.html#label-IO).
|
28
28
|
5. `kqueue` performance in Darwin is very poor. **MAY BE DISABLED IN THE FUTURE.**
|
29
|
+
6. Using poll
|
29
30
|
|
30
31
|
### Benchmark
|
31
32
|
|
32
|
-
The benchmark is running under `v0.3.
|
33
|
+
The benchmark is running under `v0.3.6` version. See `example.rb` in [midori](https://github.com/midori-rb/midori.rb) for test code, the test is running under a single-thread server.
|
33
34
|
|
34
|
-
The test command is `wrk -t4 -c8192 -d30s http://localhost:
|
35
|
+
The test command is `wrk -t4 -c8192 -d30s http://localhost:8080`.
|
35
36
|
|
36
37
|
All of the systems have set their file descriptor limit to maximum.
|
37
38
|
On systems raising "Fiber unable to allocate memory", `sudo sysctl -w vm.max_map_count=1000000` is set.
|
38
39
|
|
39
40
|
| OS | CPU | Memory | Backend | req/s |
|
40
|
-
| ----- | ----------- | ------ | ---------------------- |
|
41
|
-
| Linux | Ryzen 2700x | 64GB | epoll |
|
41
|
+
| ----- | ----------- | ------ | ---------------------- | ------------- |
|
42
|
+
| Linux | Ryzen 2700x | 64GB | epoll | 2035742.59 |
|
42
43
|
| Linux | Ryzen 2700x | 64GB | io_uring | require fixes |
|
43
|
-
| Linux | Ryzen 2700x | 64GB | IO.select (using poll) |
|
44
|
-
| macOS | i7-6820HQ | 16GB | kqueue |
|
45
|
-
| macOS | i7-6820HQ | 16GB | IO.select (using poll) |
|
44
|
+
| Linux | Ryzen 2700x | 64GB | IO.select (using poll) | 1837640.54 |
|
45
|
+
| macOS | i7-6820HQ | 16GB | kqueue | 257821.78 |
|
46
|
+
| macOS | i7-6820HQ | 16GB | IO.select (using poll) | 338392.12 |
|
47
|
+
|
48
|
+
We also test the server with Redis request, with a [monkey-patched redis library](https://github.com/midori-rb/midori-contrib/blob/master/lib/midori-contrib/redic.rb). The example code is following:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require 'evt'
|
52
|
+
require 'midori'
|
53
|
+
require 'midori-contrib/redic'
|
54
|
+
|
55
|
+
Fiber.set_scheduler Evt::Scheduler.new
|
56
|
+
REDIS = Redic.new
|
57
|
+
|
58
|
+
class HelloWorldAPI < Midori::API
|
59
|
+
get '/' do
|
60
|
+
REDIS.call 'GET', 'foo'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Fiber.schedule do
|
65
|
+
Midori::Runner.new(HelloWorldAPI).start
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
The benckmark result is as following:
|
70
|
+
|
71
|
+
| OS | CPU | Memory | Backend | req/s |
|
72
|
+
| ----- | ----------- | ------ | ------- | --------- |
|
73
|
+
| Linux | Ryzen 2700x | 64GB | epoll | 378060.30 |
|
74
|
+
| macOS | i7-6820HQ | 16GB | kqueue | 204460.32 |
|
46
75
|
|
47
76
|
## Install
|
48
77
|
|
@@ -74,6 +103,15 @@ end
|
|
74
103
|
# "Hello World"
|
75
104
|
```
|
76
105
|
|
106
|
+
| | Windows `WaitFor...` | Windows `select` | Windows IOCP | `io_uring` | `epoll` | `kqueue` | `poll` | *NIX `select` |
|
107
|
+
| -------------- | -------------------- | ---------------- | ------------ | ---------- | ------- | -------- | ------ | ------------- |
|
108
|
+
| Anonymous Pipe | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
109
|
+
| Named Pipe | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
110
|
+
| Socket | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
111
|
+
| File | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
112
|
+
|
113
|
+
|
114
|
+
|
77
115
|
## Roadmap
|
78
116
|
|
79
117
|
- [x] Support epoll/kqueue/select
|
data/evt.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = "A low-level Event Handler designed for Ruby 3 Scheduler for better performance"
|
11
11
|
spec.homepage = "https://github.com/dsh0416/evt"
|
12
12
|
spec.license = 'BSD-3-Clause'
|
13
|
-
spec.required_ruby_version = '>= 3.0.0
|
13
|
+
spec.required_ruby_version = '>= 3.0.0'
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
16
|
spec.metadata["source_code_uri"] = "https://github.com/dsh0416/evt"
|
data/ext/evt/epoll.h
CHANGED
@@ -26,6 +26,8 @@ VALUE method_scheduler_epoll_register(VALUE self, VALUE io, VALUE interest) {
|
|
26
26
|
event.events |= EPOLLOUT;
|
27
27
|
}
|
28
28
|
|
29
|
+
event.events |= EPOLLRDHUP;
|
30
|
+
|
29
31
|
event.data.ptr = (void*) io;
|
30
32
|
|
31
33
|
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
|
@@ -34,14 +36,13 @@ VALUE method_scheduler_epoll_register(VALUE self, VALUE io, VALUE interest) {
|
|
34
36
|
|
35
37
|
VALUE method_scheduler_epoll_wait(VALUE self) {
|
36
38
|
int n, epfd, i, event_flag, timeout;
|
37
|
-
VALUE next_timeout, obj_io,
|
39
|
+
VALUE next_timeout, obj_io, iovs, result;
|
38
40
|
ID id_next_timeout = rb_intern("next_timeout");
|
39
41
|
ID id_push = rb_intern("push");
|
40
42
|
|
41
43
|
epfd = NUM2INT(rb_iv_get(self, "@epfd"));
|
42
44
|
next_timeout = rb_funcall(self, id_next_timeout, 0);
|
43
|
-
|
44
|
-
writables = rb_ary_new();
|
45
|
+
iovs = rb_ary_new();
|
45
46
|
|
46
47
|
if (next_timeout == Qnil) {
|
47
48
|
timeout = -1;
|
@@ -58,20 +59,17 @@ VALUE method_scheduler_epoll_wait(VALUE self) {
|
|
58
59
|
|
59
60
|
for (i = 0; i < n; i++) {
|
60
61
|
event_flag = events[i].events;
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if (event_flag & EPOLLOUT) {
|
67
|
-
obj_io = (VALUE) events[i].data.ptr;
|
68
|
-
rb_funcall(writables, id_push, 1, obj_io);
|
69
|
-
}
|
62
|
+
obj_io = (VALUE) events[i].data.ptr;
|
63
|
+
VALUE e = rb_ary_new2(2);
|
64
|
+
rb_ary_store(e, 0, obj_io);
|
65
|
+
rb_ary_store(e, 1, INT2NUM(event_flag));
|
66
|
+
rb_funcall(iovs, id_push, 1, e);
|
70
67
|
}
|
71
68
|
|
72
|
-
result = rb_ary_new2(
|
73
|
-
rb_ary_store(result, 0,
|
74
|
-
rb_ary_store(result, 1,
|
69
|
+
result = rb_ary_new2(3);
|
70
|
+
rb_ary_store(result, 0, rb_ary_new());
|
71
|
+
rb_ary_store(result, 1, rb_ary_new());
|
72
|
+
rb_ary_store(result, 2, iovs);
|
75
73
|
return result;
|
76
74
|
}
|
77
75
|
|
data/lib/evt/backends/epoll.rb
CHANGED
@@ -21,6 +21,56 @@ class Evt::Epoll < Evt::Bundled
|
|
21
21
|
epoll_deregister(io)
|
22
22
|
end
|
23
23
|
|
24
|
+
def io_wait(io, events, duration)
|
25
|
+
@iovs[io] = Fiber.current
|
26
|
+
self.register(io, events)
|
27
|
+
Fiber.yield
|
28
|
+
self.deregister(io)
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
# def io_read(io, buffer, offset, length)
|
33
|
+
# result = +('')
|
34
|
+
|
35
|
+
# self.register(io, IO::READABLE)
|
36
|
+
# direct_read = io.read_nonblock(length, exception: false)
|
37
|
+
|
38
|
+
# unless direct_read == :wait_readable
|
39
|
+
# result << direct_read
|
40
|
+
# end
|
41
|
+
|
42
|
+
# until result.length >= length or io.closed? or io.eof?
|
43
|
+
# @iovs[io] = Fiber.current
|
44
|
+
# Fiber.yield
|
45
|
+
# todo = length - result.length
|
46
|
+
# result << io.read_nonblock(todo)
|
47
|
+
# end
|
48
|
+
|
49
|
+
# self.deregister(io)
|
50
|
+
# buffer[offset...offset+result.length] = result
|
51
|
+
# result.length
|
52
|
+
# end
|
53
|
+
|
54
|
+
# def io_write(io, buffer, offset, length)
|
55
|
+
# finished = 0
|
56
|
+
|
57
|
+
# self.register(io, IO::WRITABLE)
|
58
|
+
# direct_write = io.write_nonblock(buffer.byteslice(offset+finished..-1), exception: false)
|
59
|
+
# unless direct_write == :wait_writable
|
60
|
+
# finished += direct_write
|
61
|
+
# end
|
62
|
+
|
63
|
+
# until finished >= length or io.closed?
|
64
|
+
# @iovs[io] = Fiber.current
|
65
|
+
# Fiber.yield
|
66
|
+
# finished += io.write_nonblock(buffer.byteslice(offset+finished..-1))
|
67
|
+
# end
|
68
|
+
|
69
|
+
# self.deregister(io)
|
70
|
+
|
71
|
+
# finished
|
72
|
+
# end
|
73
|
+
|
24
74
|
def wait
|
25
75
|
epoll_wait
|
26
76
|
end
|
data/lib/evt/backends/select.rb
CHANGED
data/lib/evt/backends/uring.rb
CHANGED
@@ -20,13 +20,14 @@ class Evt::Uring < Evt::Bundled
|
|
20
20
|
def deregister(io)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
23
|
+
# Disable direct I/Os for now
|
24
|
+
# def io_read(io, buffer, offset, length)
|
25
|
+
# uring_io_read(io, buffer, offset, length)
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def io_write(io, buffer, offset, length)
|
29
|
+
# uring_io_write(io, buffer, offset, length)
|
30
|
+
# end
|
30
31
|
|
31
32
|
def wait
|
32
33
|
uring_wait
|
data/lib/evt/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Delton Ding
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -100,14 +100,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 3.0.0
|
103
|
+
version: 3.0.0
|
104
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
|
-
rubygems_version: 3.2.
|
110
|
+
rubygems_version: 3.2.3
|
111
111
|
signing_key:
|
112
112
|
specification_version: 4
|
113
113
|
summary: The Event Library that designed for Ruby 3.0 Fiber Scheluer.
|