Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of fiber creation by using pool allocation strategy. #2224

Closed
wants to merge 15 commits into from

Conversation

@ioquatix
Copy link
Member

ioquatix commented Jun 2, 2019

https://bugs.ruby-lang.org/issues/15997

It would be good to get some feedback on this PR.

$ make benchmark ITEM=fiber COMPARE_RUBY="../build-master/ruby"
Calculating -------------------------------------
                     compare-ruby  built-ruby 
          make_chain       77.840      73.809 i/s -     500.000 times in 6.423414s 6.774286s
        resume_chain      161.783     168.189 i/s -     500.000 times in 3.090556s 2.972852s
  vm2_fiber_allocate      68.114k    112.117k i/s -    200.000k times in 2.936240s 1.783851s
    vm2_fiber_switch       7.812M      8.295M i/s -     10.000M times in 1.280088s 1.205587s

Comparison:
                       make_chain
        compare-ruby:        77.8 i/s 
          built-ruby:        73.8 i/s - 1.05x  slower ** n/c within margin of error

                     resume_chain
          built-ruby:       168.2 i/s 
        compare-ruby:       161.8 i/s - 1.04x  slower ** n/c within margin of error

               vm2_fiber_allocate
          built-ruby:    112117.0 i/s 
        compare-ruby:     68114.3 i/s - 1.65x  slower ** significant improvement

                 vm2_fiber_switch
          built-ruby:   8294714.5 i/s 
        compare-ruby:   7811962.9 i/s - 1.06x  slower ** n/c within margin of error
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 2, 2019

@ko1 what do you think?

@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 2, 2019

I want to test this in real world code too, but I am on holiday I don't have my desktop computer so I can't really test it at the extreme limits.

@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 2, 2019

Also, I don't expose Fiber::Pool although conceptually it could be exposed pretty easily and I think that would be a good idea.

@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch 5 times, most recently from c340778 to bc8b220 Jun 2, 2019
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 4, 2019

@ko1 I get strange error related to refinements on my desktop but not on travis:

% make test-all
../revision.h unchanged
config.status: creating ruby-runner.h
making mjit_build_dir.so
Run options: "--ruby=./miniruby -I../lib -I. -I.ext/common  ../tool/runruby.rb --extout=.ext  -- --disable-gems" --excludes-dir=../test/excludes --name=!/memory_leak/

# Running tests:

Leaked thread: Rinda::TestRingServer#test_ring_server_ipv6_multicast: #<Thread:0x000056040e910740@/home/samuel/Documents/ioquatix/ruby/lib/rinda/tuplespace.rb:617 sleep>
[ 7833/20993] TestFileExhaustive#test_birthtime = 0.07 s                                                                                   
  1) Error:
TestFileExhaustive#test_birthtime:
NotImplementedError: birthtime is unimplemented on this filesystem
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_file_exhaustive.rb:628:in `birthtime'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_file_exhaustive.rb:628:in `block in test_birthtime'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_file_exhaustive.rb:627:in `each'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_file_exhaustive.rb:627:in `test_birthtime'

[ 8996/20993] TestGc#test_latest_gc_info = 0.11 s                                                                             
  2) Failure:
TestGc#test_latest_gc_info [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_gc.rb:135]:
<:force> expected but was
<:oldmalloc>.

Leaked file descriptor: TestGem#test_use_gemdeps_automatic: 8 : #<File:/dev/null>
Leaked file descriptor: TestGem#test_use_gemdeps_automatic: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_self_pre_uninstall: 8
Closed file descriptor: TestGem#test_self_pre_uninstall: 9
Leaked file descriptor: TestGem#test_use_gemdeps_missing_gem: 8 : #<File:/dev/null>      
Leaked file descriptor: TestGem#test_use_gemdeps_missing_gem: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_self_try_activate_missing_dep: 8
Closed file descriptor: TestGem#test_self_try_activate_missing_dep: 9
Leaked file descriptor: TestGem#test_auto_activation_of_specific_gemdeps_file: 8 : #<File:/dev/null>
Leaked file descriptor: TestGem#test_auto_activation_of_specific_gemdeps_file: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_self_ensure_gem_directories: 8
Closed file descriptor: TestGem#test_self_ensure_gem_directories: 9
Leaked file descriptor: TestGem#test_self_use_gemdeps: 8 : #<File:/dev/null>                                          
Leaked file descriptor: TestGem#test_self_use_gemdeps: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_self_finish_resolve_wtf: 8
Closed file descriptor: TestGem#test_self_finish_resolve_wtf: 9
Leaked file descriptor: TestGem#test_auto_activation_of_used_gemdeps_file: 8 : #<File:/dev/null>
Leaked file descriptor: TestGem#test_auto_activation_of_used_gemdeps_file: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_use_gemdeps_argument_missing: 8
Closed file descriptor: TestGem#test_use_gemdeps_argument_missing: 9
Leaked file descriptor: TestGem#test_use_gemdeps_specific: 8 : #<File:/dev/null>   
Leaked file descriptor: TestGem#test_use_gemdeps_specific: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_self_sources: 8
Closed file descriptor: TestGem#test_self_sources: 9
Leaked file descriptor: TestGem#test_use_gemdeps: 8 : #<File:/dev/null>          
Leaked file descriptor: TestGem#test_use_gemdeps: 9 : #<File:/dev/null>
Closed file descriptor: TestGem#test_self_path: 8
Closed file descriptor: TestGem#test_self_path: 9
[14216/20993] TestPatternMatching::TestPatternMatchingRefinements#test_refinements = 0.00 s                             
  3) Error:
TestPatternMatching::TestPatternMatchingRefinements#test_refinements:
NoMatchingPatternError: #<TestPatternMatching::TestPatternMatchingRefinements::C1:0x00005604100fefc8>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_pattern_matching.rb:1126:in `block in test_refinements'
    /home/samuel/Documents/ioquatix/ruby/test/lib/test/unit/assertions.rb:51:in `assert_block'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_pattern_matching.rb:1125:in `test_refinements'

