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.
Files changed (291) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/.gitignore +1 -0
  4. data/.gitmodules +0 -3
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +12 -1
  7. data/README.md +266 -112
  8. data/Rakefile +8 -0
  9. data/TODO.md +40 -17
  10. data/benchmark/bm_io_pipe.rb +43 -1
  11. data/benchmark/bm_io_socketpair.rb +32 -2
  12. data/benchmark/bm_mutex_io.rb +47 -5
  13. data/benchmark/chart_bm_io_pipe_x.png +0 -0
  14. data/benchmark/common.rb +163 -17
  15. data/benchmark/http_parse.rb +9 -9
  16. data/benchmark/http_server_accept_queue.rb +104 -0
  17. data/benchmark/http_server_multi_accept.rb +93 -0
  18. data/benchmark/http_server_multi_ractor.rb +99 -0
  19. data/benchmark/http_server_single_thread.rb +80 -0
  20. data/benchmark/ips_io_pipe.rb +146 -0
  21. data/benchmark/openssl.rb +77 -0
  22. data/benchmark/openssl_socketpair.rb +112 -0
  23. data/benchmark/sqlite.rb +1 -1
  24. data/docs/design/buffer_pool.md +183 -0
  25. data/docs/um_api.md +91 -0
  26. data/examples/fiber_scheduler_file_io.rb +34 -0
  27. data/examples/fiber_scheduler_file_io_async.rb +33 -0
  28. data/ext/um/extconf.rb +15 -0
  29. data/ext/um/um.c +83 -50
  30. data/ext/um/um.h +18 -3
  31. data/ext/um/um_async_op_class.c +31 -0
  32. data/ext/um/um_class.c +759 -30
  33. data/ext/um/um_const.c +31 -0
  34. data/ext/um/um_mutex_class.c +12 -0
  35. data/ext/um/um_queue_class.c +16 -0
  36. data/ext/um/um_sidecar.c +106 -0
  37. data/ext/um/um_ssl.c +109 -0
  38. data/ext/um/um_stream.c +40 -8
  39. data/ext/um/um_stream_class.c +14 -0
  40. data/ext/um/um_utils.c +3 -4
  41. data/grant-2025/interim-report.md +130 -0
  42. data/grant-2025/journal.md +166 -2
  43. data/grant-2025/tasks.md +32 -20
  44. data/lib/uringmachine/dns_resolver.rb +38 -0
  45. data/lib/uringmachine/fiber_scheduler.rb +42 -32
  46. data/lib/uringmachine/version.rb +1 -1
  47. data/lib/uringmachine.rb +105 -7
  48. data/test/helper.rb +23 -3
  49. data/test/test_fiber.rb +16 -0
  50. data/test/test_fiber_scheduler.rb +221 -72
  51. data/test/test_ssl.rb +85 -0
  52. data/test/test_stream.rb +27 -0
  53. data/test/test_um.rb +250 -26
  54. data/uringmachine.gemspec +1 -7
  55. data/vendor/liburing/examples/send-zerocopy.c +43 -31
  56. data/vendor/liburing/examples/zcrx.c +260 -69
  57. data/vendor/liburing/liburing.spec +1 -1
  58. data/vendor/liburing/src/include/liburing/io_uring.h +12 -0
  59. data/vendor/liburing/src/include/liburing.h +3 -2
  60. data/vendor/liburing/src/liburing-ffi.map +4 -0
  61. data/vendor/liburing/src/liburing.map +4 -0
  62. data/vendor/liburing/src/queue.c +12 -0
  63. data/vendor/liburing/src/register.c +1 -0
  64. data/vendor/liburing/src/setup.c +15 -7
  65. data/vendor/liburing/test/Makefile +8 -4
  66. data/vendor/liburing/test/conn-unreach.c +1 -1
  67. data/vendor/liburing/test/epwait.c +32 -6
  68. data/vendor/liburing/test/io-wq-exit.c +131 -0
  69. data/vendor/liburing/test/iowait.c +1 -1
  70. data/vendor/liburing/test/min-timeout.c +3 -1
  71. data/vendor/liburing/test/open-close.c +39 -0
  72. data/vendor/liburing/test/poll-update-trigger.c +85 -0
  73. data/vendor/liburing/test/recvsend_bundle.c +14 -11
  74. data/vendor/liburing/test/sendzc-bug.c +146 -0
  75. data/vendor/liburing/test/sqe-mixed-nop.c +151 -7
  76. data/vendor/liburing/test/test.h +2 -0
  77. data/vendor/liburing/test/timestamp-bug.c +135 -0
  78. data/vendor/liburing/test/timestamp.c +5 -0
  79. data/vendor/liburing/test/vec-regbuf.c +136 -1
  80. metadata +50 -284
  81. data/vendor/libressl/.github/scripts/changelog.sh +0 -74
  82. data/vendor/libressl/.github/workflows/android.yml +0 -35
  83. data/vendor/libressl/.github/workflows/cifuzz.yml +0 -33
  84. data/vendor/libressl/.github/workflows/cmake-config.yml +0 -98
  85. data/vendor/libressl/.github/workflows/coverity.yml +0 -69
  86. data/vendor/libressl/.github/workflows/emscripten.yml +0 -71
  87. data/vendor/libressl/.github/workflows/fedora-rawhide.yml +0 -39
  88. data/vendor/libressl/.github/workflows/freebsd.yml +0 -71
  89. data/vendor/libressl/.github/workflows/linux.yml +0 -71
  90. data/vendor/libressl/.github/workflows/macos.yml +0 -37
  91. data/vendor/libressl/.github/workflows/release.yml +0 -81
  92. data/vendor/libressl/.github/workflows/rust-openssl.yml +0 -47
  93. data/vendor/libressl/.github/workflows/solaris.yml +0 -37
  94. data/vendor/libressl/.github/workflows/windows.yml +0 -70
  95. data/vendor/libressl/.gitignore +0 -333
  96. data/vendor/libressl/CMakeLists.txt +0 -581
  97. data/vendor/libressl/COPYING +0 -133
  98. data/vendor/libressl/ChangeLog +0 -3280
  99. data/vendor/libressl/FindLibreSSL.cmake +0 -232
  100. data/vendor/libressl/LibreSSLConfig.cmake.in +0 -36
  101. data/vendor/libressl/Makefile.am +0 -60
  102. data/vendor/libressl/Makefile.am.common +0 -20
  103. data/vendor/libressl/OPENBSD_BRANCH +0 -1
  104. data/vendor/libressl/README.md +0 -238
  105. data/vendor/libressl/README.mingw.md +0 -43
  106. data/vendor/libressl/apps/CMakeLists.txt +0 -18
  107. data/vendor/libressl/apps/Makefile.am +0 -5
  108. data/vendor/libressl/apps/nc/CMakeLists.txt +0 -67
  109. data/vendor/libressl/apps/nc/Makefile.am +0 -64
  110. data/vendor/libressl/apps/nc/compat/accept4.c +0 -17
  111. data/vendor/libressl/apps/nc/compat/readpassphrase.c +0 -205
  112. data/vendor/libressl/apps/nc/compat/socket.c +0 -29
  113. data/vendor/libressl/apps/nc/compat/sys/socket.h +0 -30
  114. data/vendor/libressl/apps/ocspcheck/CMakeLists.txt +0 -44
  115. data/vendor/libressl/apps/ocspcheck/Makefile.am +0 -45
  116. data/vendor/libressl/apps/ocspcheck/compat/.gitignore +0 -0
  117. data/vendor/libressl/apps/openssl/CMakeLists.txt +0 -97
  118. data/vendor/libressl/apps/openssl/Makefile.am +0 -108
  119. data/vendor/libressl/apps/openssl/apps_win.c +0 -138
  120. data/vendor/libressl/apps/openssl/certhash_win.c +0 -13
  121. data/vendor/libressl/apps/openssl/compat/clock_gettime_osx.c +0 -26
  122. data/vendor/libressl/apps/openssl/compat/poll_win.c +0 -329
  123. data/vendor/libressl/appveyor.yml +0 -53
  124. data/vendor/libressl/autogen.sh +0 -15
  125. data/vendor/libressl/check-release.sh +0 -86
  126. data/vendor/libressl/cmake_export_symbol.cmake +0 -71
  127. data/vendor/libressl/cmake_uninstall.cmake.in +0 -36
  128. data/vendor/libressl/config +0 -17
  129. data/vendor/libressl/configure.ac +0 -165
  130. data/vendor/libressl/crypto/CMakeLists.txt +0 -863
  131. data/vendor/libressl/crypto/Makefile.am +0 -962
  132. data/vendor/libressl/crypto/Makefile.am.arc4random +0 -46
  133. data/vendor/libressl/crypto/Makefile.am.elf-mips +0 -14
  134. data/vendor/libressl/crypto/Makefile.am.elf-mips64 +0 -14
  135. data/vendor/libressl/crypto/Makefile.am.elf-x86_64 +0 -35
  136. data/vendor/libressl/crypto/Makefile.am.macosx-x86_64 +0 -35
  137. data/vendor/libressl/crypto/Makefile.am.masm-x86_64 +0 -22
  138. data/vendor/libressl/crypto/Makefile.am.mingw64-x86_64 +0 -23
  139. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_darwin.c +0 -60
  140. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_linux.c +0 -62
  141. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_none.c +0 -26
  142. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_windows.c +0 -36
  143. data/vendor/libressl/crypto/arch/loongarch64/crypto_arch.h +0 -21
  144. data/vendor/libressl/crypto/arch/mips/crypto_arch.h +0 -21
  145. data/vendor/libressl/crypto/bn/arch/loongarch64/bn_arch.h +0 -23
  146. data/vendor/libressl/crypto/bn/arch/mips/bn_arch.h +0 -24
  147. data/vendor/libressl/crypto/compat/.gitignore +0 -31
  148. data/vendor/libressl/crypto/compat/arc4random.h +0 -41
  149. data/vendor/libressl/crypto/compat/b_win.c +0 -55
  150. data/vendor/libressl/crypto/compat/bsd-asprintf.c +0 -96
  151. data/vendor/libressl/crypto/compat/crypto_lock_win.c +0 -56
  152. data/vendor/libressl/crypto/compat/explicit_bzero_win.c +0 -13
  153. data/vendor/libressl/crypto/compat/freezero.c +0 -32
  154. data/vendor/libressl/crypto/compat/getdelim.c +0 -78
  155. data/vendor/libressl/crypto/compat/getline.c +0 -40
  156. data/vendor/libressl/crypto/compat/getopt_long.c +0 -528
  157. data/vendor/libressl/crypto/compat/getpagesize.c +0 -18
  158. data/vendor/libressl/crypto/compat/getprogname_linux.c +0 -23
  159. data/vendor/libressl/crypto/compat/getprogname_unimpl.c +0 -7
  160. data/vendor/libressl/crypto/compat/getprogname_windows.c +0 -13
  161. data/vendor/libressl/crypto/compat/posix_win.c +0 -296
  162. data/vendor/libressl/crypto/compat/syslog_r.c +0 -19
  163. data/vendor/libressl/crypto/compat/ui_openssl_win.c +0 -334
  164. data/vendor/libressl/dist.sh +0 -22
  165. data/vendor/libressl/gen-coverage-report.sh +0 -58
  166. data/vendor/libressl/gen-openbsd-tags.sh +0 -20
  167. data/vendor/libressl/include/CMakeLists.txt +0 -61
  168. data/vendor/libressl/include/Makefile.am +0 -79
  169. data/vendor/libressl/include/arch/loongarch64/opensslconf.h +0 -150
  170. data/vendor/libressl/include/arch/mips/opensslconf.h +0 -150
  171. data/vendor/libressl/include/compat/arpa/inet.h +0 -15
  172. data/vendor/libressl/include/compat/arpa/nameser.h +0 -25
  173. data/vendor/libressl/include/compat/cet.h +0 -19
  174. data/vendor/libressl/include/compat/dirent.h +0 -17
  175. data/vendor/libressl/include/compat/dirent_msvc.h +0 -611
  176. data/vendor/libressl/include/compat/endian.h +0 -161
  177. data/vendor/libressl/include/compat/err.h +0 -95
  178. data/vendor/libressl/include/compat/fcntl.h +0 -32
  179. data/vendor/libressl/include/compat/getopt.h +0 -50
  180. data/vendor/libressl/include/compat/limits.h +0 -25
  181. data/vendor/libressl/include/compat/netdb.h +0 -10
  182. data/vendor/libressl/include/compat/netinet/in.h +0 -19
  183. data/vendor/libressl/include/compat/netinet/ip.h +0 -49
  184. data/vendor/libressl/include/compat/netinet/tcp.h +0 -10
  185. data/vendor/libressl/include/compat/poll.h +0 -63
  186. data/vendor/libressl/include/compat/pthread.h +0 -122
  187. data/vendor/libressl/include/compat/readpassphrase.h +0 -44
  188. data/vendor/libressl/include/compat/resolv.h +0 -24
  189. data/vendor/libressl/include/compat/stdint.h +0 -31
  190. data/vendor/libressl/include/compat/stdio.h +0 -65
  191. data/vendor/libressl/include/compat/stdlib.h +0 -57
  192. data/vendor/libressl/include/compat/string.h +0 -98
  193. data/vendor/libressl/include/compat/sys/_null.h +0 -18
  194. data/vendor/libressl/include/compat/sys/ioctl.h +0 -11
  195. data/vendor/libressl/include/compat/sys/mman.h +0 -19
  196. data/vendor/libressl/include/compat/sys/param.h +0 -15
  197. data/vendor/libressl/include/compat/sys/queue.h +0 -536
  198. data/vendor/libressl/include/compat/sys/select.h +0 -10
  199. data/vendor/libressl/include/compat/sys/socket.h +0 -18
  200. data/vendor/libressl/include/compat/sys/stat.h +0 -129
  201. data/vendor/libressl/include/compat/sys/time.h +0 -37
  202. data/vendor/libressl/include/compat/sys/tree.h +0 -1006
  203. data/vendor/libressl/include/compat/sys/types.h +0 -69
  204. data/vendor/libressl/include/compat/sys/uio.h +0 -17
  205. data/vendor/libressl/include/compat/syslog.h +0 -38
  206. data/vendor/libressl/include/compat/time.h +0 -59
  207. data/vendor/libressl/include/compat/unistd.h +0 -83
  208. data/vendor/libressl/include/compat/win32netcompat.h +0 -57
  209. data/vendor/libressl/include/openssl/Makefile.am.tpl +0 -45
  210. data/vendor/libressl/libcrypto.pc.in +0 -28
  211. data/vendor/libressl/libressl.pub +0 -2
  212. data/vendor/libressl/libssl.pc.in +0 -28
  213. data/vendor/libressl/libtls.pc.in +0 -28
  214. data/vendor/libressl/m4/ax_add_fortify_source.m4 +0 -80
  215. data/vendor/libressl/m4/ax_check_compile_flag.m4 +0 -53
  216. data/vendor/libressl/m4/check-hardening-options.m4 +0 -110
  217. data/vendor/libressl/m4/check-libc.m4 +0 -189
  218. data/vendor/libressl/m4/check-os-options.m4 +0 -181
  219. data/vendor/libressl/m4/disable-compiler-warnings.m4 +0 -44
  220. data/vendor/libressl/man/CMakeLists.txt +0 -26
  221. data/vendor/libressl/man/links +0 -2780
  222. data/vendor/libressl/man/update_links.sh +0 -25
  223. data/vendor/libressl/openssl.pc.in +0 -11
  224. data/vendor/libressl/patches/bn_shift.patch +0 -34
  225. data/vendor/libressl/patches/crypto_arch.h.patch +0 -34
  226. data/vendor/libressl/patches/crypto_namespace.h.patch +0 -22
  227. data/vendor/libressl/patches/netcat.c.patch +0 -178
  228. data/vendor/libressl/patches/openssl.c.patch +0 -12
  229. data/vendor/libressl/patches/opensslfeatures.h.patch +0 -49
  230. data/vendor/libressl/patches/patch-amd64-crypto-cpu-caps.c.patch +0 -20
  231. data/vendor/libressl/patches/patch-i386-crypto-cpu-caps.c.patch +0 -20
  232. data/vendor/libressl/patches/speed.c.patch +0 -114
  233. data/vendor/libressl/patches/ssl_namespace.h.patch +0 -21
  234. data/vendor/libressl/patches/tls.h.patch +0 -16
  235. data/vendor/libressl/patches/tls_config.c.patch +0 -15
  236. data/vendor/libressl/patches/win32_amd64_bn_arch.h.patch +0 -28
  237. data/vendor/libressl/patches/windows_headers.patch +0 -80
  238. data/vendor/libressl/scripts/config.guess +0 -1774
  239. data/vendor/libressl/scripts/config.sub +0 -1907
  240. data/vendor/libressl/scripts/i686-w64-mingw32.cmake +0 -9
  241. data/vendor/libressl/scripts/test +0 -210
  242. data/vendor/libressl/scripts/wrap-compiler-for-flag-check +0 -31
  243. data/vendor/libressl/scripts/x86_64-w64-mingw32.cmake +0 -9
  244. data/vendor/libressl/ssl/CMakeLists.txt +0 -183
  245. data/vendor/libressl/ssl/Makefile.am +0 -187
  246. data/vendor/libressl/tests/CMakeLists.txt +0 -970
  247. data/vendor/libressl/tests/Makefile.am +0 -944
  248. data/vendor/libressl/tests/aeadtest.sh +0 -30
  249. data/vendor/libressl/tests/arc4randomforktest.sh +0 -21
  250. data/vendor/libressl/tests/asn1time_small.test +0 -10
  251. data/vendor/libressl/tests/cmake/CMakeLists.txt +0 -52
  252. data/vendor/libressl/tests/cmake/crypto.c +0 -7
  253. data/vendor/libressl/tests/cmake/ssl.c +0 -6
  254. data/vendor/libressl/tests/cmake/tls.c +0 -6
  255. data/vendor/libressl/tests/compat/pipe2.c +0 -186
  256. data/vendor/libressl/tests/dtlstest.sh +0 -28
  257. data/vendor/libressl/tests/evptest.sh +0 -22
  258. data/vendor/libressl/tests/keypairtest.sh +0 -27
  259. data/vendor/libressl/tests/mlkem_tests.sh +0 -39
  260. data/vendor/libressl/tests/ocsptest.bat +0 -25
  261. data/vendor/libressl/tests/ocsptest.sh +0 -23
  262. data/vendor/libressl/tests/openssl.cnf +0 -29
  263. data/vendor/libressl/tests/optionstest.c +0 -381
  264. data/vendor/libressl/tests/pidwraptest.c +0 -85
  265. data/vendor/libressl/tests/pidwraptest.sh +0 -26
  266. data/vendor/libressl/tests/quictest.bat +0 -27
  267. data/vendor/libressl/tests/quictest.sh +0 -30
  268. data/vendor/libressl/tests/renegotiation_test.bat +0 -27
  269. data/vendor/libressl/tests/renegotiation_test.sh +0 -30
  270. data/vendor/libressl/tests/rfc5280time_small.test +0 -10
  271. data/vendor/libressl/tests/servertest.bat +0 -27
  272. data/vendor/libressl/tests/servertest.sh +0 -30
  273. data/vendor/libressl/tests/shutdowntest.bat +0 -27
  274. data/vendor/libressl/tests/shutdowntest.sh +0 -30
  275. data/vendor/libressl/tests/ssltest.bat +0 -32
  276. data/vendor/libressl/tests/ssltest.sh +0 -48
  277. data/vendor/libressl/tests/testdsa.bat +0 -47
  278. data/vendor/libressl/tests/testdsa.sh +0 -57
  279. data/vendor/libressl/tests/testenc.bat +0 -85
  280. data/vendor/libressl/tests/testenc.sh +0 -93
  281. data/vendor/libressl/tests/testrsa.bat +0 -47
  282. data/vendor/libressl/tests/testrsa.sh +0 -57
  283. data/vendor/libressl/tests/testssl.bat +0 -171
  284. data/vendor/libressl/tests/tlstest.bat +0 -27
  285. data/vendor/libressl/tests/tlstest.sh +0 -28
  286. data/vendor/libressl/tls/CMakeLists.txt +0 -125
  287. data/vendor/libressl/tls/Makefile.am +0 -76
  288. data/vendor/libressl/tls/compat/ftruncate.c +0 -17
  289. data/vendor/libressl/tls/compat/pread.c +0 -29
  290. data/vendor/libressl/tls/compat/pwrite.c +0 -29
  291. data/vendor/libressl/update.sh +0 -460
