polyphony 0.43.8

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 (221) hide show
  1. checksums.yaml +7 -0
  2. data/.gitbook.yaml +4 -0
  3. data/.github/workflows/test.yml +29 -0
  4. data/.gitignore +59 -0
  5. data/.rubocop.yml +175 -0
  6. data/CHANGELOG.md +393 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +141 -0
  9. data/LICENSE +21 -0
  10. data/README.md +51 -0
  11. data/Rakefile +26 -0
  12. data/TODO.md +201 -0
  13. data/bin/polyphony-debug +87 -0
  14. data/docs/_config.yml +64 -0
  15. data/docs/_includes/head.html +40 -0
  16. data/docs/_includes/title.html +1 -0
  17. data/docs/_sass/custom/custom.scss +10 -0
  18. data/docs/_sass/overrides.scss +0 -0
  19. data/docs/_user-guide/all-about-timers.md +126 -0
  20. data/docs/_user-guide/index.md +9 -0
  21. data/docs/_user-guide/web-server.md +136 -0
  22. data/docs/api-reference/exception.md +27 -0
  23. data/docs/api-reference/fiber.md +425 -0
  24. data/docs/api-reference/index.md +9 -0
  25. data/docs/api-reference/io.md +36 -0
  26. data/docs/api-reference/object.md +99 -0
  27. data/docs/api-reference/polyphony-baseexception.md +33 -0
  28. data/docs/api-reference/polyphony-cancel.md +26 -0
  29. data/docs/api-reference/polyphony-moveon.md +24 -0
  30. data/docs/api-reference/polyphony-net.md +20 -0
  31. data/docs/api-reference/polyphony-process.md +28 -0
  32. data/docs/api-reference/polyphony-resourcepool.md +59 -0
  33. data/docs/api-reference/polyphony-restart.md +18 -0
  34. data/docs/api-reference/polyphony-terminate.md +18 -0
  35. data/docs/api-reference/polyphony-threadpool.md +67 -0
  36. data/docs/api-reference/polyphony-throttler.md +77 -0
  37. data/docs/api-reference/polyphony.md +36 -0
  38. data/docs/api-reference/thread.md +88 -0
  39. data/docs/assets/img/echo-fibers.svg +1 -0
  40. data/docs/assets/img/sleeping-fiber.svg +1 -0
  41. data/docs/faq.md +195 -0
  42. data/docs/favicon.ico +0 -0
  43. data/docs/getting-started/index.md +10 -0
  44. data/docs/getting-started/installing.md +34 -0
  45. data/docs/getting-started/overview.md +486 -0
  46. data/docs/getting-started/tutorial.md +359 -0
  47. data/docs/index.md +94 -0
  48. data/docs/main-concepts/concurrency.md +151 -0
  49. data/docs/main-concepts/design-principles.md +161 -0
  50. data/docs/main-concepts/exception-handling.md +291 -0
  51. data/docs/main-concepts/extending.md +89 -0
  52. data/docs/main-concepts/fiber-scheduling.md +197 -0
  53. data/docs/main-concepts/index.md +9 -0
  54. data/docs/polyphony-logo.png +0 -0
  55. data/examples/adapters/concurrent-ruby.rb +9 -0
  56. data/examples/adapters/pg_client.rb +36 -0
  57. data/examples/adapters/pg_notify.rb +35 -0
  58. data/examples/adapters/pg_pool.rb +43 -0
  59. data/examples/adapters/pg_transaction.rb +31 -0
  60. data/examples/adapters/redis_blpop.rb +12 -0
  61. data/examples/adapters/redis_channels.rb +122 -0
  62. data/examples/adapters/redis_client.rb +19 -0
  63. data/examples/adapters/redis_pubsub.rb +26 -0
  64. data/examples/adapters/redis_pubsub_perf.rb +68 -0
  65. data/examples/core/01-spinning-up-fibers.rb +18 -0
  66. data/examples/core/02-awaiting-fibers.rb +20 -0
  67. data/examples/core/03-interrupting.rb +39 -0
  68. data/examples/core/04-handling-signals.rb +19 -0
  69. data/examples/core/xx-agent.rb +102 -0
  70. data/examples/core/xx-at_exit.rb +29 -0
  71. data/examples/core/xx-caller.rb +12 -0
  72. data/examples/core/xx-channels.rb +45 -0
  73. data/examples/core/xx-daemon.rb +14 -0
  74. data/examples/core/xx-deadlock.rb +8 -0
  75. data/examples/core/xx-deferring-an-operation.rb +14 -0
  76. data/examples/core/xx-erlang-style-genserver.rb +81 -0
  77. data/examples/core/xx-exception-backtrace.rb +40 -0
  78. data/examples/core/xx-fork-cleanup.rb +22 -0
  79. data/examples/core/xx-fork-spin.rb +42 -0
  80. data/examples/core/xx-fork-terminate.rb +27 -0
  81. data/examples/core/xx-forking.rb +24 -0
  82. data/examples/core/xx-move_on.rb +23 -0
  83. data/examples/core/xx-pingpong.rb +18 -0
  84. data/examples/core/xx-queue-async.rb +120 -0
  85. data/examples/core/xx-readpartial.rb +18 -0
  86. data/examples/core/xx-recurrent-timer.rb +12 -0
  87. data/examples/core/xx-resource_delegate.rb +31 -0
  88. data/examples/core/xx-signals.rb +16 -0
  89. data/examples/core/xx-sleep-forever.rb +9 -0
  90. data/examples/core/xx-sleeping.rb +25 -0
  91. data/examples/core/xx-snooze-starve.rb +16 -0
  92. data/examples/core/xx-spin-fork.rb +49 -0
  93. data/examples/core/xx-spin_error_backtrace.rb +33 -0
  94. data/examples/core/xx-state-machine.rb +51 -0
  95. data/examples/core/xx-stop.rb +20 -0
  96. data/examples/core/xx-supervise-process.rb +30 -0
  97. data/examples/core/xx-supervisors.rb +21 -0
  98. data/examples/core/xx-thread-selector-sleep.rb +51 -0
  99. data/examples/core/xx-thread-selector-snooze.rb +46 -0
  100. data/examples/core/xx-thread-sleep.rb +17 -0
  101. data/examples/core/xx-thread-snooze.rb +34 -0
  102. data/examples/core/xx-thread_pool.rb +17 -0
  103. data/examples/core/xx-throttling.rb +18 -0
  104. data/examples/core/xx-timeout.rb +10 -0
  105. data/examples/core/xx-timer-gc.rb +17 -0
  106. data/examples/core/xx-trace.rb +79 -0
  107. data/examples/core/xx-using-a-mutex.rb +21 -0
  108. data/examples/core/xx-worker-thread.rb +30 -0
  109. data/examples/io/tunnel.rb +48 -0
  110. data/examples/io/xx-backticks.rb +11 -0
  111. data/examples/io/xx-echo_client.rb +25 -0
  112. data/examples/io/xx-echo_client_from_stdin.rb +21 -0
  113. data/examples/io/xx-echo_pipe.rb +16 -0
  114. data/examples/io/xx-echo_server.rb +17 -0
  115. data/examples/io/xx-echo_server_with_timeout.rb +34 -0
  116. data/examples/io/xx-echo_stdin.rb +14 -0
  117. data/examples/io/xx-happy-eyeballs.rb +36 -0
  118. data/examples/io/xx-httparty.rb +38 -0
  119. data/examples/io/xx-irb.rb +17 -0
  120. data/examples/io/xx-net-http.rb +15 -0
  121. data/examples/io/xx-open.rb +16 -0
  122. data/examples/io/xx-switch.rb +15 -0
  123. data/examples/io/xx-system.rb +11 -0
  124. data/examples/io/xx-tcpserver.rb +15 -0
  125. data/examples/io/xx-tcpsocket.rb +18 -0
  126. data/examples/io/xx-zip.rb +19 -0
  127. data/examples/performance/fiber_transfer.rb +47 -0
  128. data/examples/performance/fs_read.rb +38 -0
  129. data/examples/performance/mem-usage.rb +56 -0
  130. data/examples/performance/messaging.rb +29 -0
  131. data/examples/performance/multi_snooze.rb +33 -0
  132. data/examples/performance/snooze.rb +39 -0
  133. data/examples/performance/snooze_raw.rb +39 -0
  134. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +74 -0
  135. data/examples/performance/thread-vs-fiber/polyphony_server.rb +45 -0
  136. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  137. data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
  138. data/examples/performance/thread-vs-fiber/xx-httparty_multi.rb +36 -0
  139. data/examples/performance/thread-vs-fiber/xx-httparty_threaded.rb +29 -0
  140. data/examples/performance/thread_pool_perf.rb +63 -0
  141. data/examples/performance/xx-array.rb +11 -0
  142. data/examples/performance/xx-fiber-switch.rb +9 -0
  143. data/examples/performance/xx-snooze.rb +15 -0
  144. data/examples/xx-spin.rb +32 -0
  145. data/ext/libev/Changes +548 -0
  146. data/ext/libev/LICENSE +37 -0
  147. data/ext/libev/README +59 -0
  148. data/ext/libev/README.embed +3 -0
  149. data/ext/libev/ev.c +5279 -0
  150. data/ext/libev/ev.h +856 -0
  151. data/ext/libev/ev_epoll.c +296 -0
  152. data/ext/libev/ev_kqueue.c +224 -0
  153. data/ext/libev/ev_linuxaio.c +642 -0
  154. data/ext/libev/ev_poll.c +156 -0
  155. data/ext/libev/ev_port.c +192 -0
  156. data/ext/libev/ev_select.c +316 -0
  157. data/ext/libev/ev_vars.h +215 -0
  158. data/ext/libev/ev_win32.c +162 -0
  159. data/ext/libev/ev_wrap.h +216 -0
  160. data/ext/libev/test_libev_win32.c +123 -0
  161. data/ext/polyphony/extconf.rb +20 -0
  162. data/ext/polyphony/fiber.c +109 -0
  163. data/ext/polyphony/libev.c +2 -0
  164. data/ext/polyphony/libev.h +9 -0
  165. data/ext/polyphony/libev_agent.c +882 -0
  166. data/ext/polyphony/polyphony.c +71 -0
  167. data/ext/polyphony/polyphony.h +97 -0
  168. data/ext/polyphony/polyphony_ext.c +21 -0
  169. data/ext/polyphony/queue.c +168 -0
  170. data/ext/polyphony/ring_buffer.c +96 -0
  171. data/ext/polyphony/ring_buffer.h +28 -0
  172. data/ext/polyphony/thread.c +208 -0
  173. data/ext/polyphony/tracing.c +11 -0
  174. data/lib/polyphony.rb +136 -0
  175. data/lib/polyphony/adapters/fs.rb +19 -0
  176. data/lib/polyphony/adapters/irb.rb +52 -0
  177. data/lib/polyphony/adapters/postgres.rb +110 -0
  178. data/lib/polyphony/adapters/process.rb +33 -0
  179. data/lib/polyphony/adapters/redis.rb +67 -0
  180. data/lib/polyphony/adapters/trace.rb +138 -0
  181. data/lib/polyphony/core/channel.rb +46 -0
  182. data/lib/polyphony/core/exceptions.rb +36 -0
  183. data/lib/polyphony/core/global_api.rb +124 -0
  184. data/lib/polyphony/core/resource_pool.rb +117 -0
  185. data/lib/polyphony/core/sync.rb +21 -0
  186. data/lib/polyphony/core/thread_pool.rb +64 -0
  187. data/lib/polyphony/core/throttler.rb +41 -0
  188. data/lib/polyphony/event.rb +17 -0
  189. data/lib/polyphony/extensions/core.rb +174 -0
  190. data/lib/polyphony/extensions/fiber.rb +379 -0
  191. data/lib/polyphony/extensions/io.rb +221 -0
  192. data/lib/polyphony/extensions/openssl.rb +81 -0
  193. data/lib/polyphony/extensions/socket.rb +150 -0
  194. data/lib/polyphony/extensions/thread.rb +108 -0
  195. data/lib/polyphony/net.rb +77 -0
  196. data/lib/polyphony/version.rb +5 -0
  197. data/polyphony.gemspec +40 -0
  198. data/test/coverage.rb +54 -0
  199. data/test/eg.rb +27 -0
  200. data/test/helper.rb +56 -0
  201. data/test/q.rb +24 -0
  202. data/test/run.rb +5 -0
  203. data/test/stress.rb +25 -0
  204. data/test/test_agent.rb +130 -0
  205. data/test/test_event.rb +59 -0
  206. data/test/test_ext.rb +196 -0
  207. data/test/test_fiber.rb +988 -0
  208. data/test/test_global_api.rb +352 -0
  209. data/test/test_io.rb +249 -0
  210. data/test/test_kernel.rb +57 -0
  211. data/test/test_process_supervision.rb +46 -0
  212. data/test/test_queue.rb +112 -0
  213. data/test/test_resource_pool.rb +138 -0
  214. data/test/test_signal.rb +100 -0
  215. data/test/test_socket.rb +34 -0
  216. data/test/test_supervise.rb +103 -0
  217. data/test/test_thread.rb +170 -0
  218. data/test/test_thread_pool.rb +101 -0
  219. data/test/test_throttler.rb +50 -0
  220. data/test/test_trace.rb +68 -0
  221. metadata +482 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fiber'