[16887/20993] TestRefinement#test_include_into_refinement = 0.00 s                                            
  4) Error:
TestRefinement#test_include_into_refinement:
NoMethodError: undefined method `foo' for #<TestRefinement::IncludeIntoRefinement::C:0x000056040e8fa9e0>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:10:in `invoke_foo_on'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:802:in `test_include_into_refinement'

[16891/20993] TestRefinement#test_instance_method_should_use_refinements = 0.00 s
  5) Error:
TestRefinement#test_instance_method_should_use_refinements:
NameError: undefined method `z' for class `TestRefinement::Foo'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:122:in `instance_method'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:122:in `instance_method_z'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:251:in `test_instance_method_should_use_refinements'

[16899/20993] TestRefinement#test_method_should_use_refinements = 0.00 s                 
  6) Error:
TestRefinement#test_method_should_use_refinements:
NameError: undefined method `z' for class `TestRefinement::Foo'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:118:in `method'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:118:in `method_z'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:230:in `test_method_should_use_refinements'

[16900/20993] TestRefinement#test_mixed_using = 0.00 s                  
  7) Failure:
TestRefinement#test_mixed_using [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:1742]:
<[:bar, [:R1, :orig_foo]]> expected but was
<[:bar, :orig_foo]>.

[16902/20993] TestRefinement#test_module_inclusion = 0.00 s
  8) Failure:
TestRefinement#test_module_inclusion [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:1045]:
<"FooExt#x"> expected but was
<"Foo#x">.

[16903/20993] TestRefinement#test_module_inclusion2 = 0.00 s
  9) Failure:
TestRefinement#test_module_inclusion2 [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:1069]:
<"FooExt2#x"> expected but was
<"Foo#x">.

[16904/20993] TestRefinement#test_module_using = 0.00 s     
 10) Failure:
TestRefinement#test_module_using [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:995]:
<"FooExt#x"> expected but was
<"Foo#x">.

[16908/20993] TestRefinement#test_new_method = 0.00 s               
 11) Error:
TestRefinement#test_new_method:
NoMethodError: undefined method `z' for #<TestRefinement::Foo:0x000056040e5cdbc8>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:98:in `invoke_z_on'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:181:in `test_new_method'

[16909/20993] TestRefinement#test_new_method_on_subclass = 0.00 s
 12) Error:
TestRefinement#test_new_method_on_subclass:
NoMethodError: undefined method `z' for #<TestRefinement::FooSub:0x000056040e5c54a0>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:98:in `invoke_z_on'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:286:in `test_new_method_on_subclass'

[16912/20993] TestRefinement#test_override = 0.00 s              
 13) Failure:
TestRefinement#test_override [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:153]:
<"FooExt#x"> expected but was
<"Foo#x">.

[16917/20993] TestRefinement#test_prepend_into_refinement = 0.00 s                  
 14) Error:
