concurrently 1.0.1 → 1.1.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/.gitignore +1 -1
- data/.travis.yml +8 -3
- data/README.md +70 -60
- data/RELEASE_NOTES.md +16 -1
- data/Rakefile +98 -14
- data/concurrently.gemspec +16 -12
- data/ext/mruby/io.rb +1 -1
- data/guides/Overview.md +191 -66
- data/guides/Performance.md +300 -102
- data/guides/Troubleshooting.md +28 -28
- data/lib/Ruby/concurrently/proc/evaluation/error.rb +10 -0
- data/lib/all/concurrently/error.rb +0 -3
- data/lib/all/concurrently/evaluation.rb +8 -12
- data/lib/all/concurrently/event_loop.rb +1 -1
- data/lib/all/concurrently/event_loop/fiber.rb +3 -3
- data/lib/all/concurrently/event_loop/io_selector.rb +1 -1
- data/lib/all/concurrently/event_loop/run_queue.rb +29 -17
- data/lib/all/concurrently/proc.rb +13 -13
- data/lib/all/concurrently/proc/evaluation.rb +29 -29
- data/lib/all/concurrently/proc/evaluation/error.rb +13 -0
- data/lib/all/concurrently/proc/fiber.rb +3 -6
- data/lib/all/concurrently/version.rb +1 -1
- data/lib/all/io.rb +118 -41
- data/lib/all/kernel.rb +82 -29
- data/lib/mruby/concurrently/event_loop/io_selector.rb +46 -0
- data/lib/mruby/kernel.rb +1 -1
- data/mrbgem.rake +28 -17
- data/mruby_builds/build_config.rb +67 -0
- data/perf/Ruby/stage.rb +23 -0
- data/perf/benchmark_call_methods.rb +32 -0
- data/perf/benchmark_call_methods_waiting.rb +52 -0
- data/perf/benchmark_wait_methods.rb +38 -0
- data/perf/mruby/stage.rb +8 -0
- data/perf/profile_await_readable.rb +10 -0
- data/perf/{concurrent_proc_call.rb → profile_call.rb} +1 -5
- data/perf/{concurrent_proc_call_and_forget.rb → profile_call_and_forget.rb} +1 -5
- data/perf/{concurrent_proc_call_detached.rb → profile_call_detached.rb} +1 -5
- data/perf/{concurrent_proc_call_nonblock.rb → profile_call_nonblock.rb} +1 -5
- data/perf/profile_wait.rb +7 -0
- data/perf/stage.rb +47 -0
- data/perf/stage/benchmark.rb +47 -0
- data/perf/stage/benchmark/code_gen.rb +29 -0
- data/perf/stage/benchmark/code_gen/batch.rb +41 -0
- data/perf/stage/benchmark/code_gen/single.rb +38 -0
- metadata +27 -23
- data/ext/mruby/array.rb +0 -19
- data/lib/Ruby/concurrently/error.rb +0 -4
- data/perf/_shared/stage.rb +0 -33
- data/perf/concurrent_proc_calls.rb +0 -49
- data/perf/concurrent_proc_calls_awaiting.rb +0 -48
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module Concurrently
         | 
| 2 | 
            +
              # @private
         | 
| 3 | 
            +
              class EventLoop::IOSelector
         | 
| 4 | 
            +
                def initialize(event_loop)
         | 
| 5 | 
            +
                  @run_queue = event_loop.run_queue
         | 
| 6 | 
            +
                  @poll = Poll.new
         | 
| 7 | 
            +
                  @fds = {}
         | 
| 8 | 
            +
                  @evaluations = {}
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def awaiting?
         | 
| 12 | 
            +
                  @evaluations.size > 0
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def await_reader(io, evaluation)
         | 
| 16 | 
            +
                  fd = @poll.add(io, Poll::In)
         | 
| 17 | 
            +
                  @fds.store io, fd
         | 
| 18 | 
            +
                  @evaluations.store fd, evaluation
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def await_writer(io, evaluation)
         | 
| 22 | 
            +
                  fd = @poll.add(io, Poll::Out)
         | 
| 23 | 
            +
                  @fds.store io, fd
         | 
| 24 | 
            +
                  @evaluations.store fd, evaluation
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def cancel_reader(io)
         | 
| 28 | 
            +
                  fd = @fds.delete io
         | 
| 29 | 
            +
                  @poll.remove fd
         | 
| 30 | 
            +
                  @evaluations.delete fd
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def cancel_writer(io)
         | 
| 34 | 
            +
                  fd = @fds.delete io
         | 
| 35 | 
            +
                  @poll.remove fd
         | 