@@ -3,10 +3,10 @@
3
3
  require_relative './common'
4
4
  require 'socket'
5
5
 
6
- GROUPS = 50
6
+ GROUPS = 48
7
7
  ITERATIONS = 10000
8
8
 
9
- SIZE = 1024
9
+ SIZE = 1 << 14
10
10
  DATA = '*' * SIZE
11
11
 
12
12
  class UMBenchmark
@@ -55,6 +55,22 @@ class UMBenchmark
55
55
  end
56
56
  end
57
57
 
58
+ def do_scheduler_x(div, scheduler, ios)
59
+ (GROUPS/div).times do
60
+ r, w = Socket.socketpair(:AF_UNIX, :SOCK_STREAM, 0)
61
+ r.sync = true
62
+ w.sync = true
63
+ Fiber.schedule do
64
+ ITERATIONS.times { w.send(DATA, 0) }
65
+ w.close
66
+ end
67
+ Fiber.schedule do
68
+ ITERATIONS.times { r.recv(SIZE) }
69
+ r.close
70
+ end
71
+ end
72
+ end
73
+
58
74
  def do_um(machine, fibers, fds)
59
75
  GROUPS.times do
60
76
  r, w = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
@@ -68,4 +84,18 @@ class UMBenchmark
68
84
  end