TestRefinement#test_prepend_into_refinement:
NoMethodError: undefined method `foo' for #<TestRefinement::PrependIntoRefinement::C:0x000056040df737c8>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:10:in `invoke_foo_on'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:865:in `test_prepend_into_refinement'

[16919/20993] TestRefinement#test_public_send_should_use_refinements = 0.00 s
 15) Error:
TestRefinement#test_public_send_should_use_refinements:
NoMethodError: undefined method `z' for #<TestRefinement::Foo:0x000056040df66e88>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:110:in `public_send'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:110:in `public_send_z_on'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:215:in `test_public_send_should_use_refinements'

[16926/20993] TestRefinement#test_refine_module = 0.00 s                                  
 16) Failure:
TestRefinement#test_refine_module [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:478]:
<"M@M2#foo"> expected but was
<"M#foo">.

[16946/20993] TestRefinement#test_send_should_use_refinements = 0.00 s      
 17) Error:
TestRefinement#test_send_should_use_refinements:
NoMethodError: undefined method `z' for #<TestRefinement::Foo:0x00005603d61e8860>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:102:in `send_z_on'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:205:in `test_send_should_use_refinements'

[16949/20993] TestRefinement#test_super = 0.00 s                                      
 18) Failure:
TestRefinement#test_super [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:160]:
<"FooExt#y Foo#y"> expected but was
<"Foo#y">.

[16953/20993] TestRefinement#test_super_not_chained = 0.00 s        
 19) Failure:
TestRefinement#test_super_not_chained [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:167]:
<"FooExt2#y Foo#y"> expected but was
<"Foo#y">.

[16954/20993] TestRefinement#test_super_to_module = 0.00 s  
 20) Failure:
TestRefinement#test_super_to_module [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:1957]:
[ruby-core:79588] [Bug #13227].
<"Parent -> Child"> expected but was
<"#<TestRefinement::SuperToModule::Child:0x00005603d621cb38>">.

[16955/20993] TestRefinement#test_symbol_proc = 0.00 s    
 21) Failure:
TestRefinement#test_symbol_proc [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:1839]:
<"FooExt#x"> expected but was
<"Foo#x">.

[16957/20993] TestRefinement#test_to_proc = 0.00 s               
 22) Error:
TestRefinement#test_to_proc:
TypeError: wrong argument type TestRefinement::ToProc::ReturnProc (expected Proc)
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:2099:in `call'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:2191:in `test_to_proc'

[16958/20993] TestRefinement#test_tostring = 0.00 s
 23) Failure:
TestRefinement#test_tostring [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:2065]:
<"ok"> expected but was
<"#<TestRefinement::ToString:0x00005603d62bc6b0>">.

[16968/20993] TestRefinement#test_using_same_class_refinements = 0.00 s    
 24) Failure:
TestRefinement#test_using_same_class_refinements [/home/samuel/Documents/ioquatix/ruby/test/ruby/test_refinement.rb:174]:
<"FooExt#a"> expected but was
<"Foo#a">.

[19135/20993] TestSymbol#test_to_proc_arg_with_refinements = 0.00 s                                      
 25) Error:
TestSymbol#test_to_proc_arg_with_refinements:
NoMethodError: undefined method `hoge' for #<TestSymbol::TestToPRocArgWithRefinements:0x00005603d8f01e28>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_symbol.rb:166:in `_test_to_proc_arg_with_refinements_call'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_symbol.rb:176:in `test_to_proc_arg_with_refinements'

[19136/20993] TestSymbol#test_to_proc_arg_with_refinements_override = 0.00 s
 26) Error:
TestSymbol#test_to_proc_arg_with_refinements_override:
NoMethodError: undefined method `hoge' for #<TestSymbol::TestToPRocArgWithRefinements:0x00005603d8f113c8>
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_symbol.rb:166:in `_test_to_proc_arg_with_refinements_call'
    /home/samuel/Documents/ioquatix/ruby/test/ruby/test_symbol.rb:191:in `test_to_proc_arg_with_refinements_override'

Finished tests in 616.142118s, 34.0587 tests/s, 4392.5807 assertions/s.                                        
20985 tests, 2706454 assertions, 13 failures, 13 errors, 36 skips

ruby -v: ruby 2.7.0dev (2019-06-04 fiber-pool cbce6d4f11) [x86_64-linux]
make: *** [uncommon.mk:767: yes-test-all] Error 26
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 4, 2019

On 32-bit travis test:

test_thread.rb           ...Fstderr output is not empty
   
   fiber_pool_expand: 0x414660a0, 32 x [131072]
   bootstraptest.tmp.rb: failed to allocate memory (NoMemoryError)
Fstderr output is not empty
   
   fiber_pool_expand: 0x414a80a0, 32 x [131072]
   bootstraptest.tmp.rb: failed to allocate memory (NoMemoryError)
.............................................
#1351 test_thread.rb:28:in `<top (required)>': 
   begin
     :ok if 5000 == 5000.times{|e|
       (1..2).map{
         Thread.new{
         }
       }.each{|e|
         e.join()
       }
     }
   rescue ThreadError => e
     :ok if /can't create Thread/ =~ e.message
   end
  #=> "" (expected "ok")  
