Skip to content

Commit 18c33e8

Browse files
authored
Add optional support for the fiber-profiler gem. (#376)
1 parent 9ee239b commit 18c33e8

File tree

5 files changed

+45
-11
lines changed

5 files changed

+45
-11
lines changed

.github/workflows/test-coverage.yaml

+13-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,15 @@ jobs:
2727
ruby: "3.3"
2828
selector: EPoll
2929
- os: ubuntu
30-
ruby: "3.3"
30+
ruby: "3.4"
31+
selector: EPoll
32+
- os: ubuntu
33+
ruby: "3.4"
3134
selector: URing
35+
- os: ubuntu
36+
ruby: "3.4"
37+
selector: URing
38+
fiber_profile_capture: "true"
3239
- os: ubuntu
3340
ruby: "head"
3441
selector: URing
@@ -37,6 +44,9 @@ jobs:
3744
selector: URing
3845
worker_pool: "true"
3946

47+
env:
48+
FIBER_PROFILER_CAPTURE: ${{matrix.fiber_profile_capture}}
49+
4050
steps:
4151
- uses: actions/checkout@v4
4252
- uses: ruby/setup-ruby-pkgs@v1
@@ -51,13 +61,14 @@ jobs:
5161
env:
5262
IO_EVENT_SELECTOR: ${{matrix.selector}}
5363
ASYNC_SCHEDULER_DEFAULT_WORKER_POOL: ${{matrix.worker_pool}}
64+
FIBER_PROFILER_CAPTURE: ${{matrix.fiber_profile_capture}}
5465
run: bundle exec bake test
5566

5667
- uses: actions/upload-artifact@v4
5768
with:
5869
include-hidden-files: true
5970
if-no-files-found: error
60-
name: coverage-${{matrix.os}}-${{matrix.ruby}}-${{matrix.selector}}-${{matrix.worker_pool}}
71+
name: coverage-${{matrix.os}}-${{matrix.ruby}}-${{matrix.selector}}-${{matrix.worker_pool}}-${{matrix.fiber_profile_capture}}
6172
path: .covered.db
6273

6374
validate:

async.gemspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
2727

2828
spec.add_dependency "console", "~> 1.29"
2929
spec.add_dependency "fiber-annotation"
30-
spec.add_dependency "io-event", "~> 1.7"
30+
spec.add_dependency "io-event", "~> 1.9"
3131
spec.add_dependency "traces", "~> 0.15"
3232
spec.add_dependency "metrics", "~> 0.12"
3333
end

gems.rb

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
# gem "io-event", git: "https://github.com/socketry/io-event.git"
1313

14+
# In order to capture both code paths in coverage, we need to optionally load this gem:
15+
if ENV["FIBER_PROFILER_CAPTURE"] == "true"
16+
gem "fiber-profiler"
17+
end
18+
1419
group :maintenance, optional: true do
1520
gem "bake-gem"
1621
gem "bake-modernize"

lib/async/scheduler.rb

+23-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
require "resolv"
1616

1717
module Async
18+
begin
19+
require "fiber/profiler"
20+
Profiler = Fiber::Profiler
21+
rescue LoadError
22+
# Fiber::Profiler is not available.
23+
Profiler = nil
24+
end
25+
1826
# Handles scheduling of fibers. Implements the fiber scheduler interface.
1927
class Scheduler < Node
2028
DEFAULT_WORKER_POOL = ENV.fetch("ASYNC_SCHEDULER_DEFAULT_WORKER_POOL", nil).then do |value|
@@ -42,10 +50,12 @@ def self.supported?
4250
# @public Since *Async v1*.
4351
# @parameter parent [Node | Nil] The parent node to use for task hierarchy.
4452
# @parameter selector [IO::Event::Selector] The selector to use for event handling.
45-
def initialize(parent = nil, selector: nil, worker_pool: DEFAULT_WORKER_POOL)
53+
def initialize(parent = nil, selector: nil, profiler: Profiler&.default, worker_pool: DEFAULT_WORKER_POOL)
4654
super(parent)
4755

4856
@selector = selector || ::IO::Event::Selector.new(Fiber.current)
57+
@profiler = profiler
58+
4959
@interrupted = false
5060

5161
@blocked = 0
@@ -492,13 +502,19 @@ def stop
492502
def run(...)
493503
Kernel.raise ClosedError if @selector.nil?
494504

495-
initial_task = self.async(...) if block_given?
496-
497-
self.run_loop do
498-
run_once
505+
begin
506+
@profiler&.start
507+
508+
initial_task = self.async(...) if block_given?
509+
510+
self.run_loop do
511+
run_once
512+
end
513+
514+
return initial_task
515+
ensure
516+
@profiler&.stop
499517
end
500-
501-
return initial_task
502518
end
503519

504520
# Start an asynchronous task within the specified reactor. The task will be executed until the first blocking call, at which point it will yield and and this method will return.

test/io.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@
4545
it "can write with timeout" do
4646
skip_unless_constant_defined(:TimeoutError, IO)
4747

48+
big = "x" * 1024 * 1024
49+
4850
input, output = IO.pipe
4951
output.timeout = 0.001
5052

5153
expect do
5254
while true
53-
output.write("Hello")
55+
output.write(big)
5456
end
5557
end.to raise_exception(::IO::TimeoutError)
5658
end

0 commit comments

Comments
 (0)