69
85
  end
70
86
  end
87
+
88
+ def do_um_x(div, machine, fibers, fds)
89
+ (GROUPS/div).times do
90
+ r, w = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
91
+ fibers << machine.spin do
92
+ ITERATIONS.times { machine.send(w, DATA, SIZE, UM::MSG_WAITALL) }
93
+ machine.close_async(w)
94
+ end
95
+ fibers << machine.spin do
96
+ ITERATIONS.times { machine.recv(r, +'', SIZE, 0) }
97
+ machine.close_async(r)
98
+ end
99
+ end
100
+ end
71
101
  end
@@ -4,9 +4,9 @@ require_relative './common'
4
4
  require 'securerandom'
5
5
  require 'fileutils'
6
6
 
7
- GROUPS = ENV['N']&.to_i || 50
7
+ GROUPS = ENV['N']&.to_i || 48
8
8
  WORKERS = 10
9
- ITERATIONS = 1000
9
+ ITERATIONS = 10000
10
10
 
11
11
  puts "N=#{GROUPS}"
12
12
 
@@ -14,10 +14,15 @@ SIZE = 1024
14
14
  DATA = "*" * SIZE
15
15
 
16
16
  class UMBenchmark
17
+ def cleanup
18
+ # `rm /tmp/mutex*` rescue nil
19
+ end
20
+
17
21
  def do_threads(threads, ios)
