uringmachine 0.23.1 → 0.24.0
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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -1
- data/TODO.md +52 -12
- data/benchmark/bm_io_pipe.rb +43 -1
- data/benchmark/bm_io_socketpair.rb +32 -2
- data/benchmark/bm_mutex_io.rb +47 -5
- data/benchmark/chart_bm_io_pipe_x.png +0 -0
- data/benchmark/common.rb +161 -17
- data/benchmark/http_parse.rb +9 -9
- data/benchmark/http_server_accept_queue.rb +104 -0
- data/benchmark/http_server_multi_accept.rb +93 -0
- data/benchmark/http_server_multi_ractor.rb +99 -0
- data/benchmark/http_server_single_thread.rb +80 -0
- data/benchmark/ips_io_pipe.rb +146 -0
- data/docs/design/buffer_pool.md +183 -0
- data/docs/um_api.md +91 -0
- data/examples/fiber_scheduler_file_io.rb +34 -0
- data/examples/fiber_scheduler_file_io_async.rb +33 -0
- data/ext/um/um.c +65 -48
- data/ext/um/um.h +11 -1
- data/ext/um/um_class.c +54 -11
- data/ext/um/um_sidecar.c +106 -0
- data/ext/um/um_stream.c +31 -0
- data/ext/um/um_stream_class.c +14 -0
- data/grant-2025/interim-report.md +130 -0
- data/grant-2025/journal.md +166 -2
- data/grant-2025/tasks.md +27 -17
- data/lib/uringmachine/fiber_scheduler.rb +35 -27
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +4 -6
- data/test/helper.rb +8 -3
- data/test/test_fiber.rb +16 -0
- data/test/test_fiber_scheduler.rb +184 -72
- data/test/test_stream.rb +16 -0
- data/test/test_um.rb +94 -24
- metadata +14 -2
data/test/test_stream.rb
CHANGED
|
@@ -175,10 +175,26 @@ class StreamRespTest < StreamBaseTest
|
|
|
175
175
|
assert_equal "$6\r\nfoobar\r\n", s.resp_encode(+'', 'foobar')
|
|
176
176
|
assert_equal "$10\r\nפובאר\r\n", s.resp_encode(+'', 'פובאר')
|
|
177
177
|
|
|
178
|
+
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
|
|
179
|
+
s.resp_encode(+'', ['foo', 'bar'])
|
|
180
|
+
|
|
178
181
|
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
|
|
179
182
|
s.resp_encode(+'', ['foo', 'bar'])
|
|
180
183
|
|
|
181
184
|
assert_equal "%2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$3\r\nbaz\r\n:42\r\n",
|
|
182
185
|
s.resp_encode(+'', { 'foo' => 'bar', 'baz' => 42 })
|
|
183
186
|
end
|
|
187
|
+
|
|
188
|
+
def test_resp_encode_cmd
|
|
189
|
+
s = UM::Stream
|
|
190
|
+
|
|
191
|
+
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
|
|
192
|
+
s.resp_encode_cmd(+'', 'foo', 'bar')
|
|
193
|
+
|
|
194
|
+
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
|
|
195
|
+
s.resp_encode_cmd(+'', 'foo', :bar)
|
|
196
|
+
|
|
197
|
+
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\n123\r\n",
|
|
198
|
+
s.resp_encode_cmd(+'', 'foo', 123)
|
|
199
|
+
end
|
|
184
200
|
end
|
data/test/test_um.rb
CHANGED
|
@@ -12,20 +12,46 @@ class UringMachineTest < Minitest::Test
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
class SizeTest < Minitest::Test
|
|
15
|
-
def
|
|
15
|
+
def test_size_opt_default
|
|
16
16
|
m = UM.new
|
|
17
17
|
assert_equal 4096, m.size
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def
|
|
21
|
-
m = UM.new(13)
|
|
20
|
+
def test_size_opt_custom
|
|
21
|
+
m = UM.new(size: 13)
|
|
22
22
|
assert_equal 13, m.size
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
def test_size_opt_effective_sq_size
|
|
26
|
+
m = UM.new(size: 1)
|
|
27
|
+
r, w = UM.pipe
|
|
28
|
+
m.close_async(r)
|
|
29
|
+
assert_equal 1, m.metrics[:ops_unsubmitted]
|
|
30
|
+
assert_raises(UM::Error) { m.close_async(w) }
|
|
31
|
+
|
|
32
|
+
m.submit
|
|
33
|
+
m.close_async(w)
|
|
34
|
+
assert_equal 1, m.metrics[:ops_unsubmitted]
|
|
35
|
+
|
|
36
|
+
m.submit
|
|
37
|
+
assert_equal 0, m.metrics[:ops_unsubmitted]
|
|
38
|
+
end
|
|
24
39
|
end
|
|
25
40
|
|
|
26
41
|
class SQPOLLTest < Minitest::Test
|
|
42
|
+
def test_sqpoll_mode
|
|
43
|
+
m = UM.new()
|
|
44
|
+
assert_equal false, m.sqpoll_mode?
|
|
45
|
+
|
|
46
|
+
m = UM.new(sqpoll: true)
|
|
47
|
+
assert_equal true, m.sqpoll_mode?
|
|
48
|
+
|
|
49
|
+
m = UM.new(sqpoll: 1)
|
|
50
|
+
assert_equal true, m.sqpoll_mode?
|
|
51
|
+
end
|
|
52
|
+
|
|
27
53
|
def test_sqpoll_timeout
|
|
28
|
-
m = UM.new(
|
|
54
|
+
m = UM.new(sqpoll: 0.05)
|
|
29
55
|
|
|
30
56
|
r, w = UM.pipe
|
|
31
57
|
|
|
@@ -46,7 +72,7 @@ class SQPOLLTest < Minitest::Test
|
|
|
46
72
|
end
|
|
47
73
|
|
|
48
74
|
def test_sqpoll_timeout_with_submit
|
|
49
|
-
m = UM.new(
|
|
75
|
+
m = UM.new(sqpoll: 0.05)
|
|
50
76
|
|
|
51
77
|
r, w = UM.pipe
|
|
52
78
|
|
|
@@ -69,6 +95,16 @@ class SQPOLLTest < Minitest::Test
|
|
|
69
95
|
end
|
|
70
96
|
end
|
|
71
97
|
|
|
98
|
+
class SidecarTest < Minitest::Test
|
|
99
|
+
def test_sidecar_mode
|
|
100
|
+
m = UM.new()
|
|
101
|
+
assert_equal false, m.sidecar_mode?
|
|
102
|
+
|
|
103
|
+
m = UM.new(sidecar: true)
|
|
104
|
+
assert_equal true, m.sidecar_mode?
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
72
108
|
class SubmitTest < UMBaseTest
|
|
73
109
|
def test_submit
|
|
74
110
|
_r, w = UM.pipe
|
|
@@ -819,7 +855,7 @@ class WritevTest < UMBaseTest
|
|
|
819
855
|
buf = +''
|
|
820
856
|
res = machine.read(r, buf, 8192)
|
|
821
857
|
break if res == 0
|
|
822
|
-
|
|
858
|
+
|
|
823
859
|
reads << buf
|
|
824
860
|
}
|
|
825
861
|
}
|
|
@@ -1171,7 +1207,7 @@ class AcceptEachTest < UMBaseTest
|
|
|
1171
1207
|
end
|
|
1172
1208
|
|
|
1173
1209
|
def teardown
|
|
1174
|
-
@server&.close
|
|
1210
|
+
@server&.close rescue nil
|
|
1175
1211
|
super
|
|
1176
1212
|
end
|
|
1177
1213
|
|
|
@@ -1221,8 +1257,37 @@ class AcceptEachTest < UMBaseTest
|
|
|
1221
1257
|
s.close
|
|
1222
1258
|
end
|
|
1223
1259
|
|
|
1260
|
+
def test_accept_each_closed
|
|
1261
|
+
count = 0
|
|
1262
|
+
done = nil
|
|
1263
|
+
f = @machine.spin do
|
|
1264
|
+
machine.accept_each(@server.fileno) do |fd|
|
|
1265
|
+
count += 1
|
|
1266
|
+
end
|
|
1267
|
+
ensure
|
|
1268
|
+
done = true
|
|
1269
|
+
end
|
|
1270
|
+
|
|
1271
|
+
s = TCPSocket.new('127.0.0.1', @port)
|
|
1272
|
+
@machine.sleep(0.01)
|
|
1273
|
+
|
|
1274
|
+
assert_equal 1, count
|
|
1275
|
+
refute done
|
|
1276
|
+
|
|
1277
|
+
machine.close(@server.fileno)
|
|
1278
|
+
@machine.sleep(0.01)
|
|
1279
|
+
refute done
|
|
1280
|
+
|
|
1281
|
+
s = TCPSocket.new('127.0.0.1', @port)
|
|
1282
|
+
@machine.sleep(0.01)
|
|
1283
|
+
|
|
1284
|
+
assert_equal 2, count
|
|
1285
|
+
refute done
|
|
1286
|
+
ensure
|
|
1287
|
+
s.close rescue nil
|
|
1288
|
+
end
|
|
1289
|
+
|
|
1224
1290
|
def test_accept_each_bad_fd
|
|
1225
|
-
queue = UM::Queue.new
|
|
1226
1291
|
assert_raises(Errno::ENOTSOCK) { machine.accept_each(STDOUT.fileno) }
|
|
1227
1292
|
end
|
|
1228
1293
|
end
|
|
@@ -1264,7 +1329,6 @@ class AcceptIntoQueueTest < UMBaseTest
|
|
|
1264
1329
|
end
|
|
1265
1330
|
|
|
1266
1331
|
def test_accept_into_queue_interrupted
|
|
1267
|
-
count = 0
|
|
1268
1332
|
terminated = nil
|
|
1269
1333
|
queue = UM::Queue.new
|
|
1270
1334
|
f = @machine.spin do
|
|
@@ -1792,12 +1856,13 @@ class QueueTest < UMBaseTest
|
|
|
1792
1856
|
assert_equal 1, q.count
|
|
1793
1857
|
machine.snooze
|
|
1794
1858
|
assert_equal 1, machine.metrics[:ops_pending]
|
|
1859
|
+
machine.snooze
|
|
1795
1860
|
assert_equal [[1, :foo]], buf
|
|
1796
1861
|
|
|
1797
1862
|
machine.push(q, :bar)
|
|
1798
1863
|
assert_equal 1, q.count
|
|
1799
1864
|
|
|
1800
|
-
machine.snooze
|
|
1865
|
+
2.times { machine.snooze }
|
|
1801
1866
|
assert_equal [[1, :foo], [2, :bar]], buf
|
|
1802
1867
|
assert_equal 0, q.count
|
|
1803
1868
|
end
|
|
@@ -1851,7 +1916,7 @@ class QueueTest < UMBaseTest
|
|
|
1851
1916
|
assert_equal [[1, :foo]], buf
|
|
1852
1917
|
|
|
1853
1918
|
machine.push(q, :bar)
|
|
1854
|
-
machine.snooze
|
|
1919
|
+
2.times { machine.snooze }
|
|
1855
1920
|
assert_equal [[1, :foo], [2, :bar]], buf
|
|
1856
1921
|
end
|
|
1857
1922
|
|
|
@@ -2028,7 +2093,9 @@ end
|
|
|
2028
2093
|
|
|
2029
2094
|
class PidfdTest < UMBaseTest
|
|
2030
2095
|
def test_pidfd_open
|
|
2096
|
+
# machine.sidecar_stop
|
|
2031
2097
|
pid = fork { exit 13 }
|
|
2098
|
+
# machine.sidecar_start
|
|
2032
2099
|
fd = UM.pidfd_open(pid)
|
|
2033
2100
|
assert_kind_of Integer, fd
|
|
2034
2101
|
|
|
@@ -2121,6 +2188,7 @@ class SelectTest < UMBaseTest
|
|
|
2121
2188
|
machine.spin do
|
|
2122
2189
|
events << 1
|
|
2123
2190
|
events << machine.select([rfd1, rfd2], [], [])
|
|
2191
|
+
machine.snooze
|
|
2124
2192
|
events << 2
|
|
2125
2193
|
events << machine.select([rfd1, rfd2], [], [])
|
|
2126
2194
|
events << 3
|
|
@@ -2134,14 +2202,13 @@ class SelectTest < UMBaseTest
|
|
|
2134
2202
|
|
|
2135
2203
|
machine.write(wfd1, 'foo')
|
|
2136
2204
|
machine.snooze
|
|
2137
|
-
assert_equal [1, [[rfd1], [], []]
|
|
2205
|
+
assert_equal [1, [[rfd1], [], []]], events
|
|
2138
2206
|
|
|
2139
2207
|
machine.write(wfd2, 'foo')
|
|
2140
|
-
|
|
2141
|
-
machine.snooze
|
|
2208
|
+
2.times { machine.snooze }
|
|
2142
2209
|
assert_equal [1, [[rfd1], [], []], 2, [[rfd1, rfd2], [], []], 3], events
|
|
2143
2210
|
|
|
2144
|
-
machine.snooze
|
|
2211
|
+
2.times { machine.snooze }
|
|
2145
2212
|
|
|
2146
2213
|
assert_equal [
|
|
2147
2214
|
1, [[rfd1], [], []],
|
|
@@ -2522,7 +2589,10 @@ class MetricsTest < UMBaseTest
|
|
|
2522
2589
|
end
|
|
2523
2590
|
|
|
2524
2591
|
def test_metrics_size
|
|
2525
|
-
m = UM.new
|
|
2592
|
+
m = UM.new
|
|
2593
|
+
assert_equal 4096, m.metrics[:size]
|
|
2594
|
+
|
|
2595
|
+
m = UM.new(size: 13)
|
|
2526
2596
|
assert_equal 13, m.metrics[:size]
|
|
2527
2597
|
end
|
|
2528
2598
|
|
|
@@ -2602,8 +2672,6 @@ class MetricsTest < UMBaseTest
|
|
|
2602
2672
|
f = machine.spin { machine.sleep(0.001) }
|
|
2603
2673
|
assert_equal [0, 0, 1, 255, 0], ops_metrics
|
|
2604
2674
|
machine.snooze
|
|
2605
|
-
assert_equal [1, 1, 0, 256, 0], ops_metrics
|
|
2606
|
-
machine.submit
|
|
2607
2675
|
assert_equal [1, 0, 0, 256, 0], ops_metrics
|
|
2608
2676
|
machine.join(f)
|
|
2609
2677
|
assert_equal [0, 0, 0, 256, 0], ops_metrics
|
|
@@ -2626,22 +2694,22 @@ end
|
|
|
2626
2694
|
|
|
2627
2695
|
class ProfileModeTest < UMBaseTest
|
|
2628
2696
|
def test_profile_mode_empty
|
|
2629
|
-
assert_equal false, machine.
|
|
2697
|
+
assert_equal false, machine.profile_mode?
|
|
2630
2698
|
assert_equal([
|
|
2631
2699
|
:size, :total_ops, :total_switches, :total_waits, :ops_pending,
|
|
2632
2700
|
:ops_unsubmitted, :ops_runqueue, :ops_free, :ops_transient
|
|
2633
2701
|
], machine.metrics.keys)
|
|
2634
2702
|
|
|
2635
|
-
machine.
|
|
2636
|
-
assert_equal true, machine.
|
|
2703
|
+
machine.profile_mode = true
|
|
2704
|
+
assert_equal true, machine.profile_mode?
|
|
2637
2705
|
assert_equal([
|
|
2638
2706
|
:size, :total_ops, :total_switches, :total_waits, :ops_pending,
|
|
2639
2707
|
:ops_unsubmitted, :ops_runqueue, :ops_free, :ops_transient,
|
|
2640
2708
|
:time_total_cpu, :time_total_wait,
|
|
2641
2709
|
], machine.metrics.keys)
|
|
2642
2710
|
|
|
2643
|
-
machine.
|
|
2644
|
-
assert_equal false, machine.
|
|
2711
|
+
machine.profile_mode = false
|
|
2712
|
+
assert_equal false, machine.profile_mode?
|
|
2645
2713
|
assert_equal([
|
|
2646
2714
|
:size, :total_ops, :total_switches, :total_waits, :ops_pending,
|
|
2647
2715
|
:ops_unsubmitted, :ops_runqueue, :ops_free, :ops_transient
|
|
@@ -2649,7 +2717,9 @@ class ProfileModeTest < UMBaseTest
|
|
|
2649
2717
|
end
|
|
2650
2718
|
|
|
2651
2719
|
def test_profile_mode_total_times
|
|
2652
|
-
|
|
2720
|
+
skip "TODO: make profile mode usable in in sidecar mode"
|
|
2721
|
+
|
|
2722
|
+
machine.profile_mode = true
|
|
2653
2723
|
machine.sleep(0.01)
|
|
2654
2724
|
assert_in_range 0.0..0.0005, machine.metrics[:time_total_cpu]
|
|
2655
2725
|
assert_in_range 0.01..0.015, machine.metrics[:time_total_wait]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: uringmachine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.24.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sharon Rosner
|
|
@@ -106,9 +106,15 @@ files:
|
|
|
106
106
|
- benchmark/bm_pg_client.rb
|
|
107
107
|
- benchmark/bm_queue.rb
|
|
108
108
|
- benchmark/chart_all.png
|
|
109
|
+
- benchmark/chart_bm_io_pipe_x.png
|
|
109
110
|
- benchmark/common.rb
|
|
110
111
|
- benchmark/dns_client.rb
|
|
111
112
|
- benchmark/http_parse.rb
|
|
113
|
+
- benchmark/http_server_accept_queue.rb
|
|
114
|
+
- benchmark/http_server_multi_accept.rb
|
|
115
|
+
- benchmark/http_server_multi_ractor.rb
|
|
116
|
+
- benchmark/http_server_single_thread.rb
|
|
117
|
+
- benchmark/ips_io_pipe.rb
|
|
112
118
|
- benchmark/mutex.rb
|
|
113
119
|
- benchmark/mutex_single.rb
|
|
114
120
|
- benchmark/read_each.rb
|
|
@@ -117,8 +123,12 @@ files:
|
|
|
117
123
|
- benchmark/snooze.rb
|
|
118
124
|
- benchmark/sqlite.rb
|
|
119
125
|
- benchmark/write.rb
|
|
126
|
+
- docs/design/buffer_pool.md
|
|
127
|
+
- docs/um_api.md
|
|
120
128
|
- examples/echo_server.rb
|
|
121
129
|
- examples/fiber_scheduler_demo.rb
|
|
130
|
+
- examples/fiber_scheduler_file_io.rb
|
|
131
|
+
- examples/fiber_scheduler_file_io_async.rb
|
|
122
132
|
- examples/fiber_scheduler_fork.rb
|
|
123
133
|
- examples/http_server.rb
|
|
124
134
|
- examples/inout.rb
|
|
@@ -141,10 +151,12 @@ files:
|
|
|
141
151
|
- ext/um/um_mutex_class.c
|
|
142
152
|
- ext/um/um_op.c
|
|
143
153
|
- ext/um/um_queue_class.c
|
|
154
|
+
- ext/um/um_sidecar.c
|
|
144
155
|
- ext/um/um_stream.c
|
|
145
156
|
- ext/um/um_stream_class.c
|
|
146
157
|
- ext/um/um_sync.c
|
|
147
158
|
- ext/um/um_utils.c
|
|
159
|
+
- grant-2025/interim-report.md
|
|
148
160
|
- grant-2025/journal.md
|
|
149
161
|
- grant-2025/tasks.md
|
|
150
162
|
- lib/uringmachine.rb
|
|
@@ -720,7 +732,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
720
732
|
- !ruby/object:Gem::Version
|
|
721
733
|
version: '0'
|
|
722
734
|
requirements: []
|
|
723
|
-
rubygems_version: 4.0.
|
|
735
|
+
rubygems_version: 4.0.3
|
|
724
736
|
specification_version: 4
|
|
725
737
|
summary: A lean, mean io_uring machine
|
|
726
738
|
test_files: []
|