polyphony 0.57.0 → 0.60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/Gemfile.lock +15 -29
  4. data/examples/core/message_based_supervision.rb +51 -0
  5. data/ext/polyphony/backend_common.c +108 -3
  6. data/ext/polyphony/backend_common.h +23 -0
  7. data/ext/polyphony/backend_io_uring.c +117 -39
  8. data/ext/polyphony/backend_io_uring_context.c +11 -3
  9. data/ext/polyphony/backend_io_uring_context.h +5 -3
  10. data/ext/polyphony/backend_libev.c +92 -30
  11. data/ext/polyphony/extconf.rb +2 -2
  12. data/ext/polyphony/fiber.c +1 -34
  13. data/ext/polyphony/polyphony.c +12 -19
  14. data/ext/polyphony/polyphony.h +10 -20
  15. data/ext/polyphony/polyphony_ext.c +0 -4
  16. data/ext/polyphony/queue.c +12 -12
  17. data/ext/polyphony/runqueue.c +17 -85
  18. data/ext/polyphony/runqueue.h +27 -0
  19. data/ext/polyphony/thread.c +10 -99
  20. data/lib/polyphony/core/timer.rb +2 -2
  21. data/lib/polyphony/extensions/fiber.rb +102 -82
  22. data/lib/polyphony/extensions/io.rb +10 -9
  23. data/lib/polyphony/extensions/openssl.rb +14 -4
  24. data/lib/polyphony/extensions/socket.rb +15 -15
  25. data/lib/polyphony/extensions/thread.rb +8 -0
  26. data/lib/polyphony/version.rb +1 -1
  27. data/polyphony.gemspec +0 -7
  28. data/test/test_backend.rb +71 -5
  29. data/test/test_ext.rb +1 -1
  30. data/test/test_fiber.rb +106 -18
  31. data/test/test_global_api.rb +1 -1
  32. data/test/test_io.rb +29 -0
  33. data/test/test_supervise.rb +100 -100
  34. data/test/test_thread.rb +57 -11
  35. data/test/test_thread_pool.rb +1 -1
  36. data/test/test_trace.rb +28 -49
  37. metadata +4 -108
  38. data/ext/polyphony/tracing.c +0 -11
  39. data/lib/polyphony/adapters/trace.rb +0 -138
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
- t = Polyphony::Trace.new(:fiber_all) do |r|
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
- t.disable
141
- assert_equal [:fiber_switchpoint], records.map { |r| r[:event] }
134
+ assert_equal [
135
+ [:fiber_switchpoint, Fiber.current]
136
+ ], records
142
137
  ensure
143
- t&.disable
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
@@ -68,7 +68,7 @@ class ThreadPoolTest < MiniTest::Test
68
68
  assert_in_range 0.0..0.009, elapsed
69
69
  assert buffer.size < 2
70
70
 
71
- sleep 0.1 # allow time for threads to spawn
71
+ sleep 0.15 # allow time for threads to spawn
72
72
  assert_equal @pool.size, threads.uniq.size
73
73
  assert_equal (0..9).to_a, buffer.sort
74
74
  end
data/test/test_trace.rb CHANGED
@@ -1,70 +1,49 @@
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
- records = []
20
- t = Polyphony::Trace.new(:fiber_all) { |r| records << r if r[:event] =~ /^fiber_/ }
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 3, records.size
27
- events = records.map { |r| r[:event] }
28
- assert_equal [:fiber_schedule, :fiber_switchpoint, :fiber_run], events
29
- assert_equal [Fiber.current], records.map { |r| r[:fiber] }.uniq
11
+ assert_equal [
12
+ [:fiber_schedule, Fiber.current, nil, false],
13
+ [:fiber_switchpoint, Fiber.current],
14
+ [:fiber_run, Fiber.current, nil]
15
+ ], events
30
16
  ensure
31
- t&.disable
32
- Polyphony.trace(nil)
17
+ Thread.backend.trace_proc = nil
33
18
  end
34
19
 
35
20
  def test_2_fiber_trace
36
- records = []
37
- thread = Thread.current
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
- [:f, :fiber_create],
51
- [:f, :fiber_schedule],
52
- [:current, :fiber_switchpoint],
53
- [:f, :fiber_run],
54
- [:f, :fiber_switchpoint],
55
- [:f, :fiber_event_poll_enter],
56
- [:f, :fiber_schedule],
57
- [:f, :fiber_event_poll_leave],
58
- [:f, :fiber_run],
59
- [:f, :fiber_terminate],
60
- [:current, :fiber_switchpoint],
61
- [:current, :fiber_event_poll_enter],
62
- [:current, :fiber_schedule],
63
- [:current, :fiber_event_poll_leave],
64
- [:current, :fiber_run]
29
+ [:fiber_create, f],
30
+ [:fiber_schedule, f, nil, false],
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, false],
36
+ [:fiber_event_poll_leave, f],
37
+ [:fiber_run, f, nil],
38
+ [:fiber_terminate, f, :byebye],
39
+ [:fiber_switchpoint, f],
40
+ [:fiber_switchpoint, Fiber.current],
41
+ [:fiber_event_poll_enter, Fiber.current],
42
+ [:fiber_schedule, Fiber.current, nil, false],
43
+ [:fiber_event_poll_leave, Fiber.current],
44
+ [:fiber_run, Fiber.current, nil]
65
45
  ], events