18
22
  GROUPS.times do
19
23
  mutex = Mutex.new
20
- ios << (f = File.open("/tmp/mutex_io_threads_#{SecureRandom.hex}", 'w'))
24
+ # ios << (f = File.open("/tmp/mutex_io_threads_#{SecureRandom.hex}", 'w'))
25
+ ios << (f = File.open("/dev/null", 'w'))
21
26
  f.sync = true
22
27
  WORKERS.times do
23
28
  threads << Thread.new do
@@ -34,7 +39,24 @@ class UMBenchmark
34
39
  def do_scheduler(scheduler, ios)
35
40
  GROUPS.times do
36
41
  mutex = Mutex.new
37
- ios << (f = File.open("/tmp/mutex_io_fiber_scheduler_#{SecureRandom.hex}", 'w'))
42
+ # ios << (f = File.open("/tmp/mutex_io_fiber_scheduler_#{SecureRandom.hex}", 'w'))
43
+ ios << (f = File.open("/dev/null", 'w'))
44
+ f.sync = true
45
+ WORKERS.times do
46
+ Fiber.schedule do
47
+ ITERATIONS.times do
48
+ mutex.synchronize { f.write(DATA) }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def do_scheduler_x(div, scheduler, ios)
56
+ (GROUPS/div).times do
57
+ mutex = Mutex.new
58
+ # ios << (f = File.open("/tmp/mutex_io_fiber_scheduler_#{SecureRandom.hex}", 'w'))
59
+ ios << (f = File.open("/dev/null", 'w'))
38
60
  f.sync = true
