polyphony 0.55.0 → 0.59.1
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 +1 -1
- data/examples/core/idle_gc.rb +21 -0
- data/examples/io/pipe.rb +11 -0
- data/examples/io/splice_chunks.rb +29 -0
- data/ext/polyphony/backend_common.c +288 -0
- data/ext/polyphony/backend_common.h +49 -130
- data/ext/polyphony/backend_io_uring.c +263 -54
- data/ext/polyphony/backend_io_uring_context.c +2 -3
- data/ext/polyphony/backend_libev.c +466 -84
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/polyphony.c +17 -22
- data/ext/polyphony/polyphony.h +8 -16
- data/ext/polyphony/polyphony_ext.c +0 -4
- data/ext/polyphony/runqueue.c +17 -82
- data/ext/polyphony/runqueue.h +27 -0
- data/ext/polyphony/thread.c +10 -94
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/extensions/fiber.rb +2 -2
- data/lib/polyphony/extensions/thread.rb +8 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/test_backend.rb +91 -0
- data/test/test_thread.rb +57 -11
- data/test/test_timer.rb +7 -7
- data/test/test_trace.rb +27 -49
- metadata +7 -4
- data/ext/polyphony/tracing.c +0 -11
- data/lib/polyphony/adapters/trace.rb +0 -138
data/lib/polyphony/core/timer.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
module Polyphony
|
4
4
|
# Implements a common timer for running multiple timeouts
|
5
5
|
class Timer
|
6
|
-
def initialize(resolution:)
|
7
|
-
@fiber = spin_loop(interval: resolution) { update }
|
6
|
+
def initialize(tag = nil, resolution:)
|
7
|
+
@fiber = spin_loop(tag, interval: resolution) { update }
|
8
8
|
@timeouts = {}
|
9
9
|
end
|
10
10
|
|
@@ -262,7 +262,7 @@ module Polyphony
|
|
262
262
|
@parent = parent
|
263
263
|
@caller = caller
|
264
264
|
@block = block
|
265
|
-
|
265
|
+
Thread.backend.trace(:fiber_create, self)
|
266
266
|
schedule
|
267
267
|
end
|
268
268
|
|
@@ -311,7 +311,7 @@ module Polyphony
|
|
311
311
|
|
312
312
|
def finalize(result, uncaught_exception = false)
|
313
313
|
result, uncaught_exception = finalize_children(result, uncaught_exception)
|
314
|
-
|
314
|
+
Thread.backend.trace(:fiber_terminate, self, result)
|
315
315
|
@result = result
|
316
316
|
@running = false
|
317
317
|
inform_dependants(result, uncaught_exception)
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -281,6 +281,97 @@ class BackendTest < MiniTest::Test
|
|
281
281
|
f.await
|
282
282
|
end
|
283
283
|
end
|
284
|
+
|
285
|
+
|
286
|
+
def test_splice_chunks
|
287
|
+
body = 'abcd' * 250
|
288
|
+
chunk_size = 750
|
289
|
+
|
290
|
+
buf = +''
|
291
|
+
r, w = IO.pipe
|
292
|
+
reader = spin do
|
293
|
+
r.read_loop { |data| buf << data }
|
294
|
+
end
|
295
|
+
|
296
|
+
i, o = IO.pipe
|
297
|
+
writer = spin do
|
298
|
+
o << body
|
299
|
+
o.close
|
300
|
+
end
|
301
|
+
Thread.current.backend.splice_chunks(
|
302
|
+
i,
|
303
|
+
w,
|
304
|
+
"Content-Type: foo\r\n\r\n",
|
305
|
+
"0\r\n\r\n",
|
306
|
+
->(len) { "#{len.to_s(16)}\r\n" },
|
307
|
+
"\r\n",
|
308
|
+
chunk_size
|
309
|
+
)
|
310
|
+
w.close
|
311
|
+
reader.await
|
312
|
+
|
313
|
+
expected = "Content-Type: foo\r\n\r\n#{750.to_s(16)}\r\n#{body[0..749]}\r\n#{250.to_s(16)}\r\n#{body[750..999]}\r\n0\r\n\r\n"
|
314
|
+
assert_equal expected, buf
|
315
|
+
ensure
|
316
|
+
o.close
|
317
|
+
w.close
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_idle_gc
|
321
|
+
GC.disable
|
322
|
+
|
323
|
+
count = GC.count
|
324
|
+
snooze
|
325
|
+
assert_equal count, GC.count
|
326
|
+
sleep 0.01
|
327
|
+
assert_equal count, GC.count
|
328
|
+
|
329
|
+
@backend.idle_gc_period = 0.1
|
330
|
+
snooze
|
331
|
+
assert_equal count, GC.count
|
332
|
+
sleep 0.05
|
333
|
+
assert_equal count, GC.count
|
334
|
+
# The idle tasks are ran at most once per fiber switch, before the backend
|
335
|
+
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
336
|
+
# only 0.05s have passed since the gc period was set.
|
337
|
+
sleep 0.07
|
338
|
+
assert_equal count, GC.count
|
339
|
+
# Upon the third sleep the GC should be triggered, at 0.12s post setting the
|
340
|
+
# GC period.
|
341
|
+
sleep 0.05
|
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
|
350
|
+
ensure
|
351
|
+
GC.enable
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_idle_proc
|
355
|
+
counter = 0
|
356
|
+
|
357
|
+
@backend.idle_proc = 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_proc = nil
|
372
|
+
sleep 0.01
|
373
|
+
assert_equal 2, counter
|
374
|
+
end
|
284
375
|
end
|
285
376
|
|
286
377
|
class BackendChainTest < MiniTest::Test
|
data/test/test_thread.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
|
-
require 'polyphony/adapters/trace'
|
5
4
|
|
6
5
|
class ThreadTest < MiniTest::Test
|
7
6
|
def test_thread_spin
|
@@ -130,18 +129,13 @@ class ThreadTest < MiniTest::Test
|
|
130
129
|
|
131
130
|
def test_that_suspend_returns_immediately_if_no_watchers
|
132
131
|
records = []
|
133
|
-
|
134
|
-
records << r if r[:event] =~ /^fiber_/
|
135
|
-
end
|
136
|
-
t.enable
|
137
|
-
Polyphony.trace(true)
|
138
|
-
|
132
|
+
Thread.backend.trace_proc = proc {|*r| records << r }
|
139
133
|
suspend
|
140
|
-
|
141
|
-
|
134
|
+
assert_equal [
|
135
|
+
[:fiber_switchpoint, Fiber.current]
|
136
|
+
], records
|
142
137
|
ensure
|
143
|
-
|
144
|
-
Polyphony.trace(false)
|
138
|
+
Thread.backend.trace_proc = nil
|
145
139
|
end
|
146
140
|
|
147
141
|
def test_thread_child_fiber_termination
|
@@ -171,4 +165,56 @@ class ThreadTest < MiniTest::Test
|
|
171
165
|
t&.kill
|
172
166
|
t&.join
|
173
167
|
end
|
168
|
+
|
169
|
+
def test_idle_gc
|
170
|
+
GC.disable
|
171
|
+
|
172
|
+
count = GC.count
|
173
|
+
snooze
|
174
|
+
assert_equal count, GC.count
|
175
|
+
sleep 0.01
|
176
|
+
assert_equal count, GC.count
|
177
|
+
|
178
|
+
Thread.current.idle_gc_period = 0.1
|
179
|
+
snooze
|
180
|
+
assert_equal count, GC.count
|
181
|
+
sleep 0.05
|
182
|
+
assert_equal count, GC.count
|
183
|
+
# The idle tasks are ran at most once per fiber switch, before the backend
|
184
|
+
# is polled. Therefore, the second sleep will not have triggered a GC, since
|
185
|
+
# only 0.05s have passed since the gc period was set.
|
186
|
+
sleep 0.07
|
187
|
+
assert_equal count, GC.count
|
188
|
+
# Upon the third sleep the GC should be triggered, at 0.12s post setting the
|
189
|
+
# GC period.
|
190
|
+
sleep 0.05
|
191
|
+
assert_equal count + 1, GC.count
|
192
|
+
|
193
|
+
Thread.current.idle_gc_period = 0
|
194
|
+
count = GC.count
|
195
|
+
sleep 0.001
|
196
|
+
sleep 0.002
|
197
|
+
sleep 0.003
|
198
|
+
assert_equal count, GC.count
|
199
|
+
ensure
|
200
|
+
GC.enable
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_on_idle
|
204
|
+
counter = 0
|
205
|
+
|
206
|
+
Thread.current.on_idle { counter += 1 }
|
207
|
+
|
208
|
+
3.times { snooze }
|
209
|
+
assert_equal 0, counter
|
210
|
+
|
211
|
+
sleep 0.01
|
212
|
+
assert_equal 1, counter
|
213
|
+
sleep 0.01
|
214
|
+
assert_equal 2, counter
|
215
|
+
|
216
|
+
assert_equal 2, counter
|
217
|
+
3.times { snooze }
|
218
|
+
assert_equal 2, counter
|
219
|
+
end
|
174
220
|
end
|
data/test/test_timer.rb
CHANGED
@@ -48,7 +48,7 @@ class TimerMoveOnAfterTest < MiniTest::Test
|
|
48
48
|
t1 = Time.now
|
49
49
|
|
50
50
|
assert_nil v
|
51
|
-
assert_in_range 0.015..0.
|
51
|
+
assert_in_range 0.015..0.04, t1 - t0
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -76,17 +76,17 @@ class TimerCancelAfterTest < MiniTest::Test
|
|
76
76
|
|
77
77
|
def test_timer_cancel_after_with_reset
|
78
78
|
buf = []
|
79
|
-
@timer.cancel_after(0.
|
80
|
-
sleep 0.
|
79
|
+
@timer.cancel_after(0.13) do
|
80
|
+
sleep 0.05
|
81
81
|
buf << 1
|
82
82
|
@timer.reset
|
83
|
-
sleep 0.
|
83
|
+
sleep 0.05
|
84
84
|
buf << 2
|
85
85
|
@timer.reset
|
86
|
-
sleep 0.
|
86
|
+
sleep 0.05
|
87
87
|
buf << 3
|
88
88
|
@timer.reset
|
89
|
-
sleep 0.
|
89
|
+
sleep 0.05
|
90
90
|
buf << 4
|
91
91
|
end
|
92
92
|
assert_equal [1, 2, 3, 4], buf
|
@@ -158,6 +158,6 @@ class TimerMiscTest < MiniTest::Test
|
|
158
158
|
end
|
159
159
|
sleep 0.05
|
160
160
|
f.stop
|
161
|
-
assert_in_range
|
161
|
+
assert_in_range 3..7, buffer.size
|
162
162
|
end
|
163
163
|
end
|
data/test/test_trace.rb
CHANGED
@@ -1,70 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
|
-
require 'polyphony/adapters/trace'
|
5
4
|
|
6
5
|
class TraceTest < MiniTest::Test
|
7
|
-
def test_tracing_disabled
|
8
|
-
records = []
|
9
|
-
t = Polyphony::Trace.new { |r| records << r if r[:event] =~ /^fiber_/ }
|
10
|
-
t.enable
|
11
|
-
snooze
|
12
|
-
assert_equal 0, records.size
|
13
|
-
ensure
|
14
|
-
t&.disable
|
15
|
-
Polyphony.trace(nil)
|
16
|
-
end
|
17
|
-
|
18
6
|
def test_tracing_enabled
|
19
|
-
|
20
|
-
|
21
|
-
Polyphony.trace(true)
|
22
|
-
t.enable
|
7
|
+
events = []
|
8
|
+
Thread.backend.trace_proc = proc { |*e| events << e }
|
23
9
|
snooze
|
24
|
-
t.disable
|
25
10
|
|
26
|
-
assert_equal
|
27
|
-
|
28
|
-
|
29
|
-
|
11
|
+
assert_equal [
|
12
|
+
[:fiber_schedule, Fiber.current, nil],
|
13
|
+
[:fiber_switchpoint, Fiber.current],
|
14
|
+
[:fiber_run, Fiber.current, nil]
|
15
|
+
], events
|
30
16
|
ensure
|
31
|
-
|
32
|
-
Polyphony.trace(nil)
|
17
|
+
Thread.backend.trace_proc = nil
|
33
18
|
end
|
34
19
|
|
35
20
|
def test_2_fiber_trace
|
36
|
-
|
37
|
-
|
38
|
-
t = Polyphony::Trace.new(:fiber_all) do |r|
|
39
|
-
records << r if Thread.current == thread && r[:event] =~ /^fiber_/
|
40
|
-
end
|
41
|
-
t.enable
|
42
|
-
Polyphony.trace(true)
|
21
|
+
events = []
|
22
|
+
Thread.backend.trace_proc = proc { |*e| events << e }
|
43
23
|
|
44
|
-
f = spin { sleep 0 }
|
24
|
+
f = spin { sleep 0; :byebye }
|
45
25
|
suspend
|
46
26
|
sleep 0
|
47
27
|
|
48
|
-
events = records.map { |r| [r[:fiber] == f ? :f : :current, r[:event]] }
|
49
28
|
assert_equal [
|
50
|
-
[:
|
51
|
-
[:f,
|
52
|
-
[:
|
53
|
-
[:f,
|
54
|
-
[:
|
55
|
-
[:
|
56
|
-
[:f,
|
57
|
-
[:
|
58
|
-
[:f,
|
59
|
-
[:f, :
|
60
|
-
[:
|
61
|
-
[:
|
62
|
-
[:current,
|
63
|
-
[:
|
64
|
-
[:current,
|
29
|
+
[:fiber_create, f],
|
30
|
+
[:fiber_schedule, f, nil],
|
31
|
+
[:fiber_switchpoint, Fiber.current],
|
32
|
+
[:fiber_run, f, nil],
|
33
|
+
[:fiber_switchpoint, f],
|
34
|
+
[:fiber_event_poll_enter, f],
|
35
|
+
[:fiber_schedule, f, nil],
|
36
|
+
[:fiber_event_poll_leave, f],
|
37
|
+
[:fiber_run, f, nil],
|
38
|
+
[:fiber_terminate, f, :byebye],
|
39
|
+
[:fiber_switchpoint, Fiber.current],
|
40
|
+
[:fiber_event_poll_enter, Fiber.current],
|
41
|
+
[:fiber_schedule, Fiber.current, nil],
|
42
|
+
[:fiber_event_poll_leave, Fiber.current],
|
43
|
+
[:fiber_run, Fiber.current, nil]
|
65
44
|
], events
|
66
45
|
ensure
|
67
|
-
|
68
|
-
Polyphony.trace(nil)
|
46
|
+
Thread.backend.trace_proc = nil
|
69
47
|
end
|
70
48
|
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.59.1
|
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-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -324,6 +324,7 @@ files:
|
|
324
324
|
- examples/core/erlang-style-genserver.rb
|
325
325
|
- examples/core/forking.rb
|
326
326
|
- examples/core/handling-signals.rb
|
327
|
+
- examples/core/idle_gc.rb
|
327
328
|
- examples/core/interrupt.rb
|
328
329
|
- examples/core/nested.rb
|
329
330
|
- examples/core/pingpong.rb
|
@@ -355,10 +356,12 @@ files:
|
|
355
356
|
- examples/io/irb.rb
|
356
357
|
- examples/io/net-http.rb
|
357
358
|
- examples/io/open.rb
|
359
|
+
- examples/io/pipe.rb
|
358
360
|
- examples/io/pry.rb
|
359
361
|
- examples/io/rack_server.rb
|
360
362
|
- examples/io/raw.rb
|
361
363
|
- examples/io/reline.rb
|
364
|
+
- examples/io/splice_chunks.rb
|
362
365
|
- examples/io/stdio.rb
|
363
366
|
- examples/io/system.rb
|
364
367
|
- examples/io/tcp_proxy.rb
|
@@ -414,6 +417,7 @@ files:
|
|
414
417
|
- ext/liburing/setup.c
|
415
418
|
- ext/liburing/syscall.c
|
416
419
|
- ext/liburing/syscall.h
|
420
|
+
- ext/polyphony/backend_common.c
|
417
421
|
- ext/polyphony/backend_common.h
|
418
422
|
- ext/polyphony/backend_io_uring.c
|
419
423
|
- ext/polyphony/backend_io_uring_context.c
|
@@ -433,11 +437,11 @@ files:
|
|
433
437
|
- ext/polyphony/ring_buffer.c
|
434
438
|
- ext/polyphony/ring_buffer.h
|
435
439
|
- ext/polyphony/runqueue.c
|
440
|
+
- ext/polyphony/runqueue.h
|
436
441
|
- ext/polyphony/runqueue_ring_buffer.c
|
437
442
|
- ext/polyphony/runqueue_ring_buffer.h
|
438
443
|
- ext/polyphony/socket_extensions.c
|
439
444
|
- ext/polyphony/thread.c
|
440
|
-
- ext/polyphony/tracing.c
|
441
445
|
- lib/polyphony.rb
|
442
446
|
- lib/polyphony/adapters/fs.rb
|
443
447
|
- lib/polyphony/adapters/irb.rb
|
@@ -447,7 +451,6 @@ files:
|
|
447
451
|
- lib/polyphony/adapters/readline.rb
|
448
452
|
- lib/polyphony/adapters/redis.rb
|
449
453
|
- lib/polyphony/adapters/sequel.rb
|
450
|
-
- lib/polyphony/adapters/trace.rb
|
451
454
|
- lib/polyphony/core/channel.rb
|
452
455
|
- lib/polyphony/core/exceptions.rb
|
453
456
|
- lib/polyphony/core/global_api.rb
|
data/ext/polyphony/tracing.c
DELETED