#1352 test_thread.rb:42:in `<top (required)>': 
   begin
     :ok if 5000 == 5000.times{|e|
       (1..2).map{
         Thread.new{
         }
       }.each{|e|
         e.join(1000000000)
       }
     }
   rescue ThreadError => e
     :ok if /can't create Thread/ =~ e.message
   end
  #=> "" (expected "ok")  
FAIL 2/1397 tests failed
uncommon.mk:741: recipe for target 'yes-btest-ruby' failed
make: *** [yes-btest-ruby] Error 1
The command "$SETARCH make -s test TESTOPTS="${TESTOPTS=$JOBS -q --tty=no}"" exited with 2.
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch 4 times, most recently from ea78187 to 3a0928b Jun 4, 2019
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 4, 2019

@ko1 I managed to catch rb_memerror and it seems something is wrong with rb_thread_recycle_stack. I'm no longer using this function in fiber code, but now thread has got issues.

#0  0x00007fabb3530908 in nanosleep () from /usr/lib/libc.so.6
#1  0x00007fabb353080e in sleep () from /usr/lib/libc.so.6
#2  0x00005571a6d113a0 in rb_memerror () at ../gc.c:9388
#3  0x00005571a6d115a1 in ruby_memerror () at ../gc.c:9366
#4  objspace_xmalloc0 (objspace=0x5571a82e7240, size=<optimized out>) at ../gc.c:9641
#5  0x00005571a6ea9bdd in rb_thread_recycle_stack (size=131072) at ../vm.c:2461
#6  rb_thread_recycle_stack (size=131072) at ../vm.c:2453
#7  th_init (th=th@entry=0x5571a846b6c0, self=self@entry=93946641300080) at ../vm.c:2655
#8  0x00005571a6ec5848 in ruby_thread_init (self=93946641300080) at ../vm.c:2689
#9  rb_thread_alloc (klass=klass@entry=93946641601040) at ../vm.c:2702
#10 0x00005571a6e7360b in thread_s_new (argc=0, argv=0x7fabb30320d0, klass=93946641601040) at ../thread.c:872
#11 0x00005571a6eabe3d in vm_call_cfunc_with_frame (ci=0x5571a8454f60, cc=<optimized out>, calling=<optimized out>, reg_cfp=0x7fabb3131ec0, 
    ec=0x5571a82e76b8) at ../vm_insnhelper.c:2212
#12 vm_call_cfunc (ec=<optimized out>, reg_cfp=<optimized out>, calling=<optimized out>, ci=<optimized out>, cc=<optimized out>)
    at ../vm_insnhelper.c:2230
#13 0x00005571a6ebdada in vm_sendish (method_explorer=<optimized out>, block_handler=<optimized out>, cc=<optimized out>, ci=<optimized out>, 
    reg_cfp=<optimized out>, ec=<optimized out>) at ../vm_insnhelper.c:3628
#14 vm_exec_core (ec=0x7ffd59d78210, initial=140726110749200) at ../insns.def:771
#15 0x00005571a6eb4bac in rb_vm_exec (ec=0x5571a82e76b8, mjit_enable_p=1) at ../vm.c:1890
#16 0x00005571a6eb56c8 in invoke_iseq_block_from_c (me=0x0, is_lambda=-1290592376, cref=<optimized out>, passed_block_handler=<optimized out>, 
    argv=<optimized out>, argc=1, self=93946620106395, captured=0x7fabb3131fb8, ec=0x5571a82e76b8) at ../vm.c:1102
#17 invoke_block_from_c_bh (argc=<optimized out>, passed_block_handler=<optimized out>, cref=<optimized out>, is_lambda=<optimized out>, 
    force_blockarg=<optimized out>, argv=<optimized out>, block_handler=<optimized out>, ec=<optimized out>) at ../vm.c:1120