39
61
  WORKERS.times do
40
62
  Fiber.schedule do
@@ -49,7 +71,27 @@ class UMBenchmark
49
71
  def do_um(machine, fibers, fds)
50
72
  GROUPS.times do
51
73
  mutex = UM::Mutex.new
52
- fds << (fd = machine.open("/tmp/mutex_io_um_#{SecureRandom.hex}", UM::O_CREAT | UM::O_WRONLY))
74
+ # fds << (fd = machine.open("/tmp/mutex_io_um_#{SecureRandom.hex}", UM::O_CREAT | UM::O_WRONLY))
75
+ fds << (fd = machine.open("/dev/null", UM::O_WRONLY))
76
+ WORKERS.times do
77
+ fibers << machine.spin do
78
+ ITERATIONS.times do
79
+ machine.synchronize(mutex) do
80
+ machine.write(fd, DATA)
81
+ end
82
+ end
83
+ rescue => e
84
+ p e
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def do_um_x(div, machine, fibers, fds)
91
+ (GROUPS/div).times do
92
+ mutex = UM::Mutex.new
93
+ # fds << (fd = machine.open("/tmp/mutex_io_um_#{SecureRandom.hex}", UM::O_CREAT | UM::O_WRONLY))
94
+ fds << (fd = machine.open("/dev/null", UM::O_WRONLY))
53
95
  WORKERS.times do
54
96
  fibers << machine.spin do
55
97
  ITERATIONS.times do
Binary file
data/benchmark/common.rb CHANGED
@@ -9,6 +9,9 @@ gemfile do
9
9
  gem 'io-event'
10
10
  gem 'async'
11
11
  gem 'pg'
12
+ gem 'gvltools'
13
+ gem 'openssl'
14
+ gem 'localhost'
12
15
  end
13
16
 
14
17
  require 'uringmachine/fiber_scheduler'
@@ -54,26 +57,56 @@ class UMBenchmark
54
57
  end
55
58
 
56
59
  @@benchmarks = {
57
- baseline: [:baseline, "No Concurrency"],
58
- threads: [:threads, "Threads"],
59
- thread_pool: [:thread_pool, "ThreadPool"],
60
- async_uring: [:scheduler, "Async uring"],
61
- async_epoll: [:scheduler, "Async epoll"],
62
- um_fs: [:scheduler, "UM FS"],
63
- um: [:um, "UM"],
64
- um_sqpoll: [:um, "UM sqpoll"]
60
+ # baseline: [:baseline, "No Concurrency"],
61
+ # baseline_um: [:baseline_um, "UM no concurrency"],
62
+ # thread_pool: [:thread_pool, "ThreadPool"],
63
+
64
+ threads: [:threads, "Threads"],
65
+
66
+ async_uring: [:scheduler, "Async uring"],
67
+ async_uring_x2: [:scheduler_x, "Async uring x2"],
68
+
69
+ # async_epoll: [:scheduler, "Async epoll"],
70
+ # async_epoll_x2: [:scheduler_x, "Async epoll x2"],
71
+
72
+ um_fs: [:scheduler, "UM FS"],
73
+ um_fs_x2: [:scheduler_x, "UM FS x2"],
74
+
75
+ um: [:um, "UM"],
76
+ um_sidecar: [:um, "UM sidecar"],
77
+ # um_sqpoll: [:um, "UM sqpoll"],
78
+ um_x2: [:um_x, "UM x2"],
79
+ um_x4: [:um_x, "UM x4"],
80
+ um_x8: [:um_x, "UM x8"],
65
81
  }
