polyphony 0.58 → 0.61
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/CHANGELOG.md +26 -0
- data/Gemfile.lock +15 -29
- data/examples/core/message_based_supervision.rb +51 -0
- data/examples/io/echo_server.rb +16 -7
- data/ext/polyphony/backend_common.c +160 -7
- data/ext/polyphony/backend_common.h +34 -2
- data/ext/polyphony/backend_io_uring.c +119 -40
- data/ext/polyphony/backend_io_uring_context.c +10 -1
- data/ext/polyphony/backend_io_uring_context.h +5 -3
- data/ext/polyphony/backend_libev.c +109 -31
- data/ext/polyphony/extconf.rb +2 -2
- data/ext/polyphony/fiber.c +1 -34
- data/ext/polyphony/polyphony.c +12 -19
- data/ext/polyphony/polyphony.h +9 -20
- data/ext/polyphony/polyphony_ext.c +0 -4
- data/ext/polyphony/queue.c +12 -12
- data/ext/polyphony/runqueue.c +21 -98
- data/ext/polyphony/runqueue.h +26 -0
- data/ext/polyphony/thread.c +6 -113
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/extensions/fiber.rb +102 -82
- data/lib/polyphony/extensions/io.rb +10 -9
- data/lib/polyphony/extensions/openssl.rb +14 -4
- data/lib/polyphony/extensions/socket.rb +15 -15
- data/lib/polyphony/extensions/thread.rb +1 -1
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +0 -7
- data/test/test_backend.rb +46 -9
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +106 -18
- data/test/test_global_api.rb +1 -1
- data/test/test_io.rb +29 -0
- data/test/test_supervise.rb +100 -100
- data/test/test_thread.rb +5 -11
- data/test/test_thread_pool.rb +1 -1
- data/test/test_trace.rb +28 -49
- metadata +5 -109
- data/ext/polyphony/tracing.c +0 -11
- data/lib/polyphony/adapters/trace.rb +0 -138
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b7056ec954b2264a15f88934d2b1e65f53c76c301453851ceadf60715570e474
|
|
4
|
+
data.tar.gz: 1cd5835b7a5a3d4036e1eabf45ded2e09efdc7cacb207fc0a1a60ac67da02d90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b5e32edc6bc22ba580e7c6d7d42a73982803080e9a9782326cb7b8796aa62ad6b75bccb1e6607879f0d3e5a5c4db8e5597d8407b76014f08f3945d1d8ad0097a
|
|
7
|
+
data.tar.gz: b8fe0f9419061295f830ed12ae9c8ea089a966686388cff580ddb6e1f7cd8c17a04928f9af41083019a5a11e8cccce25af404959db30a730a2ade2359a7e07ef
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
## 0.61 2021-07-20
|
|
2
|
+
|
|
3
|
+
- Add more statistics, move stats to `Backend#stats`
|
|
4
|
+
|
|
5
|
+
## 0.60 2021-07-15
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
- Fix linux version detection (for kernel version > 5.9)
|
|
9
|
+
- Fix op ctx leak in io_uring backend (when polling for I/O readiness)
|
|
10
|
+
- Add support for appending to buffer in `Backend#read`, `Backend#recv` methods
|
|
11
|
+
- Improve anti-event starvation mechanism
|
|
12
|
+
- Redesign fiber monitoring mechanism
|
|
13
|
+
- Implement `Fiber#attach`
|
|
14
|
+
- Add optional maxlen argument to `IO#read_loop`, `Socket#recv_loop` (#60)
|
|
15
|
+
- Implement `Fiber#detach` (#52)
|
|
16
|
+
|
|
17
|
+
## 0.59.1 2021-06-28
|
|
18
|
+
|
|
19
|
+
- Accept fiber tag in `Polyphony::Timer.new`
|
|
20
|
+
|
|
21
|
+
## 0.59 2021-06-28
|
|
22
|
+
|
|
23
|
+
- Redesign tracing mechanism and API - now completely separated from Ruby core
|
|
24
|
+
trace API
|
|
25
|
+
- Refactor C code - move run queue into backend
|
|
26
|
+
|
|
1
27
|
## 0.58 2021-06-25
|
|
2
28
|
|
|
3
29
|
- Implement `Thread#idle_gc_period`, `#on_idle` (#56)
|
data/Gemfile.lock
CHANGED
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
polyphony (0.
|
|
4
|
+
polyphony (0.61)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
9
|
ansi (1.5.0)
|
|
10
|
-
ast (2.4.
|
|
10
|
+
ast (2.4.2)
|
|
11
11
|
builder (3.2.4)
|
|
12
12
|
coderay (1.1.3)
|
|
13
|
-
docile (1.
|
|
14
|
-
hiredis (0.6.3)
|
|
15
|
-
http_parser.rb (0.6.0)
|
|
13
|
+
docile (1.4.0)
|
|
16
14
|
httparty (0.17.1)
|
|
17
15
|
mime-types (~> 3.0)
|
|
18
16
|
multi_xml (>= 0.5.2)
|
|
19
|
-
json (2.
|
|
17
|
+
json (2.5.1)
|
|
20
18
|
localhost (1.1.8)
|
|
21
19
|
method_source (1.0.0)
|
|
22
20
|
mime-types (3.3.1)
|
|
23
21
|
mime-types-data (~> 3.2015)
|
|
24
|
-
mime-types-data (3.
|
|
22
|
+
mime-types-data (3.2021.0704)
|
|
25
23
|
minitest (5.14.4)
|
|
26
24
|
minitest-reporters (1.4.2)
|
|
27
25
|
ansi
|
|
@@ -30,22 +28,18 @@ GEM
|
|
|
30
28
|
ruby-progressbar
|
|
31
29
|
msgpack (1.4.2)
|
|
32
30
|
multi_xml (0.6.0)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
ast (~> 2.4.0)
|
|
37
|
-
pg (1.1.4)
|
|
31
|
+
parallel (1.20.1)
|
|
32
|
+
parser (3.0.2.0)
|
|
33
|
+
ast (~> 2.4.1)
|
|
38
34
|
pry (0.13.1)
|
|
39
35
|
coderay (~> 1.1)
|
|
40
36
|
method_source (~> 1.0)
|
|
41
|
-
rack (2.2.3)
|
|
42
37
|
rainbow (3.0.0)
|
|
43
|
-
rake (13.0.
|
|
38
|
+
rake (13.0.6)
|
|
44
39
|
rake-compiler (1.1.1)
|
|
45
40
|
rake
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
rexml (3.2.4)
|
|
41
|
+
regexp_parser (2.1.1)
|
|
42
|
+
rexml (3.2.5)
|
|
49
43
|
rubocop (0.85.1)
|
|
50
44
|
parallel (~> 1.10)
|
|
51
45
|
parser (>= 2.7.0.1)
|
|
@@ -55,37 +49,29 @@ GEM
|
|
|
55
49
|
rubocop-ast (>= 0.0.3)
|
|
56
50
|
ruby-progressbar (~> 1.7)
|
|
57
51
|
unicode-display_width (>= 1.4.0, < 2.0)
|
|
58
|
-
rubocop-ast (
|
|
59
|
-
parser (>=
|
|
60
|
-
ruby-progressbar (1.
|
|
61
|
-
sequel (5.34.0)
|
|
52
|
+
rubocop-ast (1.8.0)
|
|
53
|
+
parser (>= 3.0.1.1)
|
|
54
|
+
ruby-progressbar (1.11.0)
|
|
62
55
|
simplecov (0.17.1)
|
|
63
56
|
docile (~> 1.1)
|
|
64
57
|
json (>= 1.8, < 3)
|
|
65
58
|
simplecov-html (~> 0.10.0)
|
|
66
59
|
simplecov-html (0.10.2)
|
|
67
|
-
unicode-display_width (1.
|
|
60
|
+
unicode-display_width (1.7.0)
|
|
68
61
|
|
|
69
62
|
PLATFORMS
|
|
70
63
|
ruby
|
|
71
64
|
|
|
72
65
|
DEPENDENCIES
|
|
73
|
-
hiredis (= 0.6.3)
|
|
74
|
-
http_parser.rb (~> 0.6.0)
|
|
75
66
|
httparty (= 0.17.1)
|
|
76
67
|
localhost (~> 1.1.4)
|
|
77
68
|
minitest (= 5.14.4)
|
|
78
69
|
minitest-reporters (= 1.4.2)
|
|
79
70
|
msgpack (= 1.4.2)
|
|
80
|
-
mysql2 (= 0.5.3)
|
|
81
|
-
pg (= 1.1.4)
|
|
82
71
|
polyphony!
|
|
83
72
|
pry (= 0.13.1)
|
|
84
|
-
rack (>= 2.0.8, < 2.3.0)
|
|
85
73
|
rake-compiler (= 1.1.1)
|
|
86
|
-
redis (= 4.1.0)
|
|
87
74
|
rubocop (= 0.85.1)
|
|
88
|
-
sequel (= 5.34.0)
|
|
89
75
|
simplecov (= 0.17.1)
|
|
90
76
|
|
|
91
77
|
BUNDLED WITH
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'polyphony'
|
|
5
|
+
|
|
6
|
+
class Supervisor
|
|
7
|
+
def initialize(*fibers)
|
|
8
|
+
@fiber = spin { do_supervise }
|
|
9
|
+
@fiber.message_on_child_termination = true
|
|
10
|
+
fibers.each { |f| add(f) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def await
|
|
14
|
+
@fiber.await
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def spin(tag = nil, &block)
|
|
18
|
+
@fiber.spin(tag, &block)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def add(fiber)
|
|
22
|
+
fiber.attach(@fiber)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def do_supervise
|
|
26
|
+
loop do
|
|
27
|
+
msg = receive
|
|
28
|
+
# puts "Supervisor received #{msg.inspect}"
|
|
29
|
+
f, r = msg
|
|
30
|
+
puts "Fiber #{f.tag} terminated with #{r.inspect}, restarting..."
|
|
31
|
+
f.restart
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def supervise(*fibers)
|
|
37
|
+
supervisor = Supervisor.new(*fibers)
|
|
38
|
+
supervisor.await
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def start_worker(id)
|
|
42
|
+
spin_loop(:"worker#{id}") do
|
|
43
|
+
duration = rand(0.5..1.0)
|
|
44
|
+
puts "Worker #{id} sleeping for #{duration} seconds"
|
|
45
|
+
sleep duration
|
|
46
|
+
raise 'foo' if rand > 0.7
|
|
47
|
+
break if rand > 0.6
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
supervise(start_worker(1), start_worker(2))
|
data/examples/io/echo_server.rb
CHANGED
|
@@ -3,16 +3,25 @@
|
|
|
3
3
|
require 'bundler/setup'
|
|
4
4
|
require 'polyphony'
|
|
5
5
|
|
|
6
|
+
spin_loop(interval: 5) { p Thread.backend.stats }
|
|
7
|
+
|
|
6
8
|
server = TCPServer.open('127.0.0.1', 1234)
|
|
7
9
|
puts "Pid: #{Process.pid}"
|
|
8
10
|
puts 'Echoing on port 1234...'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
begin
|
|
12
|
+
while (client = server.accept)
|
|
13
|
+
spin do
|
|
14
|
+
while (data = client.gets)
|
|
15
|
+
# client.send("you said: #{data.chomp}!\n", 0)
|
|
16
|
+
client.write('you said: ', data.chomp, "!\n")
|
|
17
|
+
end
|
|
18
|
+
rescue Errno::ECONNRESET
|
|
19
|
+
'Connection reset...'
|
|
20
|
+
ensure
|
|
21
|
+
client.shutdown
|
|
22
|
+
client.close
|
|
14
23
|
end
|
|
15
|
-
rescue Errno::ECONNRESET
|
|
16
|
-
'Connection reset...'
|
|
17
24
|
end
|
|
25
|
+
ensure
|
|
26
|
+
server.close
|
|
18
27
|
end
|
|
@@ -5,12 +5,127 @@
|
|
|
5
5
|
#include "polyphony.h"
|
|
6
6
|
#include "backend_common.h"
|
|
7
7
|
|
|
8
|
-
inline void
|
|
8
|
+
inline void backend_base_initialize(struct Backend_base *base) {
|
|
9
|
+
runqueue_initialize(&base->runqueue);
|
|
9
10
|
base->currently_polling = 0;
|
|
11
|
+
base->op_count = 0;
|
|
12
|
+
base->switch_count = 0;
|
|
13
|
+
base->poll_count = 0;
|
|
10
14
|
base->pending_count = 0;
|
|
11
15
|
base->idle_gc_period = 0;
|
|
12
16
|
base->idle_gc_last_time = 0;
|
|
13
|
-
base->
|
|
17
|
+
base->idle_proc = Qnil;
|
|
18
|
+
base->trace_proc = Qnil;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
inline void backend_base_finalize(struct Backend_base *base) {
|
|
22
|
+
runqueue_finalize(&base->runqueue);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
inline void backend_base_mark(struct Backend_base *base) {
|
|
26
|
+
if (base->idle_proc != Qnil) rb_gc_mark(base->idle_proc);
|
|
27
|
+
if (base->trace_proc != Qnil) rb_gc_mark(base->trace_proc);
|
|
28
|
+
runqueue_mark(&base->runqueue);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
|
32
|
+
|
|
33
|
+
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
|
34
|
+
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
|
35
|
+
Backend_poll(backend, Qnil);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
39
|
+
VALUE current_fiber = rb_fiber_current();
|
|
40
|
+
runqueue_entry next;
|
|
41
|
+
unsigned int pending_ops_count = base->pending_count;
|
|
42
|
+
unsigned int backend_was_polled = 0;
|
|
43
|
+
unsigned int idle_tasks_run_count = 0;
|
|
44
|
+
|
|
45
|
+
base->switch_count++;
|
|
46
|
+
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
|
47
|
+
|
|
48
|
+
while (1) {
|
|
49
|
+
next = runqueue_shift(&base->runqueue);
|
|
50
|
+
if (next.fiber != Qnil) {
|
|
51
|
+
// Polling for I/O op completion is normally done when the run queue is
|
|
52
|
+
// empty, but if the runqueue never empties, we'll never get to process
|
|
53
|
+
// any event completions. In order to prevent this, an anti-starvation
|
|
54
|
+
// mechanism is employed, under the following conditions:
|
|
55
|
+
// - a blocking poll was not yet performed
|
|
56
|
+
// - there are pending blocking operations
|
|
57
|
+
// - the runqueue shift count has reached a fixed threshold (currently 64), or
|
|
58
|
+
// - the next fiber is the same as the current fiber (a single fiber is snoozing)
|
|
59
|
+
if (!backend_was_polled && pending_ops_count)
|
|
60
|
+
conditional_nonblocking_poll(backend, base, current_fiber, next.fiber);
|
|
61
|
+
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!idle_tasks_run_count) {
|
|
66
|
+
idle_tasks_run_count++;
|
|
67
|
+
backend_run_idle_tasks(base);
|
|
68
|
+
}
|
|
69
|
+
if (pending_ops_count == 0) break;
|
|
70
|
+
Backend_poll(backend, Qtrue);
|
|
71
|
+
backend_was_polled = 1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (next.fiber == Qnil) return Qnil;
|
|
75
|
+
|
|
76
|
+
// run next fiber
|
|
77
|
+
COND_TRACE(base, 3, SYM_fiber_run, next.fiber, next.value);
|
|
78
|
+
|
|
79
|
+
rb_ivar_set(next.fiber, ID_ivar_runnable, Qnil);
|
|
80
|
+
RB_GC_GUARD(next.fiber);
|
|
81
|
+
RB_GC_GUARD(next.value);
|
|
82
|
+
return (next.fiber == current_fiber) ?
|
|
83
|
+
next.value : FIBER_TRANSFER(next.fiber, next.value);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize) {
|
|
87
|
+
int already_runnable;
|
|
88
|
+
|
|
89
|
+
if (rb_fiber_alive_p(fiber) != Qtrue) return;
|
|
90
|
+
already_runnable = rb_ivar_get(fiber, ID_ivar_runnable) != Qnil;
|
|
91
|
+
|
|
92
|
+
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
|
93
|
+
|
|
94
|
+
(prioritize ? runqueue_unshift : runqueue_push)(&base->runqueue, fiber, value, already_runnable);
|
|
95
|
+
if (!already_runnable) {
|
|
96
|
+
rb_ivar_set(fiber, ID_ivar_runnable, Qtrue);
|
|
97
|
+
if (rb_thread_current() != thread) {
|
|
98
|
+
// If the fiber scheduling is done across threads, we need to make sure the
|
|
99
|
+
// target thread is woken up in case it is in the middle of running its
|
|
100
|
+
// event selector. Otherwise it's gonna be stuck waiting for an event to
|
|
101
|
+
// happen, not knowing that it there's already a fiber ready to run in its
|
|
102
|
+
// run queue.
|
|
103
|
+
Backend_wakeup(backend);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
|
110
|
+
if (base->trace_proc == Qnil) return;
|
|
111
|
+
|
|
112
|
+
rb_funcallv(base->trace_proc, ID_call, argc, argv);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
inline struct backend_stats backend_base_stats(struct Backend_base *base) {
|
|
116
|
+
struct backend_stats stats = {
|
|
117
|
+
.runqueue_length = runqueue_len(&base->runqueue),
|
|
118
|
+
.runqueue_max_length = runqueue_max_len(&base->runqueue),
|
|
119
|
+
.op_count = base->op_count,
|
|
120
|
+
.switch_count = base->switch_count,
|
|
121
|
+
.poll_count = base->poll_count,
|
|
122
|
+
.pending_ops = base->pending_count
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
base->op_count = 0;
|
|
126
|
+
base->switch_count = 0;
|
|
127
|
+
base->poll_count = 0;
|
|
128
|
+
return stats;
|
|
14
129
|
}
|
|
15
130
|
|
|
16
131
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
|
@@ -80,7 +195,7 @@ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
|
|
80
195
|
//////////////////////////////////////////////////////////////////////
|
|
81
196
|
//////////////////////////////////////////////////////////////////////
|
|
82
197
|
|
|
83
|
-
VALUE backend_await(struct Backend_base *backend) {
|
|
198
|
+
inline VALUE backend_await(struct Backend_base *backend) {
|
|
84
199
|
VALUE ret;
|
|
85
200
|
backend->pending_count++;
|
|
86
201
|
ret = Thread_switch_fiber(rb_thread_current());
|
|
@@ -89,9 +204,10 @@ VALUE backend_await(struct Backend_base *backend) {
|
|
|
89
204
|
return ret;
|
|
90
205
|
}
|
|
91
206
|
|
|
92
|
-
VALUE backend_snooze() {
|
|
207
|
+
inline VALUE backend_snooze() {
|
|
208
|
+
VALUE ret;
|
|
93
209
|
Fiber_make_runnable(rb_fiber_current(), Qnil);
|
|
94
|
-
|
|
210
|
+
ret = Thread_switch_fiber(rb_thread_current());
|
|
95
211
|
return ret;
|
|
96
212
|
}
|
|
97
213
|
|
|
@@ -182,8 +298,8 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
|
182
298
|
}
|
|
183
299
|
|
|
184
300
|
inline void backend_run_idle_tasks(struct Backend_base *base) {
|
|
185
|
-
if (base->
|
|
186
|
-
rb_funcall(base->
|
|
301
|
+
if (base->idle_proc != Qnil)
|
|
302
|
+
rb_funcall(base->idle_proc, ID_call, 0);
|
|
187
303
|
|
|
188
304
|
if (base->idle_gc_period == 0) return;
|
|
189
305
|
|
|
@@ -195,3 +311,40 @@ inline void backend_run_idle_tasks(struct Backend_base *base) {
|
|
|
195
311
|
rb_gc_start();
|
|
196
312
|
rb_gc_disable();
|
|
197
313
|
}
|
|
314
|
+
|
|
315
|
+
VALUE SYM_runqueue_length;
|
|
316
|
+
VALUE SYM_runqueue_max_length;
|
|
317
|
+
VALUE SYM_op_count;
|
|
318
|
+
VALUE SYM_switch_count;
|
|
319
|
+
VALUE SYM_poll_count;
|
|
320
|
+
VALUE SYM_pending_ops;
|
|
321
|
+
|
|
322
|
+
VALUE Backend_stats(VALUE self) {
|
|
323
|
+
struct backend_stats backend_stats = backend_get_stats(self);
|
|
324
|
+
|
|
325
|
+
VALUE stats = rb_hash_new();
|
|
326
|
+
rb_hash_aset(stats, SYM_runqueue_length, INT2NUM(backend_stats.runqueue_length));
|
|
327
|
+
rb_hash_aset(stats, SYM_runqueue_max_length, INT2NUM(backend_stats.runqueue_max_length));
|
|
328
|
+
rb_hash_aset(stats, SYM_op_count, INT2NUM(backend_stats.op_count));
|
|
329
|
+
rb_hash_aset(stats, SYM_switch_count, INT2NUM(backend_stats.switch_count));
|
|
330
|
+
rb_hash_aset(stats, SYM_poll_count, INT2NUM(backend_stats.poll_count));
|
|
331
|
+
rb_hash_aset(stats, SYM_pending_ops, INT2NUM(backend_stats.pending_ops));
|
|
332
|
+
RB_GC_GUARD(stats);
|
|
333
|
+
return stats;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
void backend_setup_stats_symbols() {
|
|
337
|
+
SYM_runqueue_length = ID2SYM(rb_intern("runqueue_length"));
|
|
338
|
+
SYM_runqueue_max_length = ID2SYM(rb_intern("runqueue_max_length"));
|
|
339
|
+
SYM_op_count = ID2SYM(rb_intern("op_count"));
|
|
340
|
+
SYM_switch_count = ID2SYM(rb_intern("switch_count"));
|
|
341
|
+
SYM_poll_count = ID2SYM(rb_intern("poll_count"));
|
|
342
|
+
SYM_pending_ops = ID2SYM(rb_intern("pending_ops"));
|
|
343
|
+
|
|
344
|
+
rb_global_variable(&SYM_runqueue_length);
|
|
345
|
+
rb_global_variable(&SYM_runqueue_max_length);
|
|
346
|
+
rb_global_variable(&SYM_op_count);
|
|
347
|
+
rb_global_variable(&SYM_switch_count);
|
|
348
|
+
rb_global_variable(&SYM_poll_count);
|
|
349
|
+
rb_global_variable(&SYM_pending_ops);
|
|
350
|
+
}
|
|
@@ -3,16 +3,44 @@
|
|
|
3
3
|
|
|
4
4
|
#include "ruby.h"
|
|
5
5
|
#include "ruby/io.h"
|
|
6
|
+
#include "runqueue.h"
|
|
7
|
+
|
|
8
|
+
struct backend_stats {
|
|
9
|
+
unsigned int runqueue_length;
|
|
10
|
+
unsigned int runqueue_max_length;
|
|
11
|
+
unsigned int op_count;
|
|
12
|
+
unsigned int switch_count;
|
|
13
|
+
unsigned int poll_count;
|
|
14
|
+
unsigned int pending_ops;
|
|
15
|
+
};
|
|
6
16
|
|
|
7
17
|
struct Backend_base {
|
|
18
|
+
runqueue_t runqueue;
|
|
8
19
|
unsigned int currently_polling;
|
|
20
|
+
unsigned int op_count;
|
|
21
|
+
unsigned int switch_count;
|
|
22
|
+
unsigned int poll_count;
|
|
9
23
|
unsigned int pending_count;
|
|
10
24
|
double idle_gc_period;
|
|
11
25
|
double idle_gc_last_time;
|
|
12
|
-
VALUE
|
|
26
|
+
VALUE idle_proc;
|
|
27
|
+
VALUE trace_proc;
|
|
13
28
|
};
|
|
14
29
|
|
|
15
|
-
void
|
|
30
|
+
void backend_base_initialize(struct Backend_base *base);
|
|
31
|
+
void backend_base_finalize(struct Backend_base *base);
|
|
32
|
+
void backend_base_mark(struct Backend_base *base);
|
|
33
|
+
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
|
34
|
+
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
|
35
|
+
void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
|
36
|
+
struct backend_stats backend_base_stats(struct Backend_base *base);
|
|
37
|
+
|
|
38
|
+
// tracing
|
|
39
|
+
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil)
|
|
40
|
+
#define TRACE(base, ...) rb_funcall((base)->trace_proc, ID_call, __VA_ARGS__)
|
|
41
|
+
#define COND_TRACE(base, ...) if (SHOULD_TRACE(base)) { TRACE(base, __VA_ARGS__); }
|
|
42
|
+
|
|
43
|
+
|
|
16
44
|
|
|
17
45
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
|
18
46
|
int pidfd_open(pid_t pid, unsigned int flags);
|
|
@@ -39,6 +67,7 @@ VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
|
|
39
67
|
//////////////////////////////////////////////////////////////////////
|
|
40
68
|
//////////////////////////////////////////////////////////////////////
|
|
41
69
|
|
|
70
|
+
struct backend_stats backend_get_stats(VALUE self);
|
|
42
71
|
VALUE backend_await(struct Backend_base *backend);
|
|
43
72
|
VALUE backend_snooze();
|
|
44
73
|
|
|
@@ -71,7 +100,10 @@ VALUE backend_timeout_exception(VALUE exception);
|
|
|
71
100
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
|
72
101
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
|
73
102
|
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
|
103
|
+
VALUE Backend_stats(VALUE self);
|
|
74
104
|
void backend_run_idle_tasks(struct Backend_base *base);
|
|
75
105
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
|
76
106
|
|
|
107
|
+
void backend_setup_stats_symbols();
|
|
108
|
+
|
|
77
109
|
#endif /* BACKEND_COMMON_H */
|