polyphony 0.57.0 → 0.58
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 +5 -0
- data/Gemfile.lock +1 -1
- data/ext/polyphony/backend_common.c +11 -0
- data/ext/polyphony/backend_common.h +3 -0
- data/ext/polyphony/backend_io_uring.c +17 -7
- data/ext/polyphony/backend_io_uring_context.c +2 -3
- data/ext/polyphony/backend_libev.c +17 -6
- data/lib/polyphony/extensions/thread.rb +8 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +29 -0
- data/test/test_thread.rb +52 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8002b8c0e03afa8e915b5ed67d64c1fc288a5fa220dfb2c32d3966a78046eee
|
4
|
+
data.tar.gz: c3a46eeae1f048f4adee9d3130f5dd3593936e843c1874d928f742d1fa83053f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6681155761daee35b73c9674e69aa505786e576814db0c909028cb576d8609f99bccc79f80b7d06d90c7658747bc2589c9837d3bdb3419782147e573d39f278
|
7
|
+
data.tar.gz: 90197a8db54405ca37492a54a20adf00c85f142af606cad26ad823161825ccf6bd9a414adcbbf3e27eaf93eea1d94a7cbc50a2fb5982ee4ce48969d4378400cd
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -5,6 +5,14 @@
|
|
5
5
|
#include "polyphony.h"
|
6
6
|
#include "backend_common.h"
|
7
7
|
|
8
|
+
inline void initialize_backend_base(struct Backend_base *base) {
|
9
|
+
base->currently_polling = 0;
|
10
|
+
base->pending_count = 0;
|
11
|
+
base->idle_gc_period = 0;
|
12
|
+
base->idle_gc_last_time = 0;
|
13
|
+
base->idle_block = Qnil;
|
14
|
+
}
|
15
|
+
|
8
16
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
9
17
|
#ifndef __NR_pidfd_open
|
10
18
|
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
@@ -174,6 +182,9 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
|
174
182
|
}
|
175
183
|
|
176
184
|
inline void backend_run_idle_tasks(struct Backend_base *base) {
|
185
|
+
if (base->idle_block != Qnil)
|
186
|
+
rb_funcall(base->idle_block, ID_call, 0);
|
187
|
+
|
177
188
|
if (base->idle_gc_period == 0) return;
|
178
189
|
|
179
190
|
double now = current_time();
|
@@ -9,8 +9,11 @@ struct Backend_base {
|
|
9
9
|
unsigned int pending_count;
|
10
10
|
double idle_gc_period;
|
11
11
|
double idle_gc_last_time;
|
12
|
+
VALUE idle_block;
|
12
13
|
};
|
13
14
|
|
15
|
+
void initialize_backend_base(struct Backend_base *base);
|
16
|
+
|
14
17
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
15
18
|
int pidfd_open(pid_t pid, unsigned int flags);
|
16
19
|
#endif
|
@@ -42,13 +42,19 @@ typedef struct Backend_t {
|
|
42
42
|
int event_fd;
|
43
43
|
} Backend_t;
|
44
44
|
|
45
|
+
static void Backend_mark(void *ptr) {
|
46
|
+
Backend_t *backend = ptr;
|
47
|
+
if (backend->base.idle_block != Qnil)
|
48
|
+
rb_gc_mark(backend->base.idle_block);
|
49
|
+
}
|
50
|
+
|
45
51
|
static size_t Backend_size(const void *ptr) {
|
46
52
|
return sizeof(Backend_t);
|
47
53
|
}
|
48
54
|
|
49
55
|
static const rb_data_type_t Backend_type = {
|
50
56
|
"IOUringBackend",
|
51
|
-
{
|
57
|
+
{Backend_mark, 0, Backend_size,},
|
52
58
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
53
59
|
};
|
54
60
|
|
@@ -65,11 +71,7 @@ static VALUE Backend_initialize(VALUE self) {
|
|
65
71
|
Backend_t *backend;
|
66
72
|
GetBackend(self, backend);
|
67
73
|
|
68
|
-
backend->base
|
69
|
-
backend->base.pending_count = 0;
|
70
|
-
backend->base.idle_gc_period = 0;
|
71
|
-
backend->base.idle_gc_last_time = 0;
|
72
|
-
|
74
|
+
initialize_backend_base(&backend->base);
|
73
75
|
backend->pending_sqes = 0;
|
74
76
|
backend->prepared_limit = 2048;
|
75
77
|
|
@@ -134,6 +136,7 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
|
|
134
136
|
op_context_t *ctx = io_uring_cqe_get_data(cqe);
|
135
137
|
if (!ctx) return;
|
136
138
|
|
139
|
+
// printf("cqe ctx %p id: %d result: %d (%s, ref_count: %d)\n", ctx, ctx->id, cqe->res, op_type_to_str(ctx->type), ctx->ref_count);
|
137
140
|
ctx->result = cqe->res;
|
138
141
|
if (ctx->ref_count == 2 && ctx->result != -ECANCELED && ctx->fiber)
|
139
142
|
Fiber_make_runnable(ctx->fiber, ctx->resume_value);
|
@@ -908,7 +911,6 @@ int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duratio
|
|
908
911
|
|
909
912
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
910
913
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
911
|
-
|
912
914
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
913
915
|
return context_store_release(&backend->store, ctx);
|
914
916
|
}
|
@@ -1185,6 +1187,13 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
|
1185
1187
|
return self;
|
1186
1188
|
}
|
1187
1189
|
|
1190
|
+
VALUE Backend_idle_block_set(VALUE self, VALUE block) {
|
1191
|
+
Backend_t *backend;
|
1192
|
+
GetBackend(self, backend);
|
1193
|
+
backend->base.idle_block = block;
|
1194
|
+
return self;
|
1195
|
+
}
|
1196
|
+
|
1188
1197
|
inline VALUE Backend_run_idle_tasks(VALUE self) {
|
1189
1198
|
Backend_t *backend;
|
1190
1199
|
GetBackend(self, backend);
|
@@ -1359,6 +1368,7 @@ void Init_Backend() {
|
|
1359
1368
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1360
1369
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1361
1370
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1371
|
+
rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
|
1362
1372
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1363
1373
|
|
1364
1374
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
@@ -37,8 +37,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
37
37
|
ctx = malloc(sizeof(op_context_t));
|
38
38
|
}
|
39
39
|
ctx->id = (++store->last_id);
|
40
|
-
// printf("acquire %d (%s)\n", ctx->id, op_type_to_str(type));
|
41
|
-
|
40
|
+
// printf("acquire %p %d (%s)\n", ctx, ctx->id, op_type_to_str(type));
|
42
41
|
ctx->prev = NULL;
|
43
42
|
ctx->next = store->taken;
|
44
43
|
if (store->taken) store->taken->prev = ctx;
|
@@ -55,7 +54,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
55
54
|
|
56
55
|
// returns true if ctx was released
|
57
56
|
inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
58
|
-
// printf("release %d (%s, ref_count: %d)\n", ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
57
|
+
// printf("release %p %d (%s, ref_count: %d)\n", ctx, ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
|
59
58
|
|
60
59
|
assert(ctx->ref_count);
|
61
60
|
|
@@ -73,13 +73,19 @@ typedef struct Backend_t {
|
|
73
73
|
struct ev_async break_async;
|
74
74
|
} Backend_t;
|
75
75
|
|
76
|
+
static void Backend_mark(void *ptr) {
|
77
|
+
Backend_t *backend = ptr;
|
78
|
+
if (backend->base.idle_block != Qnil)
|
79
|
+
rb_gc_mark(backend->base.idle_block);
|
80
|
+
}
|
81
|
+
|
76
82
|
static size_t Backend_size(const void *ptr) {
|
77
83
|
return sizeof(Backend_t);
|
78
84
|
}
|
79
85
|
|
80
86
|
static const rb_data_type_t Backend_type = {
|
81
87
|
"LibevBackend",
|
82
|
-
{
|
88
|
+
{Backend_mark, 0, Backend_size,},
|
83
89
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
84
90
|
};
|
85
91
|
|
@@ -110,6 +116,8 @@ static VALUE Backend_initialize(VALUE self) {
|
|
110
116
|
Backend_t *backend;
|
111
117
|
|
112
118
|
GetBackend(self, backend);
|
119
|
+
|
120
|
+
initialize_backend_base(&backend->base);
|
113
121
|
backend->ev_loop = libev_new_loop();
|
114
122
|
|
115
123
|
// start async watcher used for breaking a poll op (from another thread)
|
@@ -119,11 +127,6 @@ static VALUE Backend_initialize(VALUE self) {
|
|
119
127
|
// block when no other watcher is active
|
120
128
|
ev_unref(backend->ev_loop);
|
121
129
|
|
122
|
-
backend->base.currently_polling = 0;
|
123
|
-
backend->base.pending_count = 0;
|
124
|
-
backend->base.idle_gc_period = 0;
|
125
|
-
backend->base.idle_gc_last_time = 0;
|
126
|
-
|
127
130
|
return Qnil;
|
128
131
|
}
|
129
132
|
|
@@ -1290,6 +1293,13 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
|
|
1290
1293
|
return self;
|
1291
1294
|
}
|
1292
1295
|
|
1296
|
+
VALUE Backend_idle_block_set(VALUE self, VALUE block) {
|
1297
|
+
Backend_t *backend;
|
1298
|
+
GetBackend(self, backend);
|
1299
|
+
backend->base.idle_block = block;
|
1300
|
+
return self;
|
1301
|
+
}
|
1302
|
+
|
1293
1303
|
inline VALUE Backend_run_idle_tasks(VALUE self) {
|
1294
1304
|
Backend_t *backend;
|
1295
1305
|
GetBackend(self, backend);
|
@@ -1448,6 +1458,7 @@ void Init_Backend() {
|
|
1448
1458
|
rb_define_method(cBackend, "kind", Backend_kind, 0);
|
1449
1459
|
rb_define_method(cBackend, "chain", Backend_chain, -1);
|
1450
1460
|
rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
|
1461
|
+
rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
|
1451
1462
|
rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
|
1452
1463
|
|
1453
1464
|
rb_define_method(cBackend, "accept", Backend_accept, 2);
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -340,9 +340,38 @@ class BackendTest < MiniTest::Test
|
|
340
340
|
# GC period.
|
341
341
|
sleep 0.05
|
342
342
|
assert_equal count + 1, GC.count
|
343
|
+
|
344
|
+
@backend.idle_gc_period = 0
|
345
|
+
count = GC.count
|
346
|
+
sleep 0.001
|
347
|
+
sleep 0.002
|
348
|
+
sleep 0.003
|
349
|
+
assert_equal count, GC.count
|
343
350
|
ensure
|
344
351
|
GC.enable
|
345
352
|
end
|
353
|
+
|
354
|
+
def test_idle_block
|
355
|
+
counter = 0
|
356
|
+
|
357
|
+
@backend.idle_block = proc { counter += 1 }
|
358
|
+
|
359
|
+
3.times { snooze }
|
360
|
+
assert_equal 0, counter
|
361
|
+
|
362
|
+
sleep 0.01
|
363
|
+
assert_equal 1, counter
|
364
|
+
sleep 0.01
|
365
|
+
assert_equal 2, counter
|
366
|
+
|
367
|
+
assert_equal 2, counter
|
368
|
+
3.times { snooze }
|
369
|
+
assert_equal 2, counter
|
370
|
+
|
371
|
+
@backend.idle_block = nil
|
372
|
+
sleep 0.01
|
373
|
+
assert_equal 2, counter
|
374
|
+
end
|
346
375
|
end
|
347
376
|
|
348
377
|
class BackendChainTest < MiniTest::Test
|
data/test/test_thread.rb
CHANGED
@@ -171,4 +171,56 @@ class ThreadTest < MiniTest::Test
|
|
171
171
|
t&.kill
|
172
172
|
t&.join
|
173
173
|
end
|
174
|
+
|
175
|
+
def test_idle_gc
|
176
|
+
GC.disable
|
177
|
+
|
178
|
+
count = GC.count
|
179
|
+
snooze
|
180
|
+
assert_equal count, GC.count
|
181
|
+
sleep 0.01
|
182
|
+
assert_equal count, GC.count
|
183
|
+
|
184
|
+
Thread.current.idle_gc_period = 0.1
|
185
|
+
snooze
|
186
|
+
assert_equal count, GC.count
|
187
|
+
sleep 0.05
|
188
|
+
assert_equal count, GC.count
|
189
|
+
# The idle tasks are ran at most once per fiber switch, before the backend
|
190
|
+
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
191
|
+
# only 0.05s have passed since the gc period was set.
|
192
|
+
sleep 0.07
|
193
|
+
assert_equal count, GC.count
|
194
|
+
# Upon the third sleep the GC should be triggered, at 0.12s post setting the
|
195
|
+
# GC period.
|
196
|
+
sleep 0.05
|
197
|
+
assert_equal count + 1, GC.count
|
198
|
+
|
199
|
+
Thread.current.idle_gc_period = 0
|
200
|
+
count = GC.count
|
201
|
+
sleep 0.001
|
202
|
+
sleep 0.002
|
203
|
+
sleep 0.003
|
204
|
+
assert_equal count, GC.count
|
205
|
+
ensure
|
206
|
+
GC.enable
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_on_idle
|
210
|
+
counter = 0
|
211
|
+
|
212
|
+
Thread.current.on_idle { counter += 1 }
|
213
|
+
|
214
|
+
3.times { snooze }
|
215
|
+
assert_equal 0, counter
|
216
|
+
|
217
|
+
sleep 0.01
|
218
|
+
assert_equal 1, counter
|
219
|
+
sleep 0.01
|
220
|
+
assert_equal 2, counter
|
221
|
+
|
222
|
+
assert_equal 2, counter
|
223
|
+
3.times { snooze }
|
224
|
+
assert_equal 2, counter
|
225
|
+
end
|
174
226
|
end
|
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.58'
|
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-06-
|
11
|
+
date: 2021-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|