66
82
 
67
83
  def run_benchmarks(b)
84
+ STDOUT.sync = true
68
85
  @@benchmarks.each do |sym, (doer, name)|
69
- b.report(name) { send(:"run_#{sym}") } if respond_to?(:"do_#{doer}")
86
+ if respond_to?(:"do_#{doer}")
87
+ STDOUT << "Running #{name}... "
88
+ ts = nil
89
+ b.report(name) {
90
+ ts = measure_time { send(:"run_#{sym}") }
91
+ }
92
+ p ts
93
+ cleanup
94
+ end
70
95
  end
71
96
  end
72
97
 
98
+ def cleanup
99
+ end
100
+
73
101
  def run_baseline
74
102
  do_baseline
75
103
  end
76
104
 
105
+ def run_baseline_um
106
+ machine = UM.new(4096)
107
+ do_baseline_um(machine)
108
+ end
109
+
77
110
  def run_threads
78
111
  threads = []
79
112
  ios = []
@@ -117,27 +150,140 @@ class UMBenchmark
117
150
  ios.each { it.close rescue nil }
118
151
  end
119
152
 
153
+ def run_async_uring_x2
154
+ threads = 2.times.map do
155
+ Thread.new do
156
+ selector ||= IO::Event::Selector::URing.new(Fiber.current)
157
+ worker_pool = Async::Scheduler::WorkerPool.new
158
+ scheduler = Async::Scheduler.new(selector:, worker_pool:)
159
+ Fiber.set_scheduler(scheduler)
160
+ ios = []
161
+ scheduler.run { do_scheduler_x(2, scheduler, ios) }
162
+ ios.each { it.close rescue nil }
163
+ end
164
+ end
165
+ threads.each(&:join)
166
+ end
167
+
168
+ def run_async_epoll_x2
169
+ threads = 2.times.map do
170
+ Thread.new do
171
+ selector ||= IO::Event::Selector::EPoll.new(Fiber.current)
172
+ scheduler = Async::Scheduler.new(selector:)
173
+ Fiber.set_scheduler(scheduler)
174
+ ios = []
175
+ scheduler.run { do_scheduler_x(2, scheduler, ios) }
176
+ ios.each { it.close rescue nil }
177
+ end
178
+ end
179
+ threads.each(&:join)
180
+ end
181
+
182
+ def run_um_fs_x2
183
+ threads = 2.times.map do
184
+ Thread.new do
185
+ machine = UM.new
186
+ thread_pool = UM::BlockingOperationThreadPool.new(2)
187
+ scheduler = UM::FiberScheduler.new(machine, thread_pool)
188
+ Fiber.set_scheduler(scheduler)
189
+ ios = []
190
+ do_scheduler_x(2, scheduler, ios)
191
+ scheduler.join
192
+ ios.each { it.close rescue nil }
193
+ end
194
+ end
195
+ threads.each(&:join)
196
+ end
197
+
120
198
  def run_um
121
- machine = UM.new(4096)
199
+ machine = UM.new
200
+ fibers = []
201
+ fds = []
202
+ do_um(machine, fibers, fds)
203
+ machine.await_fibers(fibers)
204
+ fds.each { machine.close(it) }
205
+ end
206
+
207
+ def run_um_sidecar
208
+ machine = UM.new(sidecar: true)
122
209
  fibers = []
123
210
  fds = []
124
211
  do_um(machine, fibers, fds)
125
212
  machine.await_fibers(fibers)
126
- puts "UM:"
127
- p machine.metrics
128
213
  fds.each { machine.close(it) }
129
214
  end
130
215
 
131
216
  def run_um_sqpoll
132
- machine = UM.new(4096, true)
217
+ machine = UM.new(sqpoll: true)
133
218
  fibers = []
134
219
  fds = []
135
220
  do_um(machine, fibers, fds)
136
221
  machine.await_fibers(fibers)