4
+
5
+ def worker_loop(tag)
6
+ loop do
7
+ puts "#{Time.now} #{tag}"
8
+ snooze
9
+ end
10
+ end
11
+
12
+ f1 = Fiber.new { worker_loop(:a) }
13
+ f2 = Fiber.new { worker_loop(:b) }
14
+
15
+ $reactor = Fiber.new do
16
+ loop do
17
+ # sleep 0.001
18
+ handle_next_tick
19
+ end
20
+ end
21
+
22
+ $next_tick_items = []
23
+
24
+ def handle_next_tick
25
+ items = $next_tick_items
26
+ $next_tick_items = []
27
+ items.each(&:transfer)
28
+ end
29
+
30
+ module Kernel
31
+ def snooze
32
+ $next_tick_items << Fiber.current
33
+ $reactor.transfer
34
+ end
35
+ end
36
+
37
+ $next_tick_items << f1
38
+ $next_tick_items << f2
39
+ $reactor.transfer
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'http/parser'
6
+
7
+ class Http::Parser
8
+ def setup_async
9
+ self.on_message_complete = proc { @request_complete = true }
10
+ end
11
+
12
+ def parse(data)
13
+ self << data
14
+ return nil unless @request_complete
15
+
16
+ @request_complete = nil
17
+ self
18
+ end
19
+ end
20
+
21
+ def handle_client(socket)
22
+ parser = Http::Parser.new
23
+ reqs = []
24
+ parser.on_message_complete = proc do |env|
25
+ reqs << Object.new # parser
26
+ end
27
+ while (data = socket.readpartial(8192)) do
28
+ parser << data
29
+ while (req = reqs.shift)
30
+ handle_request(socket, req)
31
+ req = nil
32
+ # snooze
33
+ end
34
+ end
35
+ rescue IOError, SystemCallError => e
36
+ # do nothing
37
+ ensure
38
+ socket&.close
39
+ parser.reset!
40
+ end
41
+
42
+ def handle_request(client, parser)
43
+ status_code = 200
44
+ data = "Hello world!\n"
45
+ headers = "Content-Length: #{data.bytesize}\r\n"
46
+ client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
47
+ end
48
+
49
+ $incoming = Polyphony::Queue.new
50
+
51
+ $threads = (1..4).map {
52
+ Thread.new {
53
+ Thread.current.setup_fiber_scheduling
54
+ loop {
55
+ conn = $incoming.pop
56
+ puts "#{Thread.current.inspect} pop #{conn.inspect}"
57
+ spin { handle_client(conn) }
58
+ }
59
+ }
60
+ }
61
+
62
+ spin do
63
+ server = TCPServer.open('0.0.0.0', 1234)
64
+ puts "listening on port 1234"
65
+
66
+ loop do
67
+ client = server.accept
68
+ $incoming << client
69
+ # spin { handle_client(client) }
70
+ end
71
+ end
72
+
73
+ puts "pid #{Process.pid}"
74
+ suspend
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'http/parser'
6
+
7
+ $connection_count = 0
8
+
9
+ def handle_client(socket)
10
+ $connection_count += 1
11
+ parser = Http::Parser.new
12
+ reqs = []
13
+ parser.on_message_complete = proc do |env|
14
+ reqs << Object.new # parser
15
+ end
16
+ while (data = socket.readpartial(8192)) do
17
+ parser << data
18
+ while (req = reqs.shift)
19
+ handle_request(socket, req)
20
+ req = nil
21
+ snooze
22
+ end
23
+ end
24
+ rescue IOError, SystemCallError => e
25
+ # do nothing
26
+ ensure
27
+ $connection_count -= 1
28
+ socket&.close
29
+ end
30
+
31
+ def handle_request(client, parser)
32
+ status_code = "200 OK"
33
+ data = "Hello world!\n"
34
+ headers = "Content-Type: text/plain\r\nContent-Length: #{data.bytesize}\r\n"
35
+ client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
36
+ end
37
+
38
+ server = TCPServer.open('0.0.0.0', 1234)
39
+ puts "pid #{Process.pid}"
40
+ puts "listening on port 1234"
41
+
42
+ loop do
43
+ client = server.accept
44
+ spin { handle_client(client) }
45
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'http/parser'
6
+
7
+ $connection_count = 0
8
+
9
+ def handle_client(socket)
10
+ $connection_count += 1
11
+ parser = Http::Parser.new
12
+ reqs = []
13
+ parser.on_message_complete = proc do |env|
14
+ reqs << Object.new # parser
15
+ end
16
+ socket.read_loop do |data|
17
+ parser << data
18
+ while (req = reqs.shift)
19
+ handle_request(socket, req)
20
+ end
21
+ end
22
+ rescue IOError, SystemCallError => e
23
+ # do nothing
24
+ ensure
25
+ $connection_count -= 1
26
+ socket&.close
27
+ end
28
+
29
+ def handle_request(client, parser)
30
+ status_code = "200 OK"
31
+ data = "Hello world!\n"
32
+ headers = "Content-Type: text/plain\r\nContent-Length: #{data.bytesize}\r\n"
33
+ client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
34
+ end
35
+
36
+ spin do
37
+ server = TCPServer.open('0.0.0.0', 1234)
38
+ puts "listening on port 1234"
39
+
40
+ Thread.current.agent.accept_loop(server) do |client|
41
+ spin { handle_client(client) }
42
+ end
43
+ # loop do
44
+ # client = server.accept
45
+ # spin { handle_client(client) }
46
+ # end
47
+ ensure
48
+ server&.close
49
+ end
50
+
51
+ # every(1) {
52
+ # stats = Thread.current.fiber_scheduling_stats
53
+ # stats[:connection_count] = $connection_count
54
+ # puts "#{Time.now} #{stats}"
55
+ # }
56
+
57
+ puts "pid #{Process.pid}"
58
+ suspend
@@ -0,0 +1,27 @@
1
+ require 'thread'
2
+ require 'http/parser'
3
+ require 'socket'
4
+
5
+ def handle_client(client)
6
+ Thread.new do
7
+ parser = Http::Parser.new
8
+ parser.on_message_complete = proc do |env|
9
+ status_code = 200
10
+ data = "Hello world!\n"
11
+ headers = "Content-Length: #{data.bytesize}\r\n"
12
+ client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
13
+ end
14
+ loop do
15
+ while data = client.readpartial(8192) rescue nil
16
+ parser << data
17
+ end
18
+ end
19
+ client.close
20
+ end
21
+ end
22
+
23
+ server = TCPServer.open(1234)
24
+ puts "Listening on port 1234"
25
+ while socket = server.accept
26
+ handle_client(socket)
27
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'httparty'
6
+
7
+ URL = 'http://worldtimeapi.org/api/timezone/Europe/Paris'
8
+
9
+ def get_time(results)
10
+ loop do
11
+ STDOUT << '!'
12
+ if (res = HTTParty.get(URL))
13
+ results << res
14
+ STDOUT << '.'
15
+ end
16
+ rescue StandardError => e
17
+ p e
18
+ end
19
+ end
20
+
21
+ t0 = Time.now
22
+ results = []
23
+ move_on_after(3) do
24
+ supervise do |s|
25
+ 10.times do
26
+ s.spin { get_time(results) }
27
+ end
28
+ end
29
+ puts 'done'
30
+ end
31
+
32
+ puts format(
33
+ 'got %<count>d (%<rate>0.1f reqs/s)',
34
+ count: results.size,
35
+ rate: results.size / (Time.now - t0)
36
+ )
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'httparty'
4
+
5
+ URL = 'http://worldtimeapi.org/api/timezone/Europe/Paris'
6
+ results = Queue.new
7
+
8
+ t0 = Time.now
9
+ threads = []
10
+ 10.times do
11
+ threads << Thread.new do
12
+ loop do
13
+ STDOUT << '!'
14
+ if (result = HTTParty.get(URL))
15
+ results << result
16
+ STDOUT << '.'
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ sleep 3
23
+ threads.each(&:kill)
24
+ puts 'done'
25
+ puts format(
26
+ 'got %<count>d (%<rate>0.1f reqs/s)',
27
+ count: results.size,
28
+ rate: results.size / (Time.now - t0)
29
+ )
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ def lengthy_op
7
+ data = IO.orig_read(__FILE__)
8
+ data.clear
9
+ # Socket.getaddrinfo('debian.org', 80)
10
+ # Digest::SHA256.digest(IO.read('doc/Promise.html'))
11
+ end
12
+
13
+ X = 100
14
+
15
+ def compare_performance
16
+ t0 = Time.now
17
+ X.times { lengthy_op }
18
+ native_perf = X / (Time.now - t0)
19
+ puts "native performance: #{native_perf}"
20
+ # puts "*" * 40
21
+
22
+ begin
23
+ 1.times do
24
+ t0 = Time.now
25
+ X.times do
26
+ Polyphony::ThreadPool.process { lengthy_op }
27
+ end
28
+ async_perf = X / (Time.now - t0)
29
+ puts format(
30
+ 'seq thread pool performance: %g (X %0.2f)',
31
+ async_perf,
32
+ async_perf / native_perf
33
+ )
34
+ end
35
+
36
+ acc = 0
37
+ count = 0
38
+ 10.times do |_i|
39
+ t0 = Time.now
40
+ supervise do |s|
41
+ X.times do
42
+ s.spin { Polyphony::ThreadPool.process { lengthy_op } }
43
+ end
44
+ end
45
+ thread_pool_perf = X / (Time.now - t0)
46
+ acc += thread_pool_perf
47
+ count += 1
48
+ end
49
+ avg_perf = acc / count
50
+ puts format(
51
+ 'avg thread pool performance: %g (X %0.2f)',
52
+ avg_perf,
53
+ avg_perf / native_perf
54
+ )
55
+ rescue Exception => e
56
+ p e
57
+ puts e.backtrace.join("\n")
58
+ end
59
+ end
60
+
61
+ spin { compare_performance }
62
+
63
+ suspend
@@ -0,0 +1,11 @@
1
+ X = ARGV[0] ? ARGV[0].to_i : 10
2
+ a = (1..X).to_a
3
+
4
+ Y = 1_000_000
5
+ t0 = Time.now
6
+ Y.times do
7
+ i = a.shift
8
+ a.push i
9
+ end
10
+
11
+ puts "rate: #{Y / (Time.now - t0)}"
@@ -0,0 +1,9 @@
1
+ X = 1_000_000
2
+ f = Fiber.new do
3
+ loop { Fiber.yield }
4
+ end
5
+
6
+ t0 = Time.now
7
+ X.times { f.resume }
8
+ dt = Time.now - t0
9
+ puts "#{X / dt.to_f}/s"
@@ -0,0 +1,15 @@
1
+ require 'bundler/setup'
2
+ require 'polyphony'
3
+
4
+ Y = ARGV[0] ? ARGV[0].to_i : 1
5
+
6
+ count = 0
7
+ Y.times do
8
+ spin { loop { count += 1; snooze } }
9
+ end
10
+
11
+ t0 = Time.now
12
+ sleep 10
13
+ elapsed = Time.now - t0
14
+ rate = count / elapsed
15
+ puts "concurrency: #{Y} rate: #{rate} switchpoints per second"
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ puts "pid: #{Process.pid}"
7
+ GC.disable
8
+
9
+ def mem_usage
10
+ # orig_backtick('ps -o rss #{$$}').split.last.to_i
11
+ `ps -o rss #{$$}`.split.last.to_i
12
+ end
13
+
14
+ f = File.open('spin.log', 'w+')
15
+
16
+ m0 = mem_usage
17
+
18
+ X = ARGV[0] ? ARGV[0].to_i : 10
19
+ STDOUT.orig_write "Starting #{X} fibers...\n"
20
+ t0 = Time.now
21
+ x = nil
22
+ X.times do |i|
23
+ spin { p i; suspend }
24
+ end
25
+
26
+ suspend
27
+ f.close
28
+ t1 = Time.now
29
+ m1 = mem_usage
30
+ rate = X / (t1 - t0)
31
+ mem_cost = (m1 - m0) / X.to_f
32
+ STDOUT.orig_write("#{ { time: t1 - t0, spin_rate: rate, fiber_mem_cost: mem_cost }.inspect }\n")