| 36 | 
            +
                  @evaluations.delete fd
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def process_ready_in(waiting_time)
         | 
| 40 | 
            +
                  waiting_time = -1 if waiting_time == Float::INFINITY
         | 
| 41 | 
            +
                  if ready = @poll.wait(waiting_time)
         | 
| 42 | 
            +
                    ready.each{ |fd| @run_queue.resume_evaluation! @evaluations[fd], true }
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
    
        data/lib/mruby/kernel.rb
    CHANGED
    
    | @@ -4,7 +4,7 @@ module Kernel | |
| 4 4 | 
             
              # Reimplements Kernel#concurrently. mruby does not support Proc.new without
         | 
| 5 5 | 
             
              # a block.
         | 
| 6 6 | 
             
              private def concurrently(*args, &block)
         | 
| 7 | 
            -
                Concurrently::Proc.new(&block). | 
| 7 | 
            +
                Concurrently::Proc.new(&block).call_detached *args
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 10 | 
             
              # Reimplements Kernel#concurrent_proc. mruby does not support Proc.new without
         | 
    
        data/mrbgem.rake
    CHANGED
    
    | @@ -3,19 +3,23 @@ require_relative 'lib/all/concurrently/version' | |
| 3 3 | 
             
            MRuby::Gem::Specification.new('mruby-concurrently') do |spec|
         | 
| 4 4 | 
             
              spec.version      = Concurrently::VERSION
         | 
| 5 5 | 
             
              spec.summary      = %q{A concurrency framework based on fibers}
         | 
| 6 | 
            -
              spec.description  =  | 
| 7 | 
            -
            Concurrently is a concurrency framework for Ruby and mruby | 
| 8 | 
            -
            code can be  | 
| 6 | 
            +
              spec.description  = <<'DESC'
         | 
| 7 | 
            +
            Concurrently is a concurrency framework for Ruby and mruby based on
         | 
| 8 | 
            +
            fibers. With it code can be evaluated independently in its own execution
         | 
| 9 | 
            +
            context similar to a thread:
         | 
| 9 10 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 11 | 
            +
                hello = concurrently do
         | 
| 12 | 
            +
                  wait 0.2 # seconds
         | 
| 13 | 
            +
                  "hello"
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                world = concurrently do
         | 
| 17 | 
            +
                  wait 0.1 # seconds
         | 
| 18 | 
            +
                  "world"
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                puts "#{hello.await_result} #{world.await_result}"
         | 
| 22 | 
            +
            DESC
         | 
| 19 23 |  | 
| 20 24 | 
             
              spec.homepage     = "https://github.com/christopheraue/m-ruby-concurrently"
         | 
| 21 25 | 
             
              spec.license      = 'Apache-2.0'
         | 
| @@ -32,11 +36,18 @@ evaluations). | |
| 32 36 | 
             
                Dir["#{spec.dir}/lib/mruby/**/*.rb"].sort
         | 
| 33 37 | 
             
              spec.test_rbfiles = Dir["#{spec.dir}/test/mruby/*.rb"]
         | 
| 34 38 |  | 
| 35 | 
            -
              spec.add_dependency 'mruby-array-ext'
         | 
| 36 | 
            -
              spec.add_dependency 'mruby-numeric-ext'
         | 
| 37 | 
            -
              spec.add_dependency 'mruby-enumerator'
         | 
| 38 | 
            -
              spec.add_dependency 'mruby-fiber'
         | 
| 39 | 
            -
              spec.add_dependency 'mruby-time'
         | 
| 39 | 
            +
              spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext'
         | 
| 40 | 
            +
              spec.add_dependency 'mruby-numeric-ext', :core => 'mruby-numeric-ext'
         | 
| 41 | 
            +
              spec.add_dependency 'mruby-enumerator', :core => 'mruby-enumerator'
         | 
| 42 | 
            +
              spec.add_dependency 'mruby-fiber', :core => 'mruby-fiber'
         | 
| 43 | 
            +
              spec.add_dependency 'mruby-time', :core => 'mruby-time'
         | 
| 40 44 | 
             
              spec.add_dependency 'mruby-io'
         | 
| 41 45 | 
             
              spec.add_dependency 'mruby-callbacks_attachable', '~> 2.2', github: 'christopheraue/m-ruby-callbacks_attachable'
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              # use mruby-poll only on unix-like OSes
         | 
| 48 | 
            +
              if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
         | 
| 49 | 
            +
                spec.rbfiles.delete "#{spec.dir}/lib/mruby/concurrently/event_loop/io_selector.rb"
         | 
| 50 | 
            +
              else
         | 