137
- fds.each { machine.close_async(it) }
138
- puts "UM sqpoll:"
139
- p machine.metrics
140
- machine.snooze
222
+ fds.each { machine.close(it) }
223
+ end
224
+
225
+ def run_um_x2
226
+ threads = 2.times.map do
227
+ Thread.new do
228
+ machine = UM.new
229
+ fibers = []
230
+ fds = []
231
+ do_um_x(2, machine, fibers, fds)
232
+ machine.await_fibers(fibers)
233
+ fds.each { machine.close(it) }
234
+ end
235
+ end
236
+ threads.each(&:join)
237
+ end
238
+
239
+ def run_um_x4
240
+ threads = 4.times.map do
241
+ Thread.new do
242
+ machine = UM.new
243
+ fibers = []
244
+ fds = []
245
+ do_um_x(4, machine, fibers, fds)
246
+ machine.await_fibers(fibers)
247
+ fds.each { machine.close(it) }
248
+ end
249
+ end
250
+ threads.each(&:join)
251
+ end
252
+
253
+ def run_um_x8
254
+ threads = 8.times.map do
255
+ Thread.new do
256
+ machine = UM.new
257
+ fibers = []
258
+ fds = []
259
+ do_um_x(8, machine, fibers, fds)
260
+ machine.await_fibers(fibers)
261
+ fds.each { machine.close(it) }
262
+ end
263
+ end
264
+ threads.each(&:join)
265
+ end
266
+
267
+ def measure_time
268
+ GVLTools::GlobalTimer.enable
269
+ t0s = [
270
+ Process.clock_gettime(Process::CLOCK_MONOTONIC),
271
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID),
272
+ GVLTools::GlobalTimer.monotonic_time / 1_000_000_000.0
273
+ ]
274
+ yield
275
+ t1s = [
276
+ Process.clock_gettime(Process::CLOCK_MONOTONIC),
277
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID),
278
+ GVLTools::GlobalTimer.monotonic_time / 1_000_000_000.0
279
+ ]
280
+ {
281
+ monotonic: t1s[0] - t0s[0],
282
+ cpu: t1s[1] - t0s[1],
283
+ gvl: t1s[2] - t0s[2]
284
+ }
285
+ ensure
286
+ GVLTools::GlobalTimer.disable
141
287
  end
142
288
  end
143
289
 
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # require 'bundler/inline'
4
-
5
- # gemfile do
6
- # source 'https://rubygems.org'
7
- # gem 'uringmachine', path: '..'
8
- # gem 'benchmark-ips'
9
- # gem 'http_parser.rb'
10
- # end
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'uringmachine', path: '..'
8
+ gem 'benchmark'
9
+ gem 'benchmark-ips'
10
+ gem 'http_parser.rb'
11
+ end
11
12
 
12
- require 'bundler/setup'
13
13
  require 'uringmachine'
14
14
  require 'benchmark/ips'
