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,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'polyphony'
4
+
5
+ def try_connect(ip_address, port, supervisor)
6
+ puts "trying #{ip_address}"
7
+ sleep rand * 0.2
8
+ socket = TCPSocket.new(ip_address, port)
9
+ puts "connected to #{ip_address}"
10
+ supervisor.schedule [ip_address, socket]
11
+ rescue IOError, SystemCallError
12
+ # ignore error
13
+ end
14
+
15
+ def happy_eyeballs(hostname, port, max_wait_time: 0.010)
16
+ targets = Socket.getaddrinfo(hostname, port, :INET, :STREAM)
17
+ t0 = Time.now
18
+ fibers = []
19
+ supervisor = Fiber.current
20
+ spin do
21
+ targets.each do |t|
22
+ spin { try_connect(t[2], t[1], supervisor) }
23
+ sleep(max_wait_time)
24
+ end
25
+ suspend
26
+ end
27
+ target, socket = move_on_after(5) { suspend }
28
+ supervisor.shutdown_all_children
29
+ if target
30
+ puts format('success: %s (%.3fs)', target, Time.now - t0)
31
+ else
32
+ puts 'timed out'
33
+ end
34
+ end
35
+
36
+ happy_eyeballs('debian.org', 'https')
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'httparty'
6
+ require 'json'
7
+
8
+ def get_time(tzone)
9
+ res = HTTParty.get("http://worldtimeapi.org/api/timezone/#{tzone}")
10
+ return '- failed -' unless res.ok?
11
+
12
+ json = JSON.parse(res.body)
13
+ Time.parse(json['datetime'])
14
+ end
15
+
16
+ zones = %w{
17
+ Europe/London Europe/Paris Europe/Bucharest America/New_York Asia/Bangkok
18
+ }
19
+ # zones.each do |tzone|
20
+ # spin do
21
+ # time = get_time(tzone)
22
+ # puts "Time in #{tzone}: #{time}"
23
+ # end
24
+ # end
25
+
26
+ # suspend
27
+
28
+ def get_times(zones)
29
+ Polyphony::Supervisor.new do |s|
30
+ zones.each do |tzone|
31
+ s.spin { [tzone, get_time(tzone)] }
32
+ end
33
+ end
34
+ end
35
+
36
+ get_times(zones).await.each do |tzone, time|
37
+ puts "Time in #{tzone}: #{time}"
38
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'irb'
5
+ require 'polyphony/adapters/irb'
6
+
7
+ $counter = 0
8
+ timer = spin do
9
+ throttled_loop(5) do
10
+ $counter += 1
11
+ end
12
+ end
13
+
14
+ at_exit { timer.stop }
15
+
16
+ puts 'try typing $counter to see the counter incremented in the background'
17
+ IRB.start
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'net/http'
6
+
7
+ uri = URI('http://realiteq.net/?q=time')
8
+
9
+ begin
10
+ puts Net::HTTP.get(uri)
11
+ rescue StandardError => e
12
+ p e
13
+ puts '*' * 40
14
+ puts e.backtrace[0..4].join("\n")
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ stdin = IO.open(STDIN.to_i)
7
+
8
+ loop do
9
+ print 'Say something: '
10
+ cancel_after(3) do
11
+ line = stdin.gets
12
+ puts "You said: #{line}"
13
+ end
14
+ rescue Polyphony::Cancel
15
+ puts '<got nothing>'
16
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fiber'
4
+
5
+ X = 10_000_000
6
+
7
+ main = Fiber.current
8
+ f = Fiber.new do
9
+ loop { main.transfer }
10
+ end
11
+
12
+ t0 = Time.now
13
+ X.times { f.transfer }
14
+ dt = Time.now - t0
15
+ puts "#{X / dt.to_f}/s"
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ timer = spin do
7
+ throttled_loop(5) { STDOUT << '.' }
8
+ end
9
+
10
+ puts system('ruby -e "sleep 1; puts :done; STDOUT.close"')
11
+ timer.stop
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ server = TCPServer.new('127.0.0.1', 1234)
7
+
8
+ puts 'echoing on port 1234'
9
+ while (socket = server.accept)
10
+ spin do
11
+ while (data = socket.gets(8192))
12
+ socket << "you said: #{data}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ socket = TCPSocket.new('google.com', 80)
7
+
8
+ timer = spin { throttled_loop(20) { STDOUT << '.' } }
9
+
10
+ 5.times do
11
+ socket.send("GET /?q=time HTTP/1.1\r\nHost: google.com\r\n\r\n", 0)
12
+ socket.recv(8192)
13
+ STDOUT << '*'
14
+ end
15
+
16
+ timer.stop
17
+ socket.close
18
+ puts
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'zlib'
6
+
7
+ i, o = IO.pipe
8
+
9
+ w = Zlib::GzipWriter.new(o)
10
+
11
+ s = (1..1000).map { (65 + rand(26)).chr }.join
12
+ puts "full length: #{s.bytesize}"
13
+ w << s
14
+ w.close
15
+ o.close
16
+
17
+
18
+ z = i.read
19
+ puts "zipped length: #{z.bytesize}"
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fiber'
4
+
5
+ class Fiber
6
+ attr_accessor :next
7
+ end
8
+
9
+ # This program shows how the performance
10
+
11
+ def run(num_fibers)
12
+ count = 0
13
+
14
+ GC.disable
15
+
16
+ first = nil
17
+ last = nil
18
+ supervisor = Fiber.current
19
+ num_fibers.times do
20
+ fiber = Fiber.new do
21
+ loop do
22
+ count += 1
23
+ if count == 1_000_000
24
+ supervisor.transfer
25
+ else
26
+ Fiber.current.next.transfer
27
+ end
28
+ end
29
+ end
30
+ first ||= fiber
31
+ last.next = fiber if last
32
+ last = fiber
33
+ end
34
+
35
+ last.next = first
36
+
37
+ t0 = Time.now
38
+ first.transfer
39
+ elapsed = Time.now - t0
40
+
41
+ puts "fibers: #{num_fibers} count: #{count} rate: #{count / elapsed}"
42
+ GC.start
43
+ end
44
+
45
+ run(100)
46
+ run(1000)
47
+ run(10000)
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'polyphony/fs'
6
+
7
+ def raw_read_file(x)
8
+ t0 = Time.now
9
+ x.times { IO.orig_read(__FILE__) }
10
+ puts "raw_read_file: #{Time.now - t0}"
11
+ end
12
+
13
+ def threaded_read_file(x, y)
14
+ t0 = Time.now
15
+ threads = []
16
+ y.times do
17
+ threads << Thread.new { x.times { IO.orig_read(PATH) } }
18
+ end
19
+ threads.each(&:join)
20
+ puts "threaded_read_file: #{Time.now - t0}"
21
+ end
22
+
23
+ def thread_pool_read_file(x, y)
24
+ t0 = Time.now
25
+ supervise do |s|
26
+ y.times do
27
+ s.spin { x.times { IO.read(PATH) } }
28
+ end
29
+ end
30
+ puts "thread_pool_read_file: #{Time.now - t0}"
31
+ end
32
+
33
+ Y = ARGV[0] ? ARGV[0].to_i : 10
34
+ X = ARGV[1] ? ARGV[1].to_i : 100
35
+
36
+ raw_read_file(X * Y)
37
+ threaded_read_file(X, Y)
38
+ thread_pool_read_file(X, Y)
@@ -0,0 +1,56 @@
1
+ require 'fiber'
2
+
3
+ def mem_usage
4
+ `ps -o rss #{$$}`.split.last.to_i
5
+ end
6
+
7
+ def calculate_memory_cost(name, count, &block)
8
+ GC.enable
9
+ ObjectSpace.garbage_collect
10
+ sleep 0.5
11
+ GC.disable
12
+ rss0 = mem_usage
13
+ count0 = ObjectSpace.count_objects[:TOTAL] - ObjectSpace.count_objects[:FREE]
14
+ a = []
15
+ count.times { a << block.call }
16
+ rss1 = mem_usage
17
+ count1 = ObjectSpace.count_objects[:TOTAL] - ObjectSpace.count_objects[:FREE]
18
+ p [count0, count1]
19
+ # sleep 0.5
20
+ cost = (rss1 - rss0).to_f / count
21
+ count_delta = (count1 - count0) / count
22
+
23
+ puts "#{name} rss cost: #{cost}KB object count: #{count_delta}"
24
+ end
25
+
26
+ f = Fiber.new { |f| f.transfer }
27
+ f.transfer Fiber.current
28
+
29
+ calculate_memory_cost('fiber', 10000) do
30
+ f = Fiber.new { |f| f.transfer :foo }
31
+ f.transfer Fiber.current
32
+ f
33
+ end
34
+
35
+ t = Thread.new { sleep 1}
36
+ t.kill
37
+ t.join
38
+
39
+ calculate_memory_cost('thread', 500) do
40
+ t = Thread.new { sleep 1 }
41
+ sleep 0.001
42
+ t
43
+ end
44
+ (Thread.list - [Thread.current]).each(&:kill).each(&:join)
45
+
46
+ require 'bundler/setup'
47
+ require 'polyphony'
48
+
49
+ f = spin { sleep 0.1 }
50
+ f.await
51
+
52
+ calculate_memory_cost('polyphony fiber', 10000) do
53
+ f = spin { :foo }
54
+ f.await
55
+ f
56
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ X = 1_000_000
7
+
8
+ GC.disable
9
+
10
+ count = 0
11
+
12
+ pong = spin_loop do
13
+ msg, ping = receive
14
+ count += 1
15
+ ping << 'pong'
16
+ end
17
+
18
+ ping = spin do
19
+ X.times do
20
+ pong << ['ping', Fiber.current]
21
+ msg = receive
22
+ count += 1
23
+ end
24
+ end
25
+
26
+ t0 = Time.now
27
+ ping.await
28
+ dt = Time.now - t0
29
+ puts format('message rate: %d/s', (X / dt))
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ def bm(fibers, iterations)
7
+ count = 0
8
+ t_pre = Time.now
9
+ fibers.times do
10
+ spin do
11
+ iterations.times do
12
+ snooze
13
+ count += 1
14
+ end
15
+ end
16
+ end
17
+ t0 = Time.now
18
+ Fiber.current.await_all_children
19
+ dt = Time.now - t0
20
+ puts "#{[fibers, iterations].inspect} setup: #{t0 - t_pre}s count: #{count} #{count / dt.to_f}/s"
21
+ Thread.current.run_queue_trace
22
+ end
23
+
24
+ GC.disable
25
+
26
+ bm(1, 1_000_000)
27
+ bm(10, 100_000)
28
+ bm(100, 10_000)
29
+ bm(1_000, 1_000)
30
+ bm(10_000, 100)
31
+
32
+ # bm(100_000, 10)
33
+ # bm(1_000_000, 1)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ X = 1_000_000
7
+
8
+ GC.disable
9
+
10
+ STDOUT << 'Fiber.yield: '
11
+ f = Fiber.new do
12
+ loop { Fiber.yield }
13
+ end
14
+ t0 = Time.now
15
+ X.times { f.resume }
16
+ dt = Time.now - t0
17
+ puts format('%d/s', (X / dt))
18
+
19
+ STDOUT << 'Fiber.transfer: '
20
+ main = Fiber.current
21
+ f = Fiber.new do
22
+ loop { main.transfer }
23
+ end
24
+ t0 = Time.now
25
+ X.times { f.transfer }
26
+ dt = Time.now - t0
27
+ puts format('%d/s', (X / dt))
28
+
29
+ STDOUT << 'Kernel#snooze: '
30
+ t0 = Time.now
31
+ X.times { snooze }
32
+ dt = Time.now - t0
33
+ puts format('%d/s', (X / dt))
34
+
35
+ # STDOUT << 'Kernel#sleep: '
36
+ # t0 = Time.now
37
+ # X.times { sleep(0) }
38
+ # dt = Time.now - t0
39
+ # puts "%d/s" % (X / dt)