| 51 | 
            +
                spec.add_dependency 'mruby-poll'
         | 
| 52 | 
            +
              end
         | 
| 42 53 | 
             
            end
         | 
| @@ -0,0 +1,67 @@ | |
| 1 | 
            +
            MRuby::Build.new do
         | 
| 2 | 
            +
              if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
         | 
| 3 | 
            +
                toolchain :visualcpp
         | 
| 4 | 
            +
              else
         | 
| 5 | 
            +
                toolchain :gcc
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              enable_debug
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            MRuby::Build.new 'test', File.dirname(__FILE__) do
         | 
| 12 | 
            +
              self.gem_clone_dir = "#{MRUBY_ROOT}/build/mrbgems"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
         | 
| 15 | 
            +
                toolchain :visualcpp
         | 
| 16 | 
            +
              else
         | 
| 17 | 
            +
                toolchain :gcc
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              enable_test
         | 
| 21 | 
            +
              gem File.expand_path File.dirname File.dirname __FILE__
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            MRuby::Build.new 'benchmark', File.dirname(__FILE__) do
         | 
| 25 | 
            +
              self.gem_clone_dir = "#{MRUBY_ROOT}/build/mrbgems"
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
         | 
| 28 | 
            +
                toolchain :visualcpp
         | 
| 29 | 
            +
              else
         | 
| 30 | 
            +
                toolchain :gcc
         | 
| 31 | 
            +
                cc.flags << '-O3'
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              gem core: 'mruby-bin-mruby'
         | 
| 35 | 
            +
              gem core: 'mruby-bin-mirb'
         | 
| 36 | 
            +
              gem core: 'mruby-proc-ext'
         | 
| 37 | 
            +
              gem core: 'mruby-sprintf'
         | 
| 38 | 
            +
              gem core: 'mruby-eval'
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              gem_dir = File.expand_path File.dirname File.dirname __FILE__
         | 
| 41 | 
            +
              gem gem_dir do |gem|
         | 
| 42 | 
            +
                gem.rbfiles += Dir["#{gem_dir}/perf/{stage.rb,stage/**/*.rb}"]
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
            end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            MRuby::Build.new 'profile', File.dirname(__FILE__) do
         | 
| 47 | 
            +
              self.gem_clone_dir = "#{MRUBY_ROOT}/build/mrbgems"
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
         | 
| 50 | 
            +
                toolchain :visualcpp
         | 
| 51 | 
            +
              else
         | 
| 52 | 
            +
                toolchain :gcc
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              enable_debug
         | 
| 56 | 
            +
              cc.defines = %w(MRB_ENABLE_DEBUG_HOOK)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              gem github: 'miura1729/mruby-profiler'
         | 
| 59 | 
            +
              gem core: 'mruby-bin-mruby'
         | 
| 60 | 
            +
              gem core: 'mruby-proc-ext'
         | 
| 61 | 
            +
              gem core: 'mruby-sprintf'
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              gem_dir = File.expand_path File.dirname File.dirname __FILE__
         | 
| 64 | 
            +
              gem gem_dir do |gem|
         | 
| 65 | 
            +
                gem.rbfiles << "#{gem_dir}/perf/stage.rb" << "#{gem_dir}/perf/mruby/stage.rb"
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         | 
    
        data/perf/Ruby/stage.rb
    ADDED
    
    | @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'bundler'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Bundler.require :default
         | 
| 4 | 
            +
            Bundler.require :perf
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            perf = File.dirname File.dirname __FILE__
         | 
| 7 | 
            +
            Dir["#{perf}/{stage.rb,stage/**/*.rb}"].sort.each{ |f| require f }
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            class Stage
         | 
| 10 | 
            +
              def profile(seconds: 1, printer: 'flat')
         | 
| 11 | 
            +
                gc_disabled do
         | 
| 12 | 
            +
                  profile = RubyProf::Profile.new(merge_fibers: true).tap(&:start)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  result = execute(seconds: seconds){ yield }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  printer[0] = printer[0].capitalize
         | 
| 17 | 
            +
                  RubyProf.const_get("#{printer}Printer").new(profile.stop).print(STDOUT, sort_method: :self_time)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  result
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            stage = Stage.new
         | 
| 2 | 
            +
            batch_size = ARGV.fetch(0, 1).to_i
         | 
| 3 | 
            +
            print_results_only = ARGV[1] == 'skip_header'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            stage.benchmark 'proc.call',
         | 
| 6 | 
            +
              batch_size: batch_size,
         | 
| 7 | 
            +
              proc: "proc{}",
         | 
| 8 | 
            +
              call: :call
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            stage.benchmark 'conproc.call',
         | 