66
46
  ensure
67
- t&.disable
68
- Polyphony.trace(nil)
47
+ Thread.backend.trace_proc = nil
69
48
  end
70
49
  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.57.0
4
+ version: '0.60'
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-23 00:00:00.000000000 Z
11
+ date: 2021-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -108,110 +108,6 @@ dependencies:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
110
  version: 1.4.2
111
- - !ruby/object:Gem::Dependency
112
- name: pg
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - '='
116
- - !ruby/object:Gem::Version
117
- version: 1.1.4
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - '='
123
- - !ruby/object:Gem::Version
124
- version: 1.1.4
125
- - !ruby/object:Gem::Dependency
126
- name: redis
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - '='
130
- - !ruby/object:Gem::Version
131
- version: 4.1.0
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - '='
137
- - !ruby/object:Gem::Version
138
- version: 4.1.0
139
- - !ruby/object:Gem::Dependency
140
- name: hiredis
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - '='
144
- - !ruby/object:Gem::Version
145
- version: 0.6.3
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - '='
151
- - !ruby/object:Gem::Version
152
- version: 0.6.3
153
- - !ruby/object:Gem::Dependency
154
- name: http_parser.rb
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: 0.6.0
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: 0.6.0
167
- - !ruby/object:Gem::Dependency
168
- name: rack
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - ">="
172
- - !ruby/object:Gem::Version
173
- version: 2.0.8
174
- - - "<"
175
- - !ruby/object:Gem::Version
176
- version: 2.3.0
177
- type: :development
178
- prerelease: false
179
- version_requirements: !ruby/object:Gem::Requirement
180
- requirements:
181
- - - ">="
182
- - !ruby/object:Gem::Version
183
- version: 2.0.8
184
- - - "<"
185
- - !ruby/object:Gem::Version
186
- version: 2.3.0
187
- - !ruby/object:Gem::Dependency
188
- name: mysql2
189
- requirement: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - '='
192
- - !ruby/object:Gem::Version
193
- version: 0.5.3
194
- type: :development
195
- prerelease: false
196
- version_requirements: !ruby/object:Gem::Requirement
197
- requirements:
198
- - - '='
199
- - !ruby/object:Gem::Version
200
- version: 0.5.3
201
- - !ruby/object:Gem::Dependency
202
- name: sequel
203
- requirement: !ruby/object:Gem::Requirement
204
- requirements:
205
- - - '='
206
- - !ruby/object:Gem::Version
207
- version: 5.34.0
208
- type: :development
209
- prerelease: false
210
- version_requirements: !ruby/object:Gem::Requirement
211
- requirements:
212
- - - '='
213
- - !ruby/object:Gem::Version
214
- version: 5.34.0
215
111
  - !ruby/object:Gem::Dependency
216
112
  name: httparty
217
113
  requirement: !ruby/object:Gem::Requirement
@@ -326,6 +222,7 @@ files:
326
222
  - examples/core/handling-signals.rb
327
223
  - examples/core/idle_gc.rb
328
224
  - examples/core/interrupt.rb
225
+ - examples/core/message_based_supervision.rb
329
226
  - examples/core/nested.rb
330
227
  - examples/core/pingpong.rb
331
228
  - examples/core/queue.rb
@@ -437,11 +334,11 @@ files:
437
334
  - ext/polyphony/ring_buffer.c
438
335
  - ext/polyphony/ring_buffer.h
439
336
  - ext/polyphony/runqueue.c
337
+ - ext/polyphony/runqueue.h
440
338
  - ext/polyphony/runqueue_ring_buffer.c
441
339
  - ext/polyphony/runqueue_ring_buffer.h
442
340
  - ext/polyphony/socket_extensions.c
443
341
  - ext/polyphony/thread.c
444
- - ext/polyphony/tracing.c
445
342
  - lib/polyphony.rb
446
343
  - lib/polyphony/adapters/fs.rb
447
344
  - lib/polyphony/adapters/irb.rb
@@ -451,7 +348,6 @@ files:
451
348
  - lib/polyphony/adapters/readline.rb
452
349
  - lib/polyphony/adapters/redis.rb
453
350
  - lib/polyphony/adapters/sequel.rb
454
- - lib/polyphony/adapters/trace.rb
455
351
  - lib/polyphony/core/channel.rb
456
352
  - lib/polyphony/core/exceptions.rb
457
353
  - lib/polyphony/core/global_api.rb
