polyphony 0.60 → 0.61
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/examples/io/echo_server.rb +16 -7
- data/ext/polyphony/backend_common.c +61 -2
- data/ext/polyphony/backend_common.h +14 -2
- data/ext/polyphony/backend_io_uring.c +17 -6
- data/ext/polyphony/backend_libev.c +32 -5
- data/ext/polyphony/polyphony.h +0 -1
- data/ext/polyphony/runqueue.c +7 -16
- data/ext/polyphony/runqueue.h +1 -2
- data/ext/polyphony/thread.c +0 -18
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +1 -1
- metadata +3 -3
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
data/Gemfile.lock
CHANGED
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
|
@@ -8,6 +8,9 @@
|
|
8
8
|
inline void backend_base_initialize(struct Backend_base *base) {
|
9
9
|
runqueue_initialize(&base->runqueue);
|
10
10
|
base->currently_polling = 0;
|
11
|
+
base->op_count = 0;
|
12
|
+
base->switch_count = 0;
|
13
|
+
base->poll_count = 0;
|
11
14
|
base->pending_count = 0;
|
12
15
|
base->idle_gc_period = 0;
|
13
16
|
base->idle_gc_last_time = 0;
|
@@ -25,8 +28,10 @@ inline void backend_base_mark(struct Backend_base *base) {
|
|
25
28
|
runqueue_mark(&base->runqueue);
|
26
29
|
}
|
27
30
|
|
31
|
+
const unsigned int ANTI_STARVE_SWITCH_COUNT_THRESHOLD = 64;
|
32
|
+
|
28
33
|
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
29
|
-
if (
|
34
|
+
if ((base->switch_count % ANTI_STARVE_SWITCH_COUNT_THRESHOLD) == 0 || next == current)
|
30
35
|
Backend_poll(backend, Qnil);
|
31
36
|
}
|
32
37
|
|
@@ -36,7 +41,8 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
36
41
|
unsigned int pending_ops_count = base->pending_count;
|
37
42
|
unsigned int backend_was_polled = 0;
|
38
43
|
unsigned int idle_tasks_run_count = 0;
|
39
|
-
|
44
|
+
|
45
|
+
base->switch_count++;
|
40
46
|
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
41
47
|
|
42
48
|
while (1) {
|
@@ -106,6 +112,22 @@ inline void backend_trace(struct Backend_base *base, int argc, VALUE *argv) {
|
|
106
112
|
rb_funcallv(base->trace_proc, ID_call, argc, argv);
|
107
113
|
}
|
108
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;
|
129
|
+
}
|
130
|
+
|
109
131
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
110
132
|
#ifndef __NR_pidfd_open
|
111
133
|
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
@@ -289,3 +311,40 @@ inline void backend_run_idle_tasks(struct Backend_base *base) {
|
|
289
311
|
rb_gc_start();
|
290
312
|
rb_gc_disable();
|
291
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
|
+
}
|
@@ -6,13 +6,20 @@
|
|
6
6
|
#include "runqueue.h"
|
7
7
|
|
8
8
|
struct backend_stats {
|
9
|
-
int
|
10
|
-
int
|
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;
|
11
15
|
};
|
12
16
|
|
13
17
|
struct Backend_base {
|
14
18
|
runqueue_t runqueue;
|
15
19
|
unsigned int currently_polling;
|
20
|
+
unsigned int op_count;
|
21
|
+
unsigned int switch_count;
|
22
|
+
unsigned int poll_count;
|
16
23
|
unsigned int pending_count;
|
17
24
|
double idle_gc_period;
|
18
25
|
double idle_gc_last_time;
|
@@ -26,6 +33,7 @@ void backend_base_mark(struct Backend_base *base);
|
|
26
33
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base);
|
27
34
|
void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_base *base, VALUE fiber, VALUE value, int prioritize);
|
28
35
|
void backend_trace(struct Backend_base *base, int argc, VALUE *argv);
|
36
|
+
struct backend_stats backend_base_stats(struct Backend_base *base);
|
29
37
|
|
30
38
|
// tracing
|
31
39
|
#define SHOULD_TRACE(base) ((base)->trace_proc != Qnil)
|
@@ -59,6 +67,7 @@ VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
|
59
67
|
//////////////////////////////////////////////////////////////////////
|
60
68
|
//////////////////////////////////////////////////////////////////////
|
61
69
|
|
70
|
+
struct backend_stats backend_get_stats(VALUE self);
|
62
71
|
VALUE backend_await(struct Backend_base *backend);
|
63
72
|
VALUE backend_snooze();
|
64
73
|
|
@@ -91,7 +100,10 @@ VALUE backend_timeout_exception(VALUE exception);
|
|
91
100
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
92
101
|
VALUE Backend_timeout_ensure_safe(VALUE arg);
|
93
102
|
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
|
103
|
+
VALUE Backend_stats(VALUE self);
|
94
104
|
void backend_run_idle_tasks(struct Backend_base *base);
|
95
105
|
void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking);
|
96
106
|
|
107
|
+
void backend_setup_stats_symbols();
|
108
|
+
|
97
109
|
#endif /* BACKEND_COMMON_H */
|
@@ -191,6 +191,8 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
191
191
|
Backend_t *backend;
|
192
192
|
GetBackend(self, backend);
|
193
193
|
|
194
|
+
backend->base.poll_count++;
|
195
|
+
|
194
196
|
if (!is_blocking && backend->pending_sqes) {
|
195
197
|
backend->pending_sqes = 0;
|
196
198
|
io_uring_submit(&backend->ring);
|
@@ -234,14 +236,11 @@ inline VALUE Backend_switch_fiber(VALUE self) {
|
|
234
236
|
return backend_base_switch_fiber(self, &backend->base);
|
235
237
|
}
|
236
238
|
|
237
|
-
inline struct backend_stats
|
239
|
+
inline struct backend_stats backend_get_stats(VALUE self) {
|
238
240
|
Backend_t *backend;
|
239
241
|
GetBackend(self, backend);
|
240
242
|
|
241
|
-
return (
|
242
|
-
.scheduled_fibers = runqueue_len(&backend->base.runqueue),
|
243
|
-
.pending_ops = backend->base.pending_count
|
244
|
-
};
|
243
|
+
return backend_base_stats(&backend->base);
|
245
244
|
}
|
246
245
|
|
247
246
|
VALUE Backend_wakeup(VALUE self) {
|
@@ -279,6 +278,7 @@ int io_uring_backend_defer_submit_and_await(
|
|
279
278
|
{
|
280
279
|
VALUE switchpoint_result = Qnil;
|
281
280
|
|
281
|
+
backend->base.op_count++;
|
282
282
|
if (sqe) {
|
283
283
|
io_uring_sqe_set_data(sqe, ctx);
|
284
284
|
io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
|
@@ -1043,6 +1043,7 @@ VALUE Backend_timeout(int argc, VALUE *argv, VALUE self) {
|
|
1043
1043
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
1044
1044
|
io_uring_sqe_set_data(sqe, ctx);
|
1045
1045
|
io_uring_backend_defer_submit(backend);
|
1046
|
+
backend->base.op_count++;
|
1046
1047
|
|
1047
1048
|
struct Backend_timeout_ctx timeout_ctx = {backend, ctx};
|
1048
1049
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
@@ -1210,6 +1211,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1210
1211
|
sqe_count++;
|
1211
1212
|
}
|
1212
1213
|
|
1214
|
+
backend->base.op_count += sqe_count;
|
1213
1215
|
ctx->ref_count = sqe_count + 1;
|
1214
1216
|
io_uring_backend_defer_submit(backend);
|
1215
1217
|
resume_value = backend_await((struct Backend_base *)backend);
|
@@ -1346,6 +1348,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1346
1348
|
if (prefix != Qnil) {
|
1347
1349
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1348
1350
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, prefix);
|
1351
|
+
backend->base.op_count++;
|
1349
1352
|
}
|
1350
1353
|
|
1351
1354
|
while (1) {
|
@@ -1355,7 +1358,8 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1355
1358
|
|
1356
1359
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_SPLICE);
|
1357
1360
|
splice_chunks_prep_splice(ctx, sqe, src_fptr->fd, pipefd[1], maxlen);
|
1358
|
-
|
1361
|
+
backend->base.op_count++;
|
1362
|
+
|
1359
1363
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, &chunk_len, &switchpoint_result);
|
1360
1364
|
if (chunk_len == 0) break;
|
1361
1365
|
|
@@ -1367,15 +1371,18 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1367
1371
|
chunk_prefix_str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
1368
1372
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1369
1373
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, chunk_prefix_str);
|
1374
|
+
backend->base.op_count++;
|
1370
1375
|
}
|
1371
1376
|
|
1372
1377
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_SPLICE);
|
1373
1378
|
splice_chunks_prep_splice(ctx, sqe, pipefd[0], dest_fptr->fd, chunk_len);
|
1379
|
+
backend->base.op_count++;
|
1374
1380
|
|
1375
1381
|
if (chunk_postfix != Qnil) {
|
1376
1382
|
chunk_postfix_str = (TYPE(chunk_postfix) == T_STRING) ? chunk_postfix : rb_funcall(chunk_postfix, ID_call, 1, chunk_len_value);
|
1377
1383
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1378
1384
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, chunk_postfix_str);
|
1385
|
+
backend->base.op_count++;
|
1379
1386
|
}
|
1380
1387
|
|
1381
1388
|
RB_GC_GUARD(chunk_prefix_str);
|
@@ -1385,6 +1392,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1385
1392
|
if (postfix != Qnil) {
|
1386
1393
|
splice_chunks_get_sqe(backend, &ctx, &sqe, OP_WRITE);
|
1387
1394
|
splice_chunks_prep_write(ctx, sqe, dest_fptr->fd, postfix);
|
1395
|
+
backend->base.op_count++;
|
1388
1396
|
}
|
1389
1397
|
if (ctx) {
|
1390
1398
|
SPLICE_CHUNKS_AWAIT_OPS(backend, &ctx, 0, &switchpoint_result);
|
@@ -1430,6 +1438,7 @@ void Init_Backend() {
|
|
1430
1438
|
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
1431
1439
|
rb_define_method(cBackend, "trace", Backend_trace, -1);
|
1432
1440
|
rb_define_method(cBackend, "trace_proc=", Backend_trace_proc_set, 1);
|
1441
|
+
rb_define_method(cBackend, "stats", Backend_stats, 0);
|
1433
1442
|
|
1434
1443
|
rb_define_method(cBackend, "poll", Backend_poll, 1);
|
1435
1444
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
@@ -1469,6 +1478,8 @@ void Init_Backend() {
|
|
1469
1478
|
SYM_send = ID2SYM(rb_intern("send"));
|
1470
1479
|
SYM_splice = ID2SYM(rb_intern("splice"));
|
1471
1480
|
SYM_write = ID2SYM(rb_intern("write"));
|
1481
|
+
|
1482
|
+
backend_setup_stats_symbols();
|
1472
1483
|
}
|
1473
1484
|
|
1474
1485
|
#endif // POLYPHONY_BACKEND_LIBURING
|
@@ -164,6 +164,8 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
164
164
|
Backend_t *backend;
|
165
165
|
GetBackend(self, backend);
|
166
166
|
|
167
|
+
backend->base.poll_count++;
|
168
|
+
|
167
169
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
168
170
|
backend->base.currently_polling = 1;
|
169
171
|
ev_run(backend->ev_loop, blocking == Qtrue ? EVRUN_ONCE : EVRUN_NOWAIT);
|
@@ -211,14 +213,11 @@ VALUE Backend_wakeup(VALUE self) {
|
|
211
213
|
return Qnil;
|
212
214
|
}
|
213
215
|
|
214
|
-
inline struct backend_stats
|
216
|
+
inline struct backend_stats backend_get_stats(VALUE self) {
|
215
217
|
Backend_t *backend;
|
216
218
|
GetBackend(self, backend);
|
217
219
|
|
218
|
-
return (
|
219
|
-
.scheduled_fibers = runqueue_len(&backend->base.runqueue),
|
220
|
-
.pending_ops = backend->base.pending_count
|
221
|
-
};
|
220
|
+
return backend_base_stats(&backend->base);
|
222
221
|
}
|
223
222
|
|
224
223
|
struct libev_io {
|
@@ -289,6 +288,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
289
288
|
OBJ_TAINT(str);
|
290
289
|
|
291
290
|
while (1) {
|
291
|
+
backend->base.op_count++;
|
292
292
|
ssize_t n = read(fptr->fd, buf, len - total);
|
293
293
|
if (n < 0) {
|
294
294
|
int e = errno;
|
@@ -359,6 +359,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
359
359
|
watcher.fiber = Qnil;
|
360
360
|
|
361
361
|
while (1) {
|
362
|
+
backend->base.op_count++;
|
362
363
|
ssize_t n = read(fptr->fd, buf, len);
|
363
364
|
if (n < 0) {
|
364
365
|
int e = errno;
|
@@ -411,6 +412,7 @@ VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
|
|
411
412
|
watcher.fiber = Qnil;
|
412
413
|
|
413
414
|
while (1) {
|
415
|
+
backend->base.op_count++;
|
414
416
|
ssize_t n = read(fptr->fd, buf, len);
|
415
417
|
if (n < 0) {
|
416
418
|
int e = errno;
|
@@ -458,6 +460,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
458
460
|
watcher.fiber = Qnil;
|
459
461
|
|
460
462
|
while (left > 0) {
|
463
|
+
backend->base.op_count++;
|
461
464
|
ssize_t n = write(fptr->fd, buf, left);
|
462
465
|
if (n < 0) {
|
463
466
|
int e = errno;
|
@@ -517,6 +520,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
517
520
|
iov_ptr = iov;
|
518
521
|
|
519
522
|
while (1) {
|
523
|
+
backend->base.op_count++;
|
520
524
|
ssize_t n = writev(fptr->fd, iov_ptr, iov_count);
|
521
525
|
if (n < 0) {
|
522
526
|
int e = errno;
|
@@ -588,6 +592,7 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
588
592
|
io_verify_blocking_mode(fptr, server_socket, Qfalse);
|
589
593
|
watcher.fiber = Qnil;
|
590
594
|
while (1) {
|
595
|
+
backend->base.op_count++;
|
591
596
|
fd = accept(fptr->fd, &addr, &len);
|
592
597
|
if (fd < 0) {
|
593
598
|
int e = errno;
|
@@ -646,6 +651,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
646
651
|
watcher.fiber = Qnil;
|
647
652
|
|
648
653
|
while (1) {
|
654
|
+
backend->base.op_count++;
|
649
655
|
fd = accept(fptr->fd, &addr, &len);
|
650
656
|
if (fd < 0) {
|
651
657
|
int e = errno;
|
@@ -705,6 +711,7 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
705
711
|
addr.sin_addr.s_addr = inet_addr(host_buf);
|
706
712
|
addr.sin_port = htons(NUM2INT(port));
|
707
713
|
|
714
|
+
backend->base.op_count++;
|
708
715
|
int result = connect(fptr->fd, (struct sockaddr *)&addr, sizeof(addr));
|
709
716
|
if (result < 0) {
|
710
717
|
int e = errno;
|
@@ -745,6 +752,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
745
752
|
watcher.fiber = Qnil;
|
746
753
|
|
747
754
|
while (left > 0) {
|
755
|
+
backend->base.op_count++;
|
748
756
|
ssize_t n = send(fptr->fd, buf, left, flags_int);
|
749
757
|
if (n < 0) {
|
750
758
|
int e = errno;
|
@@ -852,6 +860,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
852
860
|
|
853
861
|
watcher.ctx.fiber = Qnil;
|
854
862
|
while (1) {
|
863
|
+
backend->base.op_count++;
|
855
864
|
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
856
865
|
if (len < 0) {
|
857
866
|
int e = errno;
|
@@ -903,6 +912,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
903
912
|
|
904
913
|
watcher.ctx.fiber = Qnil;
|
905
914
|
while (1) {
|
915
|
+
backend->base.op_count++;
|
906
916
|
len = splice(src_fptr->fd, 0, dest_fptr->fd, 0, NUM2INT(maxlen), 0);
|
907
917
|
if (len < 0) {
|
908
918
|
int e = errno;
|
@@ -962,6 +972,7 @@ VALUE Backend_fake_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
962
972
|
watcher.fiber = Qnil;
|
963
973
|
|
964
974
|
while (1) {
|
975
|
+
backend->base.op_count++;
|
965
976
|
ssize_t n = read(src_fptr->fd, buf, len);
|
966
977
|
if (n < 0) {
|
967
978
|
int e = errno;
|
@@ -977,6 +988,7 @@ VALUE Backend_fake_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
977
988
|
}
|
978
989
|
|
979
990
|
while (left > 0) {
|
991
|
+
backend->base.op_count++;
|
980
992
|
ssize_t n = write(dest_fptr->fd, buf, left);
|
981
993
|
if (n < 0) {
|
982
994
|
int e = errno;
|
@@ -1037,6 +1049,7 @@ VALUE Backend_fake_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen
|
|
1037
1049
|
while (1) {
|
1038
1050
|
char *ptr = buf;
|
1039
1051
|
while (1) {
|
1052
|
+
backend->base.op_count++;
|
1040
1053
|
ssize_t n = read(src_fptr->fd, ptr, len);
|
1041
1054
|
if (n < 0) {
|
1042
1055
|
int e = errno;
|
@@ -1054,6 +1067,7 @@ VALUE Backend_fake_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen
|
|
1054
1067
|
}
|
1055
1068
|
|
1056
1069
|
while (left > 0) {
|
1070
|
+
backend->base.op_count++;
|
1057
1071
|
ssize_t n = write(dest_fptr->fd, ptr, left);
|
1058
1072
|
if (n < 0) {
|
1059
1073
|
int e = errno;
|
@@ -1093,6 +1107,7 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
1093
1107
|
GetBackend(self, backend);
|
1094
1108
|
GetOpenFile(io, fptr);
|
1095
1109
|
|
1110
|
+
backend->base.op_count++;
|
1096
1111
|
return libev_wait_fd(backend, fptr->fd, events, 1);
|
1097
1112
|
}
|
1098
1113
|
|
@@ -1116,6 +1131,7 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
1116
1131
|
watcher.fiber = rb_fiber_current();
|
1117
1132
|
ev_timer_init(&watcher.timer, Backend_timer_callback, NUM2DBL(duration), 0.);
|
1118
1133
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
1134
|
+
backend->base.op_count++;
|
1119
1135
|
|
1120
1136
|
switchpoint_result = backend_await((struct Backend_base *)backend);
|
1121
1137
|
|
@@ -1145,6 +1161,7 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
1145
1161
|
VALUE switchpoint_result = Qnil;
|
1146
1162
|
ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
|
1147
1163
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
1164
|
+
backend->base.op_count++;
|
1148
1165
|
switchpoint_result = backend_await((struct Backend_base *)backend);
|
1149
1166
|
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
1150
1167
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
@@ -1196,6 +1213,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
1196
1213
|
watcher.resume_value = timeout;
|
1197
1214
|
ev_timer_init(&watcher.timer, Backend_timeout_callback, NUM2DBL(duration), 0.);
|
1198
1215
|
ev_timer_start(backend->ev_loop, &watcher.timer);
|
1216
|
+
backend->base.op_count++;
|
1199
1217
|
|
1200
1218
|
struct Backend_timeout_ctx timeout_ctx = {backend, &watcher};
|
1201
1219
|
result = rb_ensure(Backend_timeout_ensure_safe, Qnil, Backend_timeout_ensure, (VALUE)&timeout_ctx);
|
@@ -1218,6 +1236,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1218
1236
|
if (fd >= 0) {
|
1219
1237
|
Backend_t *backend;
|
1220
1238
|
GetBackend(self, backend);
|
1239
|
+
backend->base.op_count++;
|
1221
1240
|
|
1222
1241
|
VALUE resume_value = libev_wait_fd(backend, fd, EV_READ, 0);
|
1223
1242
|
close(fd);
|
@@ -1261,6 +1280,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1261
1280
|
watcher.fiber = rb_fiber_current();
|
1262
1281
|
ev_child_init(&watcher.child, Backend_child_callback, NUM2INT(pid), 0);
|
1263
1282
|
ev_child_start(backend->ev_loop, &watcher.child);
|
1283
|
+
backend->base.op_count++;
|
1264
1284
|
|
1265
1285
|
switchpoint_result = backend_await((struct Backend_base *)backend);
|
1266
1286
|
|
@@ -1283,6 +1303,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise) {
|
|
1283
1303
|
|
1284
1304
|
ev_async_init(&async, Backend_async_callback);
|
1285
1305
|
ev_async_start(backend->ev_loop, &async);
|
1306
|
+
backend->base.op_count++;
|
1286
1307
|
|
1287
1308
|
switchpoint_result = backend_await((struct Backend_base *)backend);
|
1288
1309
|
|
@@ -1346,6 +1367,7 @@ inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct lib
|
|
1346
1367
|
int len = RSTRING_LEN(str);
|
1347
1368
|
int left = len;
|
1348
1369
|
while (left > 0) {
|
1370
|
+
backend->base.op_count++;
|
1349
1371
|
ssize_t n = write(fd, buf, left);
|
1350
1372
|
if (n < 0) {
|
1351
1373
|
int err = errno;
|
@@ -1406,6 +1428,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1406
1428
|
int chunk_len;
|
1407
1429
|
// splice to pipe
|
1408
1430
|
while (1) {
|
1431
|
+
backend->base.op_count++;
|
1409
1432
|
chunk_len = splice(src_fptr->fd, 0, pipefd[1], 0, maxlen, 0);
|
1410
1433
|
if (chunk_len < 0) {
|
1411
1434
|
err = errno;
|
@@ -1431,6 +1454,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1431
1454
|
|
1432
1455
|
int left = chunk_len;
|
1433
1456
|
while (1) {
|
1457
|
+
backend->base.op_count++;
|
1434
1458
|
int n = splice(pipefd[0], 0, dest_fptr->fd, 0, left, 0);
|
1435
1459
|
if (n < 0) {
|
1436
1460
|
err = errno;
|
@@ -1503,6 +1527,7 @@ void Init_Backend() {
|
|
1503
1527
|
rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
|
1504
1528
|
rb_define_method(cBackend, "trace", Backend_trace, -1);
|
1505
1529
|
rb_define_method(cBackend, "trace_proc=", Backend_trace_proc_set, 1);
|
1530
|
+
rb_define_method(cBackend, "stats", Backend_stats, 0);
|
1506
1531
|
|
1507
1532
|
rb_define_method(cBackend, "poll", Backend_poll, 1);
|
1508
1533
|
rb_define_method(cBackend, "break", Backend_wakeup, 0);
|
@@ -1545,6 +1570,8 @@ void Init_Backend() {
|
|
1545
1570
|
SYM_send = ID2SYM(rb_intern("send"));
|
1546
1571
|
SYM_splice = ID2SYM(rb_intern("splice"));
|
1547
1572
|
SYM_write = ID2SYM(rb_intern("write"));
|
1573
|
+
|
1574
|
+
backend_setup_stats_symbols();
|
1548
1575
|
}
|
1549
1576
|
|
1550
1577
|
#endif // POLYPHONY_BACKEND_LIBEV
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -114,7 +114,6 @@ VALUE Backend_wakeup(VALUE self);
|
|
114
114
|
VALUE Backend_run_idle_tasks(VALUE self);
|
115
115
|
VALUE Backend_switch_fiber(VALUE self);
|
116
116
|
void Backend_schedule_fiber(VALUE thread, VALUE self, VALUE fiber, VALUE value, int prioritize);
|
117
|
-
struct backend_stats Backend_stats(VALUE self);
|
118
117
|
void Backend_unschedule_fiber(VALUE self, VALUE fiber);
|
119
118
|
|
120
119
|
VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
|
data/ext/polyphony/runqueue.c
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
inline void runqueue_initialize(runqueue_t *runqueue) {
|
5
5
|
runqueue_ring_buffer_init(&runqueue->entries);
|
6
6
|
runqueue->high_watermark = 0;
|
7
|
-
runqueue->switch_count = 0;
|
8
7
|
}
|
9
8
|
|
10
9
|
inline void runqueue_finalize(runqueue_t *runqueue) {
|
@@ -30,12 +29,7 @@ inline void runqueue_unshift(runqueue_t *runqueue, VALUE fiber, VALUE value, int
|
|
30
29
|
}
|
31
30
|
|
32
31
|
inline runqueue_entry runqueue_shift(runqueue_t *runqueue) {
|
33
|
-
|
34
|
-
if (entry.fiber == Qnil)
|
35
|
-
runqueue->high_watermark = 0;
|
36
|
-
else
|
37
|
-
runqueue->switch_count += 1;
|
38
|
-
return entry;
|
32
|
+
return runqueue_ring_buffer_shift(&runqueue->entries);
|
39
33
|
}
|
40
34
|
|
41
35
|
inline void runqueue_delete(runqueue_t *runqueue, VALUE fiber) {
|
@@ -54,15 +48,12 @@ inline long runqueue_len(runqueue_t *runqueue) {
|
|
54
48
|
return runqueue->entries.count;
|
55
49
|
}
|
56
50
|
|
57
|
-
inline
|
58
|
-
|
51
|
+
inline long runqueue_max_len(runqueue_t *runqueue) {
|
52
|
+
unsigned int max_len = runqueue->high_watermark;
|
53
|
+
runqueue->high_watermark = 0;
|
54
|
+
return max_len;
|
59
55
|
}
|
60
56
|
|
61
|
-
|
62
|
-
|
63
|
-
inline int runqueue_should_poll_nonblocking(runqueue_t *runqueue) {
|
64
|
-
if (runqueue->switch_count < ANTI_STARVE_SWITCH_COUNT_THRESHOLD) return 0;
|
65
|
-
|
66
|
-
runqueue->switch_count = 0;
|
67
|
-
return 1;
|
57
|
+
inline int runqueue_empty_p(runqueue_t *runqueue) {
|
58
|
+
return (runqueue->entries.count == 0);
|
68
59
|
}
|
data/ext/polyphony/runqueue.h
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
typedef struct runqueue {
|
8
8
|
runqueue_ring_buffer entries;
|
9
9
|
unsigned int high_watermark;
|
10
|
-
unsigned int switch_count;
|
11
10
|
} runqueue_t;
|
12
11
|
|
13
12
|
void runqueue_initialize(runqueue_t *runqueue);
|
@@ -21,7 +20,7 @@ void runqueue_delete(runqueue_t *runqueue, VALUE fiber);
|
|
21
20
|
int runqueue_index_of(runqueue_t *runqueue, VALUE fiber);
|
22
21
|
void runqueue_clear(runqueue_t *runqueue);
|
23
22
|
long runqueue_len(runqueue_t *runqueue);
|
23
|
+
long runqueue_max_len(runqueue_t *runqueue);
|
24
24
|
int runqueue_empty_p(runqueue_t *runqueue);
|
25
|
-
int runqueue_should_poll_nonblocking(runqueue_t *runqueue);
|
26
25
|
|
27
26
|
#endif /* RUNQUEUE_H */
|
data/ext/polyphony/thread.c
CHANGED
@@ -13,18 +13,6 @@ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
|
|
13
13
|
return self;
|
14
14
|
}
|
15
15
|
|
16
|
-
static VALUE SYM_scheduled_fibers;
|
17
|
-
static VALUE SYM_pending_watchers;
|
18
|
-
|
19
|
-
static VALUE Thread_fiber_scheduling_stats(VALUE self) {
|
20
|
-
struct backend_stats backend_stats = Backend_stats(rb_ivar_get(self, ID_ivar_backend));
|
21
|
-
|
22
|
-
VALUE stats = rb_hash_new();
|
23
|
-
rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(backend_stats.scheduled_fibers));
|
24
|
-
rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(backend_stats.pending_ops));
|
25
|
-
return stats;
|
26
|
-
}
|
27
|
-
|
28
16
|
inline void schedule_fiber(VALUE self, VALUE fiber, VALUE value, int prioritize) {
|
29
17
|
Backend_schedule_fiber(self, rb_ivar_get(self, ID_ivar_backend), fiber, value, prioritize);
|
30
18
|
}
|
@@ -72,7 +60,6 @@ VALUE Thread_class_backend(VALUE _self) {
|
|
72
60
|
|
73
61
|
void Init_Thread() {
|
74
62
|
rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
|
75
|
-
rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
|
76
63
|
rb_define_method(rb_cThread, "schedule_and_wakeup", Thread_fiber_schedule_and_wakeup, 2);
|
77
64
|
|
78
65
|
rb_define_method(rb_cThread, "schedule_fiber", Thread_schedule_fiber, 2);
|
@@ -91,9 +78,4 @@ void Init_Thread() {
|
|
91
78
|
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
92
79
|
ID_ivar_terminated = rb_intern("@terminated");
|
93
80
|
ID_stop = rb_intern("stop");
|
94
|
-
|
95
|
-
SYM_scheduled_fibers = ID2SYM(rb_intern("scheduled_fibers"));
|
96
|
-
SYM_pending_watchers = ID2SYM(rb_intern("pending_watchers"));
|
97
|
-
rb_global_variable(&SYM_scheduled_fibers);
|
98
|
-
rb_global_variable(&SYM_pending_watchers);
|
99
81
|
}
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.61'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -419,7 +419,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
419
419
|
- !ruby/object:Gem::Version
|
420
420
|
version: '0'
|
421
421
|
requirements: []
|
422
|
-
rubygems_version: 3.1.
|
422
|
+
rubygems_version: 3.1.6
|
423
423
|
signing_key:
|
424
424
|
specification_version: 4
|
425
425
|
summary: Fine grained concurrency for Ruby
|