| 11 | 
            +
              batch_size: batch_size,
         | 
| 12 | 
            +
              proc: "concurrent_proc{}",
         | 
| 13 | 
            +
              call: :call
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            stage.benchmark 'conproc.call_nonblock',
         | 
| 16 | 
            +
              batch_size: batch_size,
         | 
| 17 | 
            +
              proc: "concurrent_proc{}",
         | 
| 18 | 
            +
              call: :call_nonblock
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            stage.benchmark 'conproc.call_detached',
         | 
| 21 | 
            +
              batch_size: batch_size,
         | 
| 22 | 
            +
              proc: "concurrent_proc{}",
         | 
| 23 | 
            +
              call: :call_detached,
         | 
| 24 | 
            +
              sync: :wait
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            stage.benchmark 'conproc.call_and_forget',
         | 
| 27 | 
            +
              batch_size: batch_size,
         | 
| 28 | 
            +
              proc: "concurrent_proc{}",
         | 
| 29 | 
            +
              call: :call_and_forget,
         | 
| 30 | 
            +
              sync: :wait
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            stage.perform print_results_only
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            stage = Stage.new
         | 
| 2 | 
            +
            batch_size = ARGV.fetch(0, 1).to_i
         | 
| 3 | 
            +
            print_results_only = ARGV[1] == 'skip_header'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            stage.benchmark 'call',
         | 
| 6 | 
            +
              batch_size: batch_size,
         | 
| 7 | 
            +
              proc: "concurrent_proc{}",
         | 
| 8 | 
            +
              call: :call,
         | 
| 9 | 
            +
              sync: true
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            stage.benchmark 'call_nonblock',
         | 
| 12 | 
            +
              batch_size: batch_size,
         | 
| 13 | 
            +
              proc: "concurrent_proc{}",
         | 
| 14 | 
            +
              call: :call_nonblock
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            stage.benchmark 'call_detached',
         | 
| 17 | 
            +
              batch_size: batch_size,
         | 
| 18 | 
            +
              proc: "concurrent_proc{}",
         | 
| 19 | 
            +
              call: :call_detached,
         | 
| 20 | 
            +
              sync: true
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            stage.benchmark 'call_and_forget',
         | 
| 23 | 
            +
              batch_size: batch_size,
         | 
| 24 | 
            +
              proc: "concurrent_proc{}",
         | 
| 25 | 
            +
              call: :call_and_forget,
         | 
| 26 | 
            +
              sync: true
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            stage.benchmark 'waiting call',
         | 
| 29 | 
            +
              batch_size: batch_size,
         | 
| 30 | 
            +
              proc: "concurrent_proc{ wait 0 }",
         | 
| 31 | 
            +
              call: :call,
         | 
| 32 | 
            +
              sync: true
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            stage.benchmark 'waiting call_nonblock',
         | 
| 35 | 
            +
              batch_size: batch_size,
         | 
| 36 | 
            +
              proc: "concurrent_proc{ wait 0 }",
         | 
| 37 | 
            +
              call: :call_nonblock,
         | 
| 38 | 
            +
              sync: true
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            stage.benchmark 'waiting call_detached',
         | 
| 41 | 
            +
              batch_size: batch_size,
         | 
| 42 | 
            +
              proc: "concurrent_proc{ wait 0 }",
         | 
| 43 | 
            +
              call: :call_detached,
         | 
| 44 | 
            +
              sync: true
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            stage.benchmark 'waiting call_and_forget',
         | 
| 47 | 
            +
              batch_size: batch_size,
         | 
| 48 | 
            +
              proc: "concurrent_proc{ wait 0 }",
         | 
| 49 | 
            +
              call: :call_and_forget,
         | 
| 50 | 
            +
              sync: true
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            stage.perform print_results_only
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            stage = Stage.new
         | 
| 2 | 
            +
            batch_size = ARGV.fetch(0, 1).to_i
         | 
| 3 | 
            +
            print_results_only = ARGV[1] == 'skip_header'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            stage.benchmark :wait,
         | 
| 6 | 
            +
              batch_size: batch_size,
         | 
| 7 | 
            +
              proc: <<RUBY, call: :call
         | 
| 8 | 
            +
            proc do
         | 
| 9 | 
            +
              wait 0 # schedule the proc be resumed ASAP
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
            RUBY
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            stage.benchmark "await_readable",
         | 
| 14 | 
            +
              batch_size: batch_size,
         | 
| 15 | 
            +
              proc: <<RUBY, call: :call, args: <<RUBY
         | 
| 16 | 
            +
            proc do |r,w|
         | 
