evt 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|