#18 vm_yield (argc=1, argv=<optimized out>, ec=<optimized out>) at ../vm.c:1165
#19 rb_yield_0 (argv=<optimized out>, argc=1) at ../vm_eval.c:994
#20 catch_i (tag=<optimized out>, data=<optimized out>) at ../vm_eval.c:1915
#21 0x00005571a82fe968 in ?? ()
#22 0x00007fabb3131f88 in ?? ()
#23 0x00005571a6eb5e19 in vm_yield (argv=<optimized out>, argc=<optimized out>, ec=<optimized out>) at ../vm.c:1151
#24 rb_yield_0 (argv=<optimized out>, argc=<optimized out>) at ../vm_eval.c:994
#25 rb_yield_values2 (argc=<optimized out>, argv=<optimized out>) at ../vm_eval.c:1040
#26 0x00005571a6f4e27e in collect_i (i=<optimized out>, ary=8409590266739931136, argc=<optimized out>, argv=<optimized out>, 
    blockarg=<optimized out>) at ../enum.c:539
#27 0x00005571a6eb0f2d in vm_yield_with_cfunc (ec=ec@entry=0x5571a82e76b8, self=93946641377040, argc=77, argc@entry=1, 
    argv=argv@entry=0x7ffd59d787b8, block_handler=0, me=0x0, captured=<optimized out>, captured=<optimized out>) at ../vm_insnhelper.c:2865
#28 0x00005571a6ec430e in invoke_block_from_c_bh (argc=<optimized out>, passed_block_handler=<optimized out>, cref=<optimized out>, 
    is_lambda=<optimized out>, force_blockarg=<optimized out>, argv=<optimized out>, block_handler=<optimized out>, ec=<optimized out>)
    at ../vm_core.h:1433
#29 vm_yield (argc=1, argv=0x7ffd59d787b8, ec=0x5571a82e76b8) at ../vm.c:1165
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch from fa8ac15 to aae6524 Jun 4, 2019
@ioquatix ioquatix changed the title Fiber pool Improve performance of fiber creation by using pool allocation strategy. Jun 5, 2019
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jun 5, 2019

@ko1 this is now only blocking on one test failure which I don't know how should be fixed:

  1) Failure:
3729TestGc#test_latest_gc_info [C:/projects/ruby/test/ruby/test_gc.rb:135]:
3730<:force> expected but was
3731<:oldmalloc>.
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch 6 times, most recently from e9ea7ea to 6d49a46 Jun 19, 2019
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch 6 times, most recently from 4aea3c8 to eac8077 Jun 27, 2019
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch 8 times, most recently from 2ecab3e to 88f05f5 Jul 12, 2019
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jul 16, 2019

image

ioquatix added 14 commits Jun 1, 2019
Replace previous stack cache with fiber pool cache. The fiber pool
allocates many stacks in a single memory region. Stack allocation
becomes O(log N) and fiber creation is amortized O(1). Around 10x
performance improvement was measured in micro-benchmarks.
On 32-bit platforms, expanding the fiber pool by a large amount may fail,
even if a smaller amount may succeed. We limit the maximum size of a single
allocation to maximise the number of fibers that can be allocated.

Additionally, we implement the book-keeping required to free allocations
when their usage falls to zero.
`madvise(free)` and similar operations are good because they avoid swap
usage by clearing the dirty bit on memory pages which are mapped but no
longer needed. However, there is some performance penalty if there is no
memory pressure. Therefore, we do it by default, but it can be avoided.
…pace.

We use COROUTINE_LIMITED_ADDRESS_SPACE to select platforms where address
space is 32-bits or less. Fiber pool implementation enables more book
keeping, and reduces upper limits, in order to minimise address space
utilisation.
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch from 3330760 to 3eb1204 Jul 18, 2019
If `mmap` fails to allocate memory, try half the size, and so on.

Limit FIBER_POOL_ALLOCATION_MAXIMUM_SIZE to 1024 stacks. In typical
configurations this limits the memory mapped region to ~128MB per
allocation.
@ioquatix ioquatix force-pushed the ioquatix:fiber-pool branch from 89e9452 to 7ed0e4c Jul 18, 2019
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jul 18, 2019

Okay, it was merged.

@ioquatix ioquatix closed this Jul 18, 2019
@ioquatix

This comment has been minimized.

Copy link
Member Author

ioquatix commented Jul 18, 2019

image

@eregon eregon mentioned this pull request Dec 30, 2019
28 of 70 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants
You can’t perform that action at this time.