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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7c2d7880e0a6e8232a91b2aa154adcc7705c87d3907b33beb27f3f7b10dcbac
4
- data.tar.gz: 7d882336538396f34a3c54bb8ccc3dd34b9431f60709d9527c87e3136d0c646b
3
+ metadata.gz: 3275dc2e231b57c3e740671f2d431ede41ca23339ba799b280edeed1c7be8d2c
4
+ data.tar.gz: 4107ecb57ec3ff7e566187013348a056773ac654eb2b369b7fa8bb057675750e
5
5
  SHA512:
6
- metadata.gz: 28f8fb3d3ed2b0c1ee797ba1a36974392e5e7d8c00b38c4f7b25f95c0bf759e2d7f20402f6cb7dc1399187cc4c03e7c0e8d80d641551cc815e20db992d014843
7
- data.tar.gz: 90e7cb4395e297761462376990b5faef42598d517dcbc3d5b0001e08d5e39582d158739ba5461eb3700651166fb1041ab15b551dd50f1af002116abc3698cea9
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`) | ✅ Fallback | ✅ (⚠️See 4) | ✅ Fallback | ✅ Fallback |
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.1` 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
+ 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:3001`.
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 | 1853259.47 |
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) | 1636849.15 |
44
- | macOS | i7-6820HQ | 16GB | kqueue | 247370.37 |
45
- | macOS | i7-6820HQ | 16GB | IO.select (using poll) | 323391.38 |
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
@@ -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.rc1'
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"
@@ -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, readables, writables, result;
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
- readables = rb_ary_new();
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
- if (event_flag & EPOLLIN) {
62
- obj_io = (VALUE) events[i].data.ptr;
63
- rb_funcall(readables, id_push, 1, obj_io);
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(2);
73
- rb_ary_store(result, 0, readables);
74
- rb_ary_store(result, 1, writables);
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
 
@@ -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
@@ -22,6 +22,9 @@ class Evt::Select < Evt::Bundled
22
22
 
23
23
  def wait
24
24
  select_wait
25
+ rescue IOError => _
26
+ collect(true)
27
+ return [], []
25
28
  rescue Errno::EBADF => _
26
29
  collect(true)
27
30
  return [], []
@@ -20,13 +20,14 @@ class Evt::Uring < Evt::Bundled
20
20
  def deregister(io)
21
21
  end
22
22
 
23
- def io_read(io, buffer, offset, length)
24
- uring_io_read(io, buffer, offset, length)
25
- end
26
-
27
- def io_write(io, buffer, offset, length)
28
- uring_io_write(io, buffer, offset, length)
29
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evt
4
- VERSION = "0.3.6"
4
+ VERSION = "0.4.0"
5
5
  end
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.3.6
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-23 00:00:00.000000000 Z
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.rc1
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.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.