15
15
  require 'http/parser'
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'uringmachine', path: '..'
8
+ end
9
+
10
+ require 'uringmachine'
11
+
12
+ RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
+ RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
+
15
+ def stream_get_request_line(stream, buf)
16
+ line = stream.get_line(buf, 0)
17
+ m = line&.match(RE_REQUEST_LINE)
18
+ return nil if !m
19
+
20
+ {
21
+ 'method' => m[1].downcase,
22
+ 'path' => m[2],
23
+ 'protocol' => m[3].downcase
24
+ }
25
+ end
26
+
27
+ class InvalidHeadersError < StandardError; end
28
+
29
+ def get_headers(stream, buf)
30
+ headers = stream_get_request_line(stream, buf)
31
+ return nil if !headers
32
+
33
+ while true
34
+ line = stream.get_line(buf, 0)
35
+ break if line.empty?
36
+
37
+ m = line.match(RE_HEADER_LINE)
38
+ raise InvalidHeadersError, "Invalid header" if !m
39
+
40
+ headers[m[1]] = m[2]
41
+ end
42
+
43
+ headers
44
+ end
45
+
46
+ BODY = "Hello, world!" * 1000
47
+
48
+ def send_response(machine, fd)
49
+ headers = "HTTP/1.1 200\r\nContent-Length: #{BODY.bytesize}\r\n\r\n"
50
+ machine.sendv(fd, headers, BODY)
51
+ end
52
+
53
+ def handle_connection(machine, fd)
54
+ stream = UM::Stream.new(machine, fd)
55
+ buf = String.new(capacity: 65536)
56
+
57
+ while true
58
+ headers = get_headers(stream, buf)
59
+ break if !headers
60
+
61
+ send_response(machine, fd)
62
+ end
63
+ rescue InvalidHeadersError, SystemCallError => e
64
+ # ignore
65
+ ensure
66
+ machine.close_async(fd)
67
+ end
68
+
69
+ N = ENV['N']&.to_i || 1
70
+ PORT = ENV['PORT']&.to_i || 1234
71
+
72
+ accept_queue = UM::Queue.new
73
+
74
+ acceptor = Thread.new do
75
+ machine = UM.new
76
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
77
+ machine.setsockopt(fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
78
+ machine.setsockopt(fd, UM::SOL_SOCKET, UM::SO_REUSEPORT, true)
79
+ machine.bind(fd, '127.0.0.1', PORT)
80
+ machine.listen(fd, 128)
81
+ machine.accept_into_queue(fd, accept_queue)
82
+ rescue Exception => e
83
+ p e
84
+ p e.backtrace
85
+ exit!
86
+ end
87
+
88
+ workers = N.times.map do |idx|
89
+ Thread.new do
90
+ machine = UM.new
91
+
92
+ loop do
93
+ fd = machine.shift(accept_queue)
94
+ machine.spin { handle_connection(machine, fd) }
95
+ end
96
+ rescue Exception => e
97
+ p e
98
+ p e.backtrace
99
+ exit!
100
+ end
101
+ end
102
+
103
+ puts "Listening on localhost:#{PORT}, #{N} worker thread(s)"
104
+ acceptor.join
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'uringmachine', path: '..'
8
+ end
9
+
10
+ require 'uringmachine'
11
+
12
+ RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
+ RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
+
15
+ def stream_get_request_line(stream, buf)
16
+ line = stream.get_line(buf, 0)
17
+ m = line&.match(RE_REQUEST_LINE)
18
+ return nil if !m
19
+
20
+ {
21
+ 'method' => m[1].downcase,
22
+ 'path' => m[2],
23
+ 'protocol' => m[3].downcase
24
+ }
25
+ end
26
+
27
+ class InvalidHeadersError < StandardError; end
28
+
29
+ def get_headers(stream, buf)
30
+ headers = stream_get_request_line(stream, buf)
31
+ return nil if !headers
32
+
33
+ while true
34
+ line = stream.get_line(buf, 0)
35
+ break if line.empty?
36
+
37
+ m = line.match(RE_HEADER_LINE)
38
+ raise InvalidHeadersError, "Invalid header" if !m
39
+
40
+ headers[m[1]] = m[2]
41
+ end
42
+
43
+ headers
44
+ end
45
+
46
+ BODY = "Hello, world!" * 1000
47
+
48
+ def send_response(machine, fd)
49
+ headers = "HTTP/1.1 200\r\nContent-Length: #{BODY.bytesize}\r\n\r\n"
50
+ machine.sendv(fd, headers, BODY)
51
+ end
52
+
53
+ def handle_connection(machine, fd)
54
+ stream = UM::Stream.new(machine, fd)
55
+ buf = String.new(capacity: 65536)
56
+
57
+ while true
58
+ headers = get_headers(stream, buf)
59
+ break if !headers
60
+
61
+ send_response(machine, fd)
62
+ end
63
+ rescue InvalidHeadersError, SystemCallError => e
64
+ # ignore
65
+ ensure
66
+ machine.close_async(fd)
67
+ end
68
+
69
+ N = ENV['N']&.to_i || 1
70
+ PORT = ENV['PORT']&.to_i || 1234
71
+
72
+ workers = N.times.map do |idx|
73
+ Thread.new do
74
+ machine = UM.new
75
+
76
+ listen_fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
77
+ machine.setsockopt(listen_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
78
+ machine.setsockopt(listen_fd, UM::SOL_SOCKET, UM::SO_REUSEPORT, true)
79
+ machine.bind(listen_fd, '127.0.0.1', PORT)
80
+ machine.listen(listen_fd, 128)
81
+
82
+ machine.accept_each(listen_fd) { |fd|
83
+ machine.spin { handle_connection(machine, fd) }
84
+ }
85
+ rescue Exception => e
86
+ p e
87
+ p e.backtrace
88
+ exit!
89
+ end
90
+ end
91
+
92
+ puts "Listening on localhost:#{PORT}, #{N} worker thread(s)"
93
+ workers.each(&:join)
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'uringmachine', path: '..'
8
+ end
9
+
10
+ require 'uringmachine'
11
+
12
+ RE_REQUEST_LINE = /^([a-z]+)\s+([^\s]+)\s+(http\/[0-9\.]{1,3})/i
13
+ RE_HEADER_LINE = /^([a-z0-9\-]+)\:\s+(.+)/i
14
+
15
+ def stream_get_request_line(stream, buf)
16
+ line = stream.get_line(buf, 0)
17
+ m = line&.match(RE_REQUEST_LINE)
18
+ return nil if !m
19
+
20
+ {
21
+ 'method' => m[1].downcase,
22
+ 'path' => m[2],
23
+ 'protocol' => m[3].downcase
24
+ }
25
+ end
26
+
27
+ class InvalidHeadersError < StandardError; end
28
+
29
+ def get_headers(stream, buf)
30
+ headers = stream_get_request_line(stream, buf)
31
+ return nil if !headers
32
+
33
+ while true
34
+ line = stream.get_line(buf, 0)
35
+ break if line.empty?
36
+
37
+ m = line.match(RE_HEADER_LINE)
38
+ raise InvalidHeadersError, "Invalid header" if !m
39
+
40
+ headers[m[1]] = m[2]
41
+ end
42
+
43
+ headers
44
+ end
45
+
46
+ BODY = "Hello, world!" * 1000
47
+ Ractor.make_shareable(BODY)
48
+
49
+ def send_response(machine, fd)
50
+ headers = "HTTP/1.1 200\r\nContent-Length: #{BODY.bytesize}\r\n\r\n"
51
+ machine.sendv(fd, headers, BODY)
52
+ end
53
+
54
+ def handle_connection(machine, fd)
55
+ machine.setsockopt(fd, UM::IPPROTO_TCP, UM::TCP_NODELAY, true)
56
+ stream = UM::Stream.new(machine, fd)
57
+ buf = String.new(capacity: 65536)
58
+
59
+ while true
60
+ headers = get_headers(stream, buf)
61
+ break if !headers
62
+
63
+ send_response(machine, fd)
64
+ end
65
+ # rescue InvalidHeadersError, SystemCallError => e
66
+ # ignore
67
+ rescue Exception => e
68
+ p e: e
69
+ p bt: e.backtrace
70
+ exit!
71
+ ensure
72
+ machine.close_async(fd)
73
+ end
74
+
75
+ N = ENV['N']&.to_i || 1
76
+ PORT = ENV['PORT']&.to_i || 1234
77
+
78
+ workers = N.times.map do |idx|
79
+ Ractor.new do
80
+ machine = UM.new
81
+
82
+ listen_fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
83
+ machine.setsockopt(listen_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
84
+ machine.setsockopt(listen_fd, UM::SOL_SOCKET, UM::SO_REUSEPORT, true)
85
+ machine.bind(listen_fd, '127.0.0.1', PORT)
86
+ machine.listen(listen_fd, 128)
87
+
88
+ machine.accept_each(listen_fd) { |fd|
89
+ machine.spin { handle_connection(machine, fd) }
90
+ }
91
+ rescue Exception => e
92
+ p e
93
+ p e.backtrace
94
+ exit!
95
+ end
96
+ end
97
+
98
+ puts "Listening on localhost:#{PORT}, #{N} worker ractor(s)"
99
+ workers.each(&:join)