uringmachine 0.23.1 → 0.25.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/.gitignore +1 -0
- data/.gitmodules +0 -3
- data/CHANGELOG.md +17 -0
- data/Gemfile +12 -1
- data/README.md +266 -112
- data/Rakefile +8 -0
- data/TODO.md +40 -17
- 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 +163 -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/benchmark/openssl.rb +77 -0
- data/benchmark/openssl_socketpair.rb +112 -0
- data/benchmark/sqlite.rb +1 -1
- 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/extconf.rb +15 -0
- data/ext/um/um.c +83 -50
- data/ext/um/um.h +18 -3
- data/ext/um/um_async_op_class.c +31 -0
- data/ext/um/um_class.c +759 -30
- data/ext/um/um_const.c +31 -0
- data/ext/um/um_mutex_class.c +12 -0
- data/ext/um/um_queue_class.c +16 -0
- data/ext/um/um_sidecar.c +106 -0
- data/ext/um/um_ssl.c +109 -0
- data/ext/um/um_stream.c +40 -8
- data/ext/um/um_stream_class.c +14 -0
- data/ext/um/um_utils.c +3 -4
- data/grant-2025/interim-report.md +130 -0
- data/grant-2025/journal.md +166 -2
- data/grant-2025/tasks.md +32 -20
- data/lib/uringmachine/dns_resolver.rb +38 -0
- data/lib/uringmachine/fiber_scheduler.rb +42 -32
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +105 -7
- data/test/helper.rb +23 -3
- data/test/test_fiber.rb +16 -0
- data/test/test_fiber_scheduler.rb +221 -72
- data/test/test_ssl.rb +85 -0
- data/test/test_stream.rb +27 -0
- data/test/test_um.rb +250 -26
- data/uringmachine.gemspec +1 -7
- data/vendor/liburing/examples/send-zerocopy.c +43 -31
- data/vendor/liburing/examples/zcrx.c +260 -69
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +12 -0
- data/vendor/liburing/src/include/liburing.h +3 -2
- data/vendor/liburing/src/liburing-ffi.map +4 -0
- data/vendor/liburing/src/liburing.map +4 -0
- data/vendor/liburing/src/queue.c +12 -0
- data/vendor/liburing/src/register.c +1 -0
- data/vendor/liburing/src/setup.c +15 -7
- data/vendor/liburing/test/Makefile +8 -4
- data/vendor/liburing/test/conn-unreach.c +1 -1
- data/vendor/liburing/test/epwait.c +32 -6
- data/vendor/liburing/test/io-wq-exit.c +131 -0
- data/vendor/liburing/test/iowait.c +1 -1
- data/vendor/liburing/test/min-timeout.c +3 -1
- data/vendor/liburing/test/open-close.c +39 -0
- data/vendor/liburing/test/poll-update-trigger.c +85 -0
- data/vendor/liburing/test/recvsend_bundle.c +14 -11
- data/vendor/liburing/test/sendzc-bug.c +146 -0
- data/vendor/liburing/test/sqe-mixed-nop.c +151 -7
- data/vendor/liburing/test/test.h +2 -0
- data/vendor/liburing/test/timestamp-bug.c +135 -0
- data/vendor/liburing/test/timestamp.c +5 -0
- data/vendor/liburing/test/vec-regbuf.c +136 -1
- metadata +50 -284
- data/vendor/libressl/.github/scripts/changelog.sh +0 -74
- data/vendor/libressl/.github/workflows/android.yml +0 -35
- data/vendor/libressl/.github/workflows/cifuzz.yml +0 -33
- data/vendor/libressl/.github/workflows/cmake-config.yml +0 -98
- data/vendor/libressl/.github/workflows/coverity.yml +0 -69
- data/vendor/libressl/.github/workflows/emscripten.yml +0 -71
- data/vendor/libressl/.github/workflows/fedora-rawhide.yml +0 -39
- data/vendor/libressl/.github/workflows/freebsd.yml +0 -71
- data/vendor/libressl/.github/workflows/linux.yml +0 -71
- data/vendor/libressl/.github/workflows/macos.yml +0 -37
- data/vendor/libressl/.github/workflows/release.yml +0 -81
- data/vendor/libressl/.github/workflows/rust-openssl.yml +0 -47
- data/vendor/libressl/.github/workflows/solaris.yml +0 -37
- data/vendor/libressl/.github/workflows/windows.yml +0 -70
- data/vendor/libressl/.gitignore +0 -333
- data/vendor/libressl/CMakeLists.txt +0 -581
- data/vendor/libressl/COPYING +0 -133
- data/vendor/libressl/ChangeLog +0 -3280
- data/vendor/libressl/FindLibreSSL.cmake +0 -232
- data/vendor/libressl/LibreSSLConfig.cmake.in +0 -36
- data/vendor/libressl/Makefile.am +0 -60
- data/vendor/libressl/Makefile.am.common +0 -20
- data/vendor/libressl/OPENBSD_BRANCH +0 -1
- data/vendor/libressl/README.md +0 -238
- data/vendor/libressl/README.mingw.md +0 -43
- data/vendor/libressl/apps/CMakeLists.txt +0 -18
- data/vendor/libressl/apps/Makefile.am +0 -5
- data/vendor/libressl/apps/nc/CMakeLists.txt +0 -67
- data/vendor/libressl/apps/nc/Makefile.am +0 -64
- data/vendor/libressl/apps/nc/compat/accept4.c +0 -17
- data/vendor/libressl/apps/nc/compat/readpassphrase.c +0 -205
- data/vendor/libressl/apps/nc/compat/socket.c +0 -29
- data/vendor/libressl/apps/nc/compat/sys/socket.h +0 -30
- data/vendor/libressl/apps/ocspcheck/CMakeLists.txt +0 -44
- data/vendor/libressl/apps/ocspcheck/Makefile.am +0 -45
- data/vendor/libressl/apps/ocspcheck/compat/.gitignore +0 -0
- data/vendor/libressl/apps/openssl/CMakeLists.txt +0 -97
- data/vendor/libressl/apps/openssl/Makefile.am +0 -108
- data/vendor/libressl/apps/openssl/apps_win.c +0 -138
- data/vendor/libressl/apps/openssl/certhash_win.c +0 -13
- data/vendor/libressl/apps/openssl/compat/clock_gettime_osx.c +0 -26
- data/vendor/libressl/apps/openssl/compat/poll_win.c +0 -329
- data/vendor/libressl/appveyor.yml +0 -53
- data/vendor/libressl/autogen.sh +0 -15
- data/vendor/libressl/check-release.sh +0 -86
- data/vendor/libressl/cmake_export_symbol.cmake +0 -71
- data/vendor/libressl/cmake_uninstall.cmake.in +0 -36
- data/vendor/libressl/config +0 -17
- data/vendor/libressl/configure.ac +0 -165
- data/vendor/libressl/crypto/CMakeLists.txt +0 -863
- data/vendor/libressl/crypto/Makefile.am +0 -962
- data/vendor/libressl/crypto/Makefile.am.arc4random +0 -46
- data/vendor/libressl/crypto/Makefile.am.elf-mips +0 -14
- data/vendor/libressl/crypto/Makefile.am.elf-mips64 +0 -14
- data/vendor/libressl/crypto/Makefile.am.elf-x86_64 +0 -35
- data/vendor/libressl/crypto/Makefile.am.macosx-x86_64 +0 -35
- data/vendor/libressl/crypto/Makefile.am.masm-x86_64 +0 -22
- data/vendor/libressl/crypto/Makefile.am.mingw64-x86_64 +0 -23
- data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_darwin.c +0 -60
- data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_linux.c +0 -62
- data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_none.c +0 -26
- data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_windows.c +0 -36
- data/vendor/libressl/crypto/arch/loongarch64/crypto_arch.h +0 -21
- data/vendor/libressl/crypto/arch/mips/crypto_arch.h +0 -21
- data/vendor/libressl/crypto/bn/arch/loongarch64/bn_arch.h +0 -23
- data/vendor/libressl/crypto/bn/arch/mips/bn_arch.h +0 -24
- data/vendor/libressl/crypto/compat/.gitignore +0 -31
- data/vendor/libressl/crypto/compat/arc4random.h +0 -41
- data/vendor/libressl/crypto/compat/b_win.c +0 -55
- data/vendor/libressl/crypto/compat/bsd-asprintf.c +0 -96
- data/vendor/libressl/crypto/compat/crypto_lock_win.c +0 -56
- data/vendor/libressl/crypto/compat/explicit_bzero_win.c +0 -13
- data/vendor/libressl/crypto/compat/freezero.c +0 -32
- data/vendor/libressl/crypto/compat/getdelim.c +0 -78
- data/vendor/libressl/crypto/compat/getline.c +0 -40
- data/vendor/libressl/crypto/compat/getopt_long.c +0 -528
- data/vendor/libressl/crypto/compat/getpagesize.c +0 -18
- data/vendor/libressl/crypto/compat/getprogname_linux.c +0 -23
- data/vendor/libressl/crypto/compat/getprogname_unimpl.c +0 -7
- data/vendor/libressl/crypto/compat/getprogname_windows.c +0 -13
- data/vendor/libressl/crypto/compat/posix_win.c +0 -296
- data/vendor/libressl/crypto/compat/syslog_r.c +0 -19
- data/vendor/libressl/crypto/compat/ui_openssl_win.c +0 -334
- data/vendor/libressl/dist.sh +0 -22
- data/vendor/libressl/gen-coverage-report.sh +0 -58
- data/vendor/libressl/gen-openbsd-tags.sh +0 -20
- data/vendor/libressl/include/CMakeLists.txt +0 -61
- data/vendor/libressl/include/Makefile.am +0 -79
- data/vendor/libressl/include/arch/loongarch64/opensslconf.h +0 -150
- data/vendor/libressl/include/arch/mips/opensslconf.h +0 -150
- data/vendor/libressl/include/compat/arpa/inet.h +0 -15
- data/vendor/libressl/include/compat/arpa/nameser.h +0 -25
- data/vendor/libressl/include/compat/cet.h +0 -19
- data/vendor/libressl/include/compat/dirent.h +0 -17
- data/vendor/libressl/include/compat/dirent_msvc.h +0 -611
- data/vendor/libressl/include/compat/endian.h +0 -161
- data/vendor/libressl/include/compat/err.h +0 -95
- data/vendor/libressl/include/compat/fcntl.h +0 -32
- data/vendor/libressl/include/compat/getopt.h +0 -50
- data/vendor/libressl/include/compat/limits.h +0 -25
- data/vendor/libressl/include/compat/netdb.h +0 -10
- data/vendor/libressl/include/compat/netinet/in.h +0 -19
- data/vendor/libressl/include/compat/netinet/ip.h +0 -49
- data/vendor/libressl/include/compat/netinet/tcp.h +0 -10
- data/vendor/libressl/include/compat/poll.h +0 -63
- data/vendor/libressl/include/compat/pthread.h +0 -122
- data/vendor/libressl/include/compat/readpassphrase.h +0 -44
- data/vendor/libressl/include/compat/resolv.h +0 -24
- data/vendor/libressl/include/compat/stdint.h +0 -31
- data/vendor/libressl/include/compat/stdio.h +0 -65
- data/vendor/libressl/include/compat/stdlib.h +0 -57
- data/vendor/libressl/include/compat/string.h +0 -98
- data/vendor/libressl/include/compat/sys/_null.h +0 -18
- data/vendor/libressl/include/compat/sys/ioctl.h +0 -11
- data/vendor/libressl/include/compat/sys/mman.h +0 -19
- data/vendor/libressl/include/compat/sys/param.h +0 -15
- data/vendor/libressl/include/compat/sys/queue.h +0 -536
- data/vendor/libressl/include/compat/sys/select.h +0 -10
- data/vendor/libressl/include/compat/sys/socket.h +0 -18
- data/vendor/libressl/include/compat/sys/stat.h +0 -129
- data/vendor/libressl/include/compat/sys/time.h +0 -37
- data/vendor/libressl/include/compat/sys/tree.h +0 -1006
- data/vendor/libressl/include/compat/sys/types.h +0 -69
- data/vendor/libressl/include/compat/sys/uio.h +0 -17
- data/vendor/libressl/include/compat/syslog.h +0 -38
- data/vendor/libressl/include/compat/time.h +0 -59
- data/vendor/libressl/include/compat/unistd.h +0 -83
- data/vendor/libressl/include/compat/win32netcompat.h +0 -57
- data/vendor/libressl/include/openssl/Makefile.am.tpl +0 -45
- data/vendor/libressl/libcrypto.pc.in +0 -28
- data/vendor/libressl/libressl.pub +0 -2
- data/vendor/libressl/libssl.pc.in +0 -28
- data/vendor/libressl/libtls.pc.in +0 -28
- data/vendor/libressl/m4/ax_add_fortify_source.m4 +0 -80
- data/vendor/libressl/m4/ax_check_compile_flag.m4 +0 -53
- data/vendor/libressl/m4/check-hardening-options.m4 +0 -110
- data/vendor/libressl/m4/check-libc.m4 +0 -189
- data/vendor/libressl/m4/check-os-options.m4 +0 -181
- data/vendor/libressl/m4/disable-compiler-warnings.m4 +0 -44
- data/vendor/libressl/man/CMakeLists.txt +0 -26
- data/vendor/libressl/man/links +0 -2780
- data/vendor/libressl/man/update_links.sh +0 -25
- data/vendor/libressl/openssl.pc.in +0 -11
- data/vendor/libressl/patches/bn_shift.patch +0 -34
- data/vendor/libressl/patches/crypto_arch.h.patch +0 -34
- data/vendor/libressl/patches/crypto_namespace.h.patch +0 -22
- data/vendor/libressl/patches/netcat.c.patch +0 -178
- data/vendor/libressl/patches/openssl.c.patch +0 -12
- data/vendor/libressl/patches/opensslfeatures.h.patch +0 -49
- data/vendor/libressl/patches/patch-amd64-crypto-cpu-caps.c.patch +0 -20
- data/vendor/libressl/patches/patch-i386-crypto-cpu-caps.c.patch +0 -20
- data/vendor/libressl/patches/speed.c.patch +0 -114
- data/vendor/libressl/patches/ssl_namespace.h.patch +0 -21
- data/vendor/libressl/patches/tls.h.patch +0 -16
- data/vendor/libressl/patches/tls_config.c.patch +0 -15
- data/vendor/libressl/patches/win32_amd64_bn_arch.h.patch +0 -28
- data/vendor/libressl/patches/windows_headers.patch +0 -80
- data/vendor/libressl/scripts/config.guess +0 -1774
- data/vendor/libressl/scripts/config.sub +0 -1907
- data/vendor/libressl/scripts/i686-w64-mingw32.cmake +0 -9
- data/vendor/libressl/scripts/test +0 -210
- data/vendor/libressl/scripts/wrap-compiler-for-flag-check +0 -31
- data/vendor/libressl/scripts/x86_64-w64-mingw32.cmake +0 -9
- data/vendor/libressl/ssl/CMakeLists.txt +0 -183
- data/vendor/libressl/ssl/Makefile.am +0 -187
- data/vendor/libressl/tests/CMakeLists.txt +0 -970
- data/vendor/libressl/tests/Makefile.am +0 -944
- data/vendor/libressl/tests/aeadtest.sh +0 -30
- data/vendor/libressl/tests/arc4randomforktest.sh +0 -21
- data/vendor/libressl/tests/asn1time_small.test +0 -10
- data/vendor/libressl/tests/cmake/CMakeLists.txt +0 -52
- data/vendor/libressl/tests/cmake/crypto.c +0 -7
- data/vendor/libressl/tests/cmake/ssl.c +0 -6
- data/vendor/libressl/tests/cmake/tls.c +0 -6
- data/vendor/libressl/tests/compat/pipe2.c +0 -186
- data/vendor/libressl/tests/dtlstest.sh +0 -28
- data/vendor/libressl/tests/evptest.sh +0 -22
- data/vendor/libressl/tests/keypairtest.sh +0 -27
- data/vendor/libressl/tests/mlkem_tests.sh +0 -39
- data/vendor/libressl/tests/ocsptest.bat +0 -25
- data/vendor/libressl/tests/ocsptest.sh +0 -23
- data/vendor/libressl/tests/openssl.cnf +0 -29
- data/vendor/libressl/tests/optionstest.c +0 -381
- data/vendor/libressl/tests/pidwraptest.c +0 -85
- data/vendor/libressl/tests/pidwraptest.sh +0 -26
- data/vendor/libressl/tests/quictest.bat +0 -27
- data/vendor/libressl/tests/quictest.sh +0 -30
- data/vendor/libressl/tests/renegotiation_test.bat +0 -27
- data/vendor/libressl/tests/renegotiation_test.sh +0 -30
- data/vendor/libressl/tests/rfc5280time_small.test +0 -10
- data/vendor/libressl/tests/servertest.bat +0 -27
- data/vendor/libressl/tests/servertest.sh +0 -30
- data/vendor/libressl/tests/shutdowntest.bat +0 -27
- data/vendor/libressl/tests/shutdowntest.sh +0 -30
- data/vendor/libressl/tests/ssltest.bat +0 -32
- data/vendor/libressl/tests/ssltest.sh +0 -48
- data/vendor/libressl/tests/testdsa.bat +0 -47
- data/vendor/libressl/tests/testdsa.sh +0 -57
- data/vendor/libressl/tests/testenc.bat +0 -85
- data/vendor/libressl/tests/testenc.sh +0 -93
- data/vendor/libressl/tests/testrsa.bat +0 -47
- data/vendor/libressl/tests/testrsa.sh +0 -57
- data/vendor/libressl/tests/testssl.bat +0 -171
- data/vendor/libressl/tests/tlstest.bat +0 -27
- data/vendor/libressl/tests/tlstest.sh +0 -28
- data/vendor/libressl/tls/CMakeLists.txt +0 -125
- data/vendor/libressl/tls/Makefile.am +0 -76
- data/vendor/libressl/tls/compat/ftruncate.c +0 -17
- data/vendor/libressl/tls/compat/pread.c +0 -29
- data/vendor/libressl/tls/compat/pwrite.c +0 -29
- data/vendor/libressl/update.sh +0 -460
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 162f747c9286305e5bba72e0ab5c3d0d89c9a0ff42e1480b4c247a05dab0c2f3
|
|
4
|
+
data.tar.gz: 41ebc4a248a204f898d6d4cc954405b441c533109f08cae2806a0204bd1726aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d99daa2b45df0c28f9d087e19ce92678f78b76c551d47a5c55d93188a881b347a3d87f49cb93dc10686c5c89726fbc97b40e656cbcb09becbd53eeccc790e435
|
|
7
|
+
data.tar.gz: ba9f0408ac9157e82dfd34595d73d5e924a58cf8db0ee76971c5675b44c89a1ace5219e569c3a21ceff6e51439d39814f9a1f2a0314a2506bbde9169679c6707
|
data/.github/workflows/test.yml
CHANGED
data/.gitignore
CHANGED
data/.gitmodules
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# 0.25.0 2026-02-10
|
|
2
|
+
|
|
3
|
+
- Add Yard docs
|
|
4
|
+
- Add `UM::STDIN_FILENO`, `UM::STDOUT_FILENO`, `UM::STDERR_FILENO` constants
|
|
5
|
+
- Mark fibers as non-blocking in `#spin`
|
|
6
|
+
- Use `Set` instead of `Hash` for holding machine's fiber list
|
|
7
|
+
- Add inotify API, `#file_watch` convenience method
|
|
8
|
+
- Add SSL functionality: `#ssl_set_bio`, `#ssl_read`, `#ssl_write`
|
|
9
|
+
|
|
10
|
+
# 0.24.0 2026-01-30
|
|
11
|
+
|
|
12
|
+
- Add `Stream.resp_encode_cmd`
|
|
13
|
+
- Add sidecar mode
|
|
14
|
+
- Add test mode, remove special handling of OP_SCHEDULE in um_switch, do it only
|
|
15
|
+
in test mode
|
|
16
|
+
- Improve fiber scheduler error handling, add tests for I/O errors
|
|
17
|
+
|
|
1
18
|
# 0.23.1 2025-12-16
|
|
2
19
|
|
|
3
20
|
- Add `MSG_NOSIGNAL` to default flags for `#sendv` and `#send_bundle`
|
data/Gemfile
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
source 'https://
|
|
1
|
+
source 'https://gem.coop'
|
|
2
2
|
|
|
3
3
|
gemspec
|
|
4
|
+
|
|
5
|
+
group :development do
|
|
6
|
+
gem 'localhost'
|
|
7
|
+
gem 'rake-compiler', '~>1.3.0'
|
|
8
|
+
gem 'minitest', '~>6.0.1'
|
|
9
|
+
gem 'benchmark'
|
|
10
|
+
gem 'benchmark-ips'
|
|
11
|
+
gem 'http_parser.rb', '~>0.8.0'
|
|
12
|
+
gem 'yard'
|
|
13
|
+
gem 'irb'
|
|
14
|
+
end
|
data/README.md
CHANGED
|
@@ -1,139 +1,293 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<a href="
|
|
10
|
-
|
|
11
|
-
</a>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<br>
|
|
3
|
+
UringMachine
|
|
4
|
+
</h1>
|
|
5
|
+
|
|
6
|
+
<h4 align="center">Ruby on io_uring!</h4>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="http://rubygems.org/gems/uringmachine">
|
|
10
|
+
<img src="https://badge.fury.io/rb/uringmachine.svg" alt="Ruby gem">
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://github.com/digital-fabric/uringmachine/actions">
|
|
13
|
+
<img src="https://github.com/digital-fabric/uringmachine/actions/workflows/test.yml/badge.svg" alt="Tests">
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://github.com/digital-fabric/uringmachine/blob/master/LICENSE">
|
|
16
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
|
|
17
|
+
</a>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="https://www.rubydoc.info/gems/uringmachine">API reference</a>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
## What is UringMachine?
|
|
25
|
+
|
|
26
|
+
UringMachine is a Ruby gem for building fiber-based concurrent Ruby apps running
|
|
27
|
+
on Linux and using io_uring for performing I/O. UringMachine provides a
|
|
28
|
+
low-level API for performing concurrent I/O, as well as a full-featured
|
|
29
|
+
[`Fiber::Scheduler`](https://docs.ruby-lang.org/en/master/Fiber/Scheduler.html)
|
|
30
|
+
implementation that allows integration with the entire Ruby ecosystem.
|
|
16
31
|
|
|
17
32
|
## Features
|
|
18
33
|
|
|
19
|
-
- Automatic fiber switching when performing blocking operations.
|
|
34
|
+
- Automatic fiber switching when performing blocking I/O operations.
|
|
20
35
|
- Automatic cancellation using of ongoing operations with Ruby exceptions.
|
|
21
36
|
- General-purpose API for cancelling any operation on timeout.
|
|
22
|
-
-
|
|
23
|
-
-
|
|
37
|
+
- Excellent performance characteristics for concurrent I/O-bound applications.
|
|
38
|
+
- `Fiber::Scheduler` implementation to automatically integrate with the Ruby
|
|
39
|
+
ecosystem in a transparent fashion.
|
|
24
40
|
|
|
25
41
|
## Design
|
|
26
42
|
|
|
27
|
-
UringMachine is
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Some important learnings from those two projects, in no particular order:
|
|
38
|
-
|
|
39
|
-
- Monkey-patching is not a good solution, long term. You need to deal with
|
|
40
|
-
changing APIs (Ruby is evolving quite rapidly these days!), and anyways you're
|
|
41
|
-
always going to get stuck with some standard Ruby API that's implemented as a
|
|
42
|
-
C extension and just won't play nice with whatever you're trying to do.
|
|
43
|
-
- The design of the Polyphony io_uring backend was an evolution of something
|
|
44
|
-
that was originally based on libev as an event loop. In hindsight, adapting
|
|
45
|
-
the design for how io_uring worked led to code that was too complex and even
|
|
46
|
-
somewhat brittle.
|
|
47
|
-
- IOU showed me that even if we embrace callbacks, the developer experience is
|
|
48
|
-
substantially inferior to what you can do with a sequential coding style. Even
|
|
49
|
-
just in terms of line count - with callbacks you end up with roughly double
|
|
50
|
-
the number of lines of code.
|
|
51
|
-
- Implementing fiber switching on top of IOU was disappointing in terms of
|
|
52
|
-
performance. In order for a fiber-based solution to be performed it had to be
|
|
53
|
-
baked in - hence UringMachine.
|
|
54
|
-
- Working with fibers has the very important benefit that you can keep stuff on
|
|
55
|
-
the stack, instead of passing around all kinds of references to the heap. In
|
|
56
|
-
addition, you mostly don't need to worry about marking Ruby objects used in
|
|
57
|
-
operations, since normally they'll already be on the stack as method call
|
|
58
|
-
parameters.
|
|
59
|
-
- Polyphony was designed as an all-in-one solution that did everything: turning
|
|
60
|
-
stock APIs into fiber-aware ones, providing a solid structured-concurrency
|
|
61
|
-
implementation for controlling fiber life times, extensions providing
|
|
62
|
-
additional features such as compressing streaming data between two fds, other
|
|
63
|
-
APIs based on splicing etc. Perhaps a more cautious approach would be better.
|
|
64
|
-
- Pending operation lifetime management in Polyphony was based a complex
|
|
65
|
-
reference counting scheme that proved problematic, especially for multishot
|
|
66
|
-
operations.
|
|
67
|
-
|
|
68
|
-
So, based on those two projects, I wanted to design a Ruby API for io_uring
|
|
69
|
-
based on the following principles:
|
|
70
|
-
|
|
71
|
-
- Automatic fiber switching.
|
|
72
|
-
- No monkey-patching. Instead, provide a simple custom API, as a replacement for
|
|
73
|
-
the stock Ruby `IO` and `Socket` classes.
|
|
74
|
-
- Simpler management of pending operation lifetime.
|
|
75
|
-
- Do not insist on structured concurrency, just provide the APIs necessary to
|
|
76
|
-
create actors and to supervise the execution of fibers.
|
|
77
|
-
|
|
78
|
-
### Cancellation
|
|
79
|
-
|
|
80
|
-
When working with io_uring, managing the life cycle of asynchronous operations
|
|
81
|
-
is quite tricky, especially with regards to cancellation. This is due to the
|
|
82
|
-
fact each operation lives on both sides of the userspace-kernel divide. This
|
|
83
|
-
means that when cancelling an operation, we cannot free, or dispose of any
|
|
84
|
-
resources associated with the operation, until we know for sure that the kernel
|
|
85
|
-
side is also done with the operation.
|
|
86
|
-
|
|
87
|
-
As stated above, working with fibers allows us to keep operation metadata and
|
|
88
|
-
associated data (such as buffers etc) on the stack, which can greatly simplify
|
|
89
|
-
the managing of the operation's lifetime, as well as significantly reduce heap
|
|
90
|
-
allocations.
|
|
91
|
-
|
|
92
|
-
When a cancellation does occur, UringMachine issues a cancellation (using
|
|
93
|
-
`io_uring_prep_cancel64`), and then waits for the corresponding CQE (with a
|
|
94
|
-
`-ECANCELED` result).
|
|
95
|
-
|
|
96
|
-
## Short Example
|
|
43
|
+
In UringMachine, an I/O operation is performed by submitting it to the io_uring
|
|
44
|
+
interface (using the io_uring submission queue, or SQ) and waiting for a
|
|
45
|
+
corresponding entry to be added to the completion queue, or CQ. Since
|
|
46
|
+
UringMachine implements fiber-based concurrency, the fiber that performs the I/O
|
|
47
|
+
yields control after submitting the operation, and when a completion is
|
|
48
|
+
received, the fiber is scheduled to be resumed by putting it on the so-called
|
|
49
|
+
"runqueue", which is a queue of fibers ready to be resumed. When the runqueue is
|
|
50
|
+
exhausted, UringMachine enters the kernel in order to wait for one or more I/O
|
|
51
|
+
operation completions.
|
|
97
52
|
|
|
98
|
-
|
|
99
|
-
|
|
53
|
+
As a general rule, a single UringMachine instance is used for per thread,
|
|
54
|
+
managing the switching between the different fibers created on that same thread.
|
|
55
|
+
In addition, a UringMachine-based fiber scheduler may be installed in order to
|
|
56
|
+
allow any library that performs I/O using standard-library classes such as `IO`,
|
|
57
|
+
`TCPSocket` or `OpenSSL::SSL::SSLSocket`, and higher-level abstractions such as
|
|
58
|
+
`Net::HTTP` to perform I/O using UringMachine.
|
|
100
59
|
|
|
60
|
+
## Getting Started
|
|
61
|
+
|
|
62
|
+
To install UringMachine, simply run `gem install uringmachine` or `bundle add
|
|
63
|
+
uringmachine` in your project directory. Note: to use UringMachine, you'll need
|
|
64
|
+
a Linux machine with a minimum kernel version of 6.7. Some features require
|
|
65
|
+
newer kernel versions.
|
|
66
|
+
|
|
67
|
+
To perform I/O using UringMachine, simply create an instance:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
101
70
|
machine = UringMachine.new
|
|
102
|
-
stdout_fd = STDOUT.fileno
|
|
103
|
-
stdin_fd = STDIN.fileno
|
|
104
|
-
machine.write(stdout_fd, "Hello, world!\n")
|
|
105
71
|
|
|
106
|
-
|
|
107
|
-
|
|
72
|
+
# or alternatively
|
|
73
|
+
machine = UM.new
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
You can perform I/O by directly making method calls such as `write` or `read`
|
|
77
|
+
(for the full API see the reference.):
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
# Most UringMachine instance methods will need you to provide a file descriptor.
|
|
81
|
+
# Here we print a message to STDOUT. Note the explicit line break:
|
|
82
|
+
machine.write(STDOUT, "Hello, world!\n")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
UringMachine provides an I/O interface that is to a large degree equivalent to
|
|
86
|
+
the Unix standard C interface:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# Constants used for the different I/O APIs are available under the
|
|
90
|
+
# UringMachine, or UM namespace.
|
|
91
|
+
fd = machine.open('foo.txt', UM::O_RDONLY)
|
|
92
|
+
buf = +''
|
|
93
|
+
size = machine.read(fd, buf, 8192)
|
|
94
|
+
machine.write(STDOUT, "File content: #{buf.inspect}")
|
|
95
|
+
machine.close(fd)
|
|
96
|
+
|
|
97
|
+
# Or alternatively (with automatic file closing):
|
|
98
|
+
machine.open('foo.txt', UM::O_RDONLY) do |fd|
|
|
99
|
+
buf = +''
|
|
100
|
+
size = machine.read(fd, buf, 8192)
|
|
101
|
+
machine.write(STDOUT, "File content: #{buf.inspect}")
|
|
102
|
+
end
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Fiber control
|
|
106
|
+
|
|
107
|
+
To perform I/O operations concurrently, you can spin up new fibers by calling
|
|
108
|
+
`#spin`. You can wait for a fiber to terminate by calling `#join`:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# This creates a pipe and returns the file descriptors for its read and write
|
|
112
|
+
# ends.
|
|
113
|
+
r_fd, w_fd = UM.pipe
|
|
114
|
+
|
|
115
|
+
# read from pipe
|
|
116
|
+
read_fiber = machine.spin do
|
|
108
117
|
buf = +''
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
loop do
|
|
119
|
+
len = machine.read(r_fd, buf, 8192)
|
|
120
|
+
break if len == 0
|
|
121
|
+
|
|
122
|
+
# print to STDOUT
|
|
123
|
+
machine.write(UM::STDOUT_FILENO, "#{buf}\n")
|
|
114
124
|
end
|
|
115
125
|
end
|
|
126
|
+
|
|
127
|
+
write_fiber = machine.spin do
|
|
128
|
+
(1..10).each do |count|
|
|
129
|
+
machine.sleep(1)
|
|
130
|
+
machine.write(w_fd, "#{count} Mississipi")
|
|
131
|
+
end
|
|
132
|
+
machine.close(w_fd)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Wait for both fibers to finish running
|
|
136
|
+
machine.join(read_fiber, write_fiber)
|
|
116
137
|
```
|
|
117
138
|
|
|
118
|
-
|
|
139
|
+
You can also terminate a fiber by scheduling it manually. Normally this would be
|
|
140
|
+
done using an exception, which would cause the fiber to cancel whatever
|
|
141
|
+
operation it is currently waiting for, and run any `rescue` or `ensure` block:
|
|
119
142
|
|
|
120
|
-
|
|
143
|
+
```ruby
|
|
144
|
+
sleep_fiber = machine.spin do
|
|
145
|
+
puts "Going to sleep..."
|
|
146
|
+
machine.sleep(3)
|
|
147
|
+
puts "Done sleeping."
|
|
148
|
+
rescue => e
|
|
149
|
+
puts "Got error: #{e.inspect}"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Let sleep_fiber start running
|
|
153
|
+
machine.sleep(0.1)
|
|
154
|
+
machine.schedule(sleep_fiber, RuntimeError.new('Cancel!'))
|
|
155
|
+
machine.join(sleep_fiber)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Synchronization primitives
|
|
159
|
+
|
|
160
|
+
UringMachine also includes a io_uring-based implementation of a queue and a
|
|
161
|
+
mutex. `UM::Mutex` can be used for synchronizing access to a protected resource,
|
|
162
|
+
for example a database connection:
|
|
121
163
|
|
|
122
164
|
```ruby
|
|
123
|
-
|
|
165
|
+
class DBConnection
|
|
166
|
+
def initialize(machine, db)
|
|
167
|
+
@machine = machine
|
|
168
|
+
@db = db
|
|
169
|
+
@mutex = UM::Mutex.new
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def query(sql)
|
|
173
|
+
@machine.synchronize(@mutex) do
|
|
174
|
+
@db.query(sql)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
A queue can be used to coordinate between multiple fibers, for example a fiber
|
|
180
|
+
that consumes data and a fiber that produces data:
|
|
124
181
|
|
|
125
|
-
|
|
182
|
+
```ruby
|
|
183
|
+
queue = UM::Queue.new
|
|
126
184
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
185
|
+
producer = machine.spin do
|
|
186
|
+
10.times do
|
|
187
|
+
# lazy producer wants to sleep a bit
|
|
188
|
+
machine.sleep(rand(0.1..1.5))
|
|
189
|
+
machine.push(queue, rand(1000))
|
|
190
|
+
end
|
|
191
|
+
machine.push(queue, :STOP)
|
|
131
192
|
end
|
|
132
193
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
194
|
+
consumer = machine.spin do
|
|
195
|
+
sum = 0
|
|
196
|
+
loop do
|
|
197
|
+
# the call to #shift blocks if the queue is empty
|
|
198
|
+
value = machine.shift(queue)
|
|
199
|
+
break if value == :STOP
|
|
200
|
+
|
|
201
|
+
sum += value
|
|
137
202
|
end
|
|
203
|
+
puts "Sum: #{sum}"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
machine.join(producer, consumer)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Note: to use the regular Ruby `Mutex` and `Queue` together with UringMachine,
|
|
210
|
+
you'll need to set up a fiber scheduler (see below).
|
|
211
|
+
|
|
212
|
+
## Sleeping and Working with Timeouts
|
|
213
|
+
|
|
214
|
+
The `#sleep` method allows a fiber to sleep for a period of time:
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
puts "Sleeping"
|
|
218
|
+
machine.sleep(1)
|
|
219
|
+
puts "Done sleeping"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
You can also perform operations periodically by calling `#periodically`:
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
machine.spin do
|
|
226
|
+
# This runs an infinite loop, invoking the block every 200 msecs
|
|
227
|
+
machine.periodically(0.2) do
|
|
228
|
+
machine.write(fd, "Hello")
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
UringMachine also provides a uniform API for implementing timeouts. To add a
|
|
234
|
+
timeout to an operation, you need to wrap it with a call to `#timeout`:
|
|
235
|
+
|
|
236
|
+
```ruby
|
|
237
|
+
class TOError < StandardError; end;
|
|
238
|
+
|
|
239
|
+
# timeout after 3 seconds
|
|
240
|
+
machine.timeout(3, TOError) do
|
|
241
|
+
# wait to shift an item from the queue
|
|
242
|
+
value = machine.shift(queue)
|
|
243
|
+
rescue TOError
|
|
244
|
+
value = nil
|
|
138
245
|
end
|
|
139
246
|
```
|
|
247
|
+
|
|
248
|
+
## The Fiber Scheduler
|
|
249
|
+
|
|
250
|
+
In order to allow UringMachine to integrate with the rest of the Ruby ecosystem,
|
|
251
|
+
and act as the underlying I/O layer, UringMachine includes a full-featured
|
|
252
|
+
implementation of the `Fiber::Scheduler` interface.
|
|
253
|
+
|
|
254
|
+
Note: in order to benefit a the fiber scheduler you'll need to create so-called
|
|
255
|
+
"non-blocking" fibers. This is usually achieved automatically in app servers
|
|
256
|
+
such as [Falcon](https://github.com/socketry/falcon/).
|
|
257
|
+
|
|
258
|
+
To start a fiber scheduler, you need to create an instance of
|
|
259
|
+
`UringMachine::FiberScheduler` for each thread where you'll be doing fiber-based
|
|
260
|
+
concurrent I/O:
|
|
261
|
+
|
|
262
|
+
```ruby
|
|
263
|
+
machine = UM.new
|
|
264
|
+
scheduler = UM::FiberScheduler.new(machine)
|
|
265
|
+
Fiber.set_scheduler(scheduler)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Once the scheduler in place, it's going to handle any I/O or other blocking
|
|
269
|
+
operation (such as sleeping, or locking a mutex, or waiting for a thread to
|
|
270
|
+
terminate) by offloading the operations to the underlying UringMachine instance,
|
|
271
|
+
*provided the I/O is performed inside of a non-blocking fiber. A non-blocking
|
|
272
|
+
fiber can be started either using `UringMachine#spin` or alternatively,
|
|
273
|
+
`Fiber.schedule`:
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
machine = UM.new
|
|
277
|
+
scheduler = UM::FiberScheduler.new(machine)
|
|
278
|
+
Fiber.set_scheduler(scheduler)
|
|
279
|
+
|
|
280
|
+
fiber = Fiber.schedule do
|
|
281
|
+
# this will sleep using underlying UringMachine instance. It is equivalent to
|
|
282
|
+
# calling machine.sleep(0.05)
|
|
283
|
+
sleep(0.05)
|
|
284
|
+
end
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Performance
|
|
288
|
+
|
|
289
|
+
[Detailed benchmarks](benchmark/README.md)
|
|
290
|
+
|
|
291
|
+
## API Reference
|
|
292
|
+
|
|
293
|
+
[API Reference](https://www.rubydoc.info/gems/uringmachine)
|
data/Rakefile
CHANGED
|
@@ -37,3 +37,11 @@ task :release do
|
|
|
37
37
|
puts "Cleaning up..."
|
|
38
38
|
`rm *.gem`
|
|
39
39
|
end
|
|
40
|
+
|
|
41
|
+
require 'yard'
|
|
42
|
+
YARD_FILES = FileList['ext/um/*.c', 'lib/uringmachine.rb', 'lib/uringmachine/**/*.rb']
|
|
43
|
+
|
|
44
|
+
YARD::Rake::YardocTask.new do |t|
|
|
45
|
+
t.files = YARD_FILES
|
|
46
|
+
t.options = %w( --verbose -o yard --readme README.md)
|
|
47
|
+
end
|
data/TODO.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
## immediate
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
- Fix all futex value (Queue, Mutex) to be aligned
|
|
4
|
+
|
|
5
|
+
## Buffer rings - automatic management
|
|
4
6
|
|
|
5
7
|
```ruby
|
|
6
8
|
# completely hands off
|
|
@@ -10,40 +12,62 @@ machine.read_each(fd) { |str| ... }
|
|
|
10
12
|
machine.read_each(fd, io_buffer: true) { |iobuff, len| ... }
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
This is done as vectored IO:
|
|
15
|
+
## Balancing I/O with the runqueue
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
- in some cases where there are many entries in the runqueue, this can
|
|
18
|
+
negatively affect latency. In some cases, this can also lead to I/O
|
|
19
|
+
starvation. If the runqueue is never empty, then SQEs are not submitted and
|
|
20
|
+
CQEs are not processed.
|
|
21
|
+
- So we want to limit the number of consecutive fiber switches before processing
|
|
22
|
+
I/O.
|
|
23
|
+
- Some possible approaches:
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
1. limit consecutive switches with a parameter
|
|
26
|
+
2. limit consecutive switches relative to the runqueue size and/or the amount
|
|
27
|
+
of pending SQEs
|
|
28
|
+
3. an adaptive algorithm that occasionally measures the time between I/O
|
|
29
|
+
processing iterations, and adjusts the consecutive switches limit?
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
```
|
|
31
|
+
- We also want to devise some benchmark that measures throughput / latency with
|
|
32
|
+
different settings, in a situation with very high concurrency.
|
|
26
33
|
|
|
27
34
|
## useful concurrency tools
|
|
28
35
|
|
|
29
36
|
- debounce
|
|
30
37
|
|
|
31
38
|
```ruby
|
|
32
|
-
debouncer =
|
|
39
|
+
debouncer = machine.debounce { }
|
|
33
40
|
```
|
|
34
41
|
|
|
42
|
+
- read multiple files
|
|
35
43
|
|
|
44
|
+
```ruby
|
|
45
|
+
# with a block
|
|
46
|
+
machine.read_files(*fns) { |fn, data| ... }
|
|
47
|
+
|
|
48
|
+
# without a block
|
|
49
|
+
machine.read_files(*fns) #=> { fn1:, fn2:, fn3:, ...}
|
|
50
|
+
```
|
|
36
51
|
|
|
37
52
|
## polyvalent select
|
|
38
53
|
|
|
39
54
|
- select on multiple queues (ala Go)
|
|
40
55
|
- select on mixture of queues and fds
|
|
41
56
|
|
|
42
|
-
|
|
57
|
+
(see also simplified op management below)
|
|
58
|
+
|
|
59
|
+
## simplified op management
|
|
60
|
+
|
|
61
|
+
Op lifecycle management can be much much simpler
|
|
62
|
+
|
|
63
|
+
- make all ops heap-allocated
|
|
64
|
+
- clear up state transitions:
|
|
43
65
|
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
66
|
+
- kernel-side state: unsubmitted, submitted, completed, done (for multishot ops)
|
|
67
|
+
- app-side state: unsubmitted, submitted, ...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## ops
|
|
47
71
|
|
|
48
72
|
- splice / - tee
|
|
49
73
|
- sendto
|
|
@@ -56,7 +80,6 @@ machine.sendv(fd, buf1, buf2, buf3)
|
|
|
56
80
|
- fadvise
|
|
57
81
|
- madvise
|
|
58
82
|
- getxattr / setxattr
|
|
59
|
-
- send_bundle / recv_bundle (kernel >= 6.10)
|
|
60
83
|
|
|
61
84
|
## actors
|
|
62
85
|
|
data/benchmark/bm_io_pipe.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative './common'
|
|
4
4
|
|
|
5
|
-
GROUPS =
|
|
5
|
+
GROUPS = 48
|
|
6
6
|
ITERATIONS = 10000
|
|
7
7
|
|
|
8
8
|
SIZE = 1024
|
|
@@ -52,6 +52,18 @@ class UMBenchmark
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
def do_baseline_um(machine)
|
|
56
|
+
GROUPS.times do
|
|
57
|
+
r, w = UM.pipe
|
|
58
|
+
ITERATIONS.times {
|
|
59
|
+
machine.write(w, DATA)
|
|
60
|
+
machine.read(r, +'', SIZE)
|
|
61
|
+
}
|
|
62
|
+
machine.close(w)
|
|
63
|
+
machine.close(r)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
55
67
|
def do_scheduler(scheduler, ios)
|
|
56
68
|
GROUPS.times do
|
|
57
69
|
r, w = IO.pipe
|
|
@@ -68,6 +80,22 @@ class UMBenchmark
|
|
|
68
80
|
end
|
|
69
81
|
end
|
|
70
82
|
|
|
83
|
+
def do_scheduler_x(div, scheduler, ios)
|
|
84
|
+
(GROUPS/div).times do
|
|
85
|
+
r, w = IO.pipe
|
|
86
|
+
r.sync = true
|
|
87
|
+
w.sync = true
|
|
88
|
+
Fiber.schedule do
|
|
89
|
+
ITERATIONS.times { w.write(DATA) }
|
|
90
|
+
w.close
|
|
91
|
+
end
|
|
92
|
+
Fiber.schedule do
|
|
93
|
+
ITERATIONS.times { r.readpartial(SIZE) }
|
|
94
|
+
r.close
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
71
99
|
def do_um(machine, fibers, fds)
|
|
72
100
|
GROUPS.times do
|
|
73
101
|
r, w = UM.pipe
|
|
@@ -81,4 +109,18 @@ class UMBenchmark
|
|
|
81
109
|
end
|
|
82
110
|
end
|
|
83
111
|
end
|
|
112
|
+
|
|
113
|
+
def do_um_x(div, machine, fibers, fds)
|
|
114
|
+
(GROUPS/div).times do
|
|
115
|
+
r, w = UM.pipe
|
|
116
|
+
fibers << machine.spin do
|
|
117
|
+
ITERATIONS.times { machine.write(w, DATA) }
|
|
118
|
+
machine.close_async(w)
|
|
119
|
+
end
|
|
120
|
+
fibers << machine.spin do
|
|
121
|
+
ITERATIONS.times { machine.read(r, +'', SIZE) }
|
|
122
|
+
machine.close_async(r)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
84
126
|
end
|