| 17 | 
            +
              r.await_readable
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
            RUBY
         | 
| 20 | 
            +
            IO.pipe.tap{ |r,w| w.write '0' }
         | 
| 21 | 
            +
            RUBY
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            stage.benchmark "await_writable",
         | 
| 24 | 
            +
              batch_size: batch_size,
         | 
| 25 | 
            +
              proc: <<RUBY, call: :call, args: <<RUBY
         | 
| 26 | 
            +
            proc do |r,w|
         | 
| 27 | 
            +
              w.await_writable
         | 
| 28 | 
            +
            end
         | 
| 29 | 
            +
            RUBY
         | 
| 30 | 
            +
            IO.pipe
         | 
| 31 | 
            +
            RUBY
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            # Warm up
         | 
| 34 | 
            +
            wait_proc = concurrent_proc{ wait 0 }
         | 
| 35 | 
            +
            stage.execute{ wait_proc.call }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            # Performance
         | 
| 38 | 
            +
            stage.perform print_results_only
         | 
    
        data/perf/mruby/stage.rb
    ADDED
    
    
| @@ -1,13 +1,9 @@ | |
| 1 | 
            -
            #!/bin/env ruby
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require_relative "_shared/stage"
         | 
| 4 | 
            -
             | 
| 5 1 | 
             
            stage = Stage.new
         | 
| 6 2 |  | 
| 7 3 | 
             
            evaluation = Concurrently::Evaluation.current
         | 
| 8 4 | 
             
            conproc = concurrent_proc{ evaluation.resume! }
         | 
| 9 5 |  | 
| 10 | 
            -
            result = stage. | 
| 6 | 
            +
            result = stage.profile(seconds: 1) do
         | 
| 11 7 | 
             
              conproc.call_and_forget
         | 
| 12 8 | 
             
              await_resume!
         | 
| 13 9 | 
             
            end
         | 
| @@ -1,13 +1,9 @@ | |
| 1 | 
            -
            #!/bin/env ruby
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require_relative "_shared/stage"
         | 
| 4 | 
            -
             | 
| 5 1 | 
             
            stage = Stage.new
         | 
| 6 2 |  | 
| 7 3 | 
             
            evaluation = Concurrently::Evaluation.current
         | 
| 8 4 | 
             
            conproc = concurrent_proc{ evaluation.resume! }
         | 
| 9 5 |  | 
| 10 | 
            -
            result = stage. | 
| 6 | 
            +
            result = stage.profile(seconds: 1) do
         | 
| 11 7 | 
             
              conproc.call_detached
         | 
| 12 8 | 
             
              await_resume!
         | 
| 13 9 | 
             
            end
         | 
    
        data/perf/stage.rb
    ADDED
    
    | @@ -0,0 +1,47 @@ | |
| 1 | 
            +
            class Stage
         | 
| 2 | 
            +
              def initialize
         | 
| 3 | 
            +
                @benchmarks = []
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def gc_disabled
         | 
| 7 | 
            +
                GC.start
         | 
| 8 | 
            +
                GC.disable
         | 
| 9 | 
            +
                yield
         | 
| 10 | 
            +
              ensure
         | 
| 11 | 
            +
                GC.enable
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def execute(opts = {})
         | 
| 15 | 
            +
                seconds = opts[:seconds] || 1
         | 
| 16 | 
            +
                event_loop = Concurrently::EventLoop.current
         | 
| 17 | 
            +
                event_loop.reinitialize!
         | 
| 18 | 
            +
                iterations = 0
         | 
| 19 | 
            +
                start_time = event_loop.lifetime
         | 
| 20 | 
            +
                end_time = start_time + seconds
         | 
| 21 | 
            +
                while event_loop.lifetime < end_time
         | 
| 22 | 
            +
                  yield
         | 
| 23 | 
            +
                  iterations += 1
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
                stop_time = event_loop.lifetime
         | 
| 26 | 
            +
                { iterations: iterations, time: (stop_time-start_time) }
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def benchmark(*args)
         | 
| 30 | 
            +
                @benchmarks << Benchmark.new(self, *args)
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def perform(print_results_only = false)
         | 
| 34 | 
            +
                if @benchmarks.size
         | 
| 35 | 
            +
                  unless print_results_only
         | 
| 36 | 
            +
                    puts Benchmark.header
         | 
| 37 | 
            +
                    @benchmarks.each do |b|
         | 
| 38 | 
            +
                      puts b.desc
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                  puts Benchmark.result_header
         | 
| 42 | 
            +
                  @benchmarks.each{ |b| b.run }
         | 
| 43 | 
            +
                  puts
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| 47 | 
            +
             |