@@ -1,11 +0,0 @@
1
- #include "polyphony.h"
2
-
3
- int __tracing_enabled__ = 0;
4
-
5
- VALUE __fiber_trace__(int argc, VALUE *argv, VALUE self) {
6
- return rb_ary_new4(argc, argv);
7
- }
8
-
9
- void Init_Tracing() {
10
- rb_define_global_function("__fiber_trace__", __fiber_trace__, -1);
11
- }
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../../polyphony'
4
-
5
- STOCK_EVENTS = %i[line call return c_call c_return b_call b_return].freeze
6
-
7
- module Polyphony
8
- # Tracing functionality for Polyphony
9
- module Trace
10
- class << self
11
- def new(*events)
12
- start_stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
13
- events = STOCK_EVENTS if events.empty?
14
- ::TracePoint.new(*events) { |tp| yield trace_record(tp, start_stamp) }
15
- end
16
-
17
- def trace_record(trp, start_stamp)
18
- stamp = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start_stamp
19
-
20
- { stamp: stamp, event: trp.event, location: "#{trp.path}:#{trp.lineno}",
21
- self: trp.self, binding: trp.binding, fiber: tp_fiber(trp),
22
- lineno: trp.lineno, method_id: trp.method_id,
23
- path: trp.path, parameters: tp_params(trp),
24
- return_value: tp_return_value(trp), schedule_value: tp_schedule_value(trp),
25
- exception: tp_raised_exception(trp) }
26
- end
27
-
28
- def tp_fiber(trp)
29
- trp.is_a?(FiberTracePoint) ? trp.fiber : Fiber.current
30
- end
31
-
32
- PARAMS_EVENTS = %i[call c_call b_call].freeze
33
-
34
- def tp_params(trp)
35
- PARAMS_EVENTS.include?(trp.event) ? trp.parameters : nil
36
- end
37
-
38
- RETURN_VALUE_EVENTS = %i[return c_return b_return].freeze
39
-
40
- def tp_return_value(trp)
41
- RETURN_VALUE_EVENTS.include?(trp.event) ? trp.return_value : nil
42
- end
43
-
44
- SCHEDULE_VALUE_EVENTS = %i[fiber_schedule fiber_run].freeze
45
-
46
- def tp_schedule_value(trp)
47
- SCHEDULE_VALUE_EVENTS.include?(trp.event) ? trp.value : nil
48
- end
49
-
50
- def tp_raised_exception(trp)
51
- trp.event == :raise && trp.raised_exception
52
- end
53
-
54
- def analyze(records)
55
- by_fiber = Hash.new { |h, f| h[f] = [] }
56
- records.each_with_object(by_fiber) { |r, h| h[r[:fiber]] << r }
57
- { by_fiber: by_fiber }
58
- end
59
-
60
- # Implements fake TracePoint instances for fiber-related events
61
- class FiberTracePoint
62
- attr_reader :event, :fiber, :value
63
-
64
- def initialize(tpoint)
65
- @tp = tpoint
66
- @event = tpoint.return_value[0]
67
- @fiber = tpoint.return_value[1]
68
- @value = tpoint.return_value[2]
69
- end
70
-
71
- def lineno
72
- @tp.lineno
73
- end
74
-
75
- def method_id
76
- @tp.method_id
77
- end
78
-
79
- def path
80
- @tp.path
81
- end
82
-
83
- def self
84
- @tp.self
85
- end
86
-
87
- def binding
88
- @tp.binding
89
- end
90
- end
91
-
92
- class << ::TracePoint
93
- POLYPHONY_FILE_REGEXP = /^#{::Exception::POLYPHONY_DIR}/.freeze
94
-
95
- alias_method :orig_new, :new
96
- def new(*args, &block)
97
- events_mask, fiber_events_mask = event_masks(args)
98
-
99
- orig_new(*events_mask) do |tp|
100
- handle_tp_event(tp, fiber_events_mask, &block)
101
- end
102
- end
103
-
104
- def handle_tp_event(tpoint, fiber_events_mask)
105
- # next unless !$watched_fiber || Fiber.current == $watched_fiber
106
-
107
- if tpoint.method_id == :__fiber_trace__
108
- return if tpoint.event != :c_return
109
- return unless fiber_events_mask.include?(tpoint.return_value[0])
110
-
111
- tpoint = FiberTracePoint.new(tpoint)
112
- elsif tpoint.path =~ POLYPHONY_FILE_REGEXP
113
- return
114
- end
115
-
116
- yield tpoint
117
- end
118
-
119
- ALL_FIBER_EVENTS = %i[
120
- fiber_create fiber_terminate fiber_schedule fiber_switchpoint fiber_run
121
- fiber_event_poll_enter fiber_event_poll_leave
122
- ].freeze
123
-
124
- def event_masks(events)
125
- events.each_with_object([[], []]) do |e, masks|
126
- case e
127
- when /^fiber_/
128
- masks[1] += e == :fiber_all ? ALL_FIBER_EVENTS : [e]
129
- masks[0] << :c_return unless masks[0].include?(:c_return)
130
- else
131
- masks[0] << e
132
- end
133
- end
134
- end
135
- end
136
- end
137
- end
138
- end