Project

General

Profile

Actions

Misc #16124

open

Let the transient heap belong to objspace

Added by methodmissing (Lourens Naudé) about 5 years ago. Updated about 5 years ago.

Status:
Assigned
[ruby-core:94530]

Description

As per comment from Nobu in https://github.com/ruby/ruby/pull/2303#issuecomment-523248875 , I took an initial stab @ a tighter integration between objspace and the transient heap in https://github.com/ruby/ruby/pull/2400

Benefits

  • Multi-VM (MVM) friendly - ( vm -> objspace -> theap )
  • The 32MB (current size) arena lazy allocated on ruby init is now properly freed on shutdown as well
  • It feels strange that the evacuation from the current global theap is to objspace, whereas the space evacuated from is a global arena.

Not so great

  • A fast reference to a global variable global_transient_heap becomes a function call to rb_objspace_get_theap() and related pointer chasing from vm -> objspace -> theap
  • Some internal transient heap structs moved to the header file now leaks into all other reference sites where this source file (transient_heap.c) as previously just used for API
  • I'm not sure exactly of the boundary Koichi had in mind for the GC compile module and how tightly it should (or shouldn't) be coupled to the transient heap. struct rb_objspace* declarations elsewhere for example reveals nothing about the structure members for example, whereas with this PR a lot of transient heap internals are exposed via the header file now
  • Also possible to move transient_heap.c into gc.c - I feel theap is not an experimental feature anymore and has been stable for quite some time with plausible performance benefits. The downside of that is gc.c is quite dense already, but then all ruby heap management concerns belong to one compile unit.

In a similar vein the global method cache could perhaps belong to the VM instance as well, effectively better alignment with MVM and also easier to have a balanced VM setup and teardown sequence without anything left dangling on ruby shutdown.

Thoughts?

Updated by mame (Yusuke Endoh) about 5 years ago

  • Status changed from Open to Assigned
  • Assignee set to ko1 (Koichi Sasada)

Updated by nobu (Nobuyoshi Nakada) about 5 years ago

I'm positive about this, except for the performance.
Do you have any numbers?

Updated by methodmissing (Lourens Naudé) about 5 years ago

nobu (Nobuyoshi Nakada) wrote:

I'm positive about this, except for the performance.
Do you have any numbers?

Using the rdoc gc bench tooling Koichi used in https://bugs.ruby-lang.org/issues/14858, it's difficult to get consistent results between this change and master.

Master:

lourens@CarbonX1:~/src/ruby/trunk$ make gcbench-rdoc
Script: ./benchmark/gc/rdoc.rb
{:count=>137,
 :heap_allocated_pages=>10124,
 :heap_sorted_length=>10124,
 :heap_allocatable_pages=>0,
 :heap_available_slots=>4126494,
 :heap_live_slots=>4117009,
 :heap_free_slots=>9485,
 :heap_final_slots=>0,
 :heap_marked_slots=>2396930,
 :heap_eden_pages=>10124,
 :heap_tomb_pages=>0,
 :total_allocated_pages=>10124,
 :total_freed_pages=>0,
 :total_allocated_objects=>24630985,
 :total_freed_objects=>20513976,
 :malloc_increase_bytes=>23046392,
 :malloc_increase_bytes_limit=>32225676,
 :minor_gc_count=>113,
 :object_id_collisions=>0,
 :major_gc_count=>24,
 :remembered_wb_unprotected_objects=>2482,
 :remembered_wb_unprotected_objects_limit=>4964,
 :old_objects=>2387069,
 :old_objects_limit=>4774138,
 :oldmalloc_increase_bytes=>48011656,
 :oldmalloc_increase_bytes_limit=>41096563}
ruby 2.7.0dev (2019-09-22T07:39:47Z master 2272efa463) [x86_64-linux] ["USE_RGENGC", "RGENGC_DEBUG", "RGENGC_ESTIMATE_OLDMALLOC", "GC_ENABLE_LAZY_SWEEP"]

./benchmark/gc/rdoc.rb
      user     system      total        real
 18.842867   0.687732  19.530599 ( 19.722540)
GC total time (sec): 0

VmHWM: 411940 kB

Summary of rdoc on 2.7.0dev	19.722539804002736	0	137
         (real time in sec, GC time in sec, GC count)

Objspace linked theap:

lourens@CarbonX1:~/src/ruby/ruby$ make gcbench-rdoc
Script: ./benchmark/gc/rdoc.rb
{:count=>137,
 :heap_allocated_pages=>10122,
 :heap_sorted_length=>10122,
 :heap_allocatable_pages=>0,
 :heap_available_slots=>4125809,
 :heap_live_slots=>4116170,
 :heap_free_slots=>9639,
 :heap_final_slots=>0,
 :heap_marked_slots=>2396677,
 :heap_eden_pages=>10122,
 :heap_tomb_pages=>0,
 :total_allocated_pages=>10122,
 :total_freed_pages=>0,
 :total_allocated_objects=>24630955,
 :total_freed_objects=>20514785,
 :malloc_increase_bytes=>23055352,
 :malloc_increase_bytes_limit=>32225676,
 :minor_gc_count=>113,
 :object_id_collisions=>0,
 :major_gc_count=>24,
 :remembered_wb_unprotected_objects=>2482,
 :remembered_wb_unprotected_objects_limit=>4964,
 :old_objects=>2387070,
 :old_objects_limit=>4774140,
 :oldmalloc_increase_bytes=>47981528,
 :oldmalloc_increase_bytes_limit=>41096563}
ruby 2.7.0dev (2019-09-22T11:43:20Z objspace-theap 11b7839f09) [x86_64-linux] ["USE_RGENGC", "RGENGC_DEBUG", "RGENGC_ESTIMATE_OLDMALLOC", "GC_ENABLE_LAZY_SWEEP"]

./benchmark/gc/rdoc.rb
      user     system      total        real
 18.517571   0.764057  19.281628 ( 19.303723)
GC total time (sec): 0

VmHWM: 411780 kB

Summary of rdoc on 2.7.0dev	19.303723024990177	0	137
         (real time in sec, GC time in sec, GC count)

Array specific (adapted from the original issue to include RUBY_DESCRIPTION):

p RUBY_DESCRIPTION
require 'benchmark'
N = 10_000_000

def n_times str, args = ''
  eval <<-EOS
    proc{|max, #{args}|
      i = 0
      while i < max
        #{str}
        i+=1
      end
    }
  EOS
end

m = n_times 'ary = Array.new(size)', 'size'

Benchmark.bm(10){|x|
  0.step(to: 16){|i|
    size = i
    x.report(size){
      m.call(N, size)
    }
  }
}

objspace-theap branch:

lourens@CarbonX1:~/src/ruby/ruby$ ./miniruby -Ilib $HOME/src/theap_array.rb
"ruby 2.7.0dev (2019-09-22T11:43:20Z objspace-theap 11b7839f09) [x86_64-linux]"
                 user     system      total        real
0            1.060482   0.000000   1.060482 (  1.060477)
1            1.063371   0.000000   1.063371 (  1.063398)
2            1.049839   0.000000   1.049839 (  1.049846)
3            1.066307   0.000000   1.066307 (  1.066311)
4            1.187135   0.000000   1.187135 (  1.187147)
5            1.130953   0.000000   1.130953 (  1.130964)
6            1.160799   0.000000   1.160799 (  1.160805)
7            1.220265   0.000000   1.220265 (  1.220272)
8            1.160544   0.000000   1.160544 (  1.160554)
9            1.262271   0.000000   1.262271 (  1.262282)
10           1.182926   0.000000   1.182926 (  1.182933)
11           1.305176   0.000000   1.305176 (  1.305187)
12           1.170598   0.000000   1.170598 (  1.170605)
13           1.243933   0.000000   1.243933 (  1.243940)
14           1.197929   0.000000   1.197929 (  1.197955)
15           1.257225   0.000000   1.257225 (  1.257232)
16           1.203359   0.000000   1.203359 (  1.203365)

master:

lourens@CarbonX1:~/src/ruby/trunk$ ./miniruby -Ilib $HOME/src/theap_array.rb
"ruby 2.7.0dev (2019-09-22T07:39:47Z master 2272efa463) [x86_64-linux]"
                 user     system      total        real
0            1.034709   0.000000   1.034709 (  1.035330)
1            1.073345   0.000000   1.073345 (  1.073350)
2            1.046693   0.000000   1.046693 (  1.046704)
3            1.046481   0.000000   1.046481 (  1.046487)
4            1.135405   0.000000   1.135405 (  1.135410)
5            1.152307   0.000000   1.152307 (  1.152308)
6            1.163179   0.000000   1.163179 (  1.163184)
7            1.229176   0.000000   1.229176 (  1.229193)
8            1.171530   0.000000   1.171530 (  1.171541)
9            1.229018   0.000000   1.229018 (  1.229023)
10           1.218360   0.000000   1.218360 (  1.218369)
11           1.258088   0.000000   1.258088 (  1.258093)
12           1.214547   0.000000   1.214547 (  1.214557)
13           1.246675   0.000000   1.246675 (  1.246693)
14           1.217621   0.000000   1.217621 (  1.217620)
15           1.240967   0.000000   1.240967 (  1.240972)
16           1.246610   0.000000   1.246610 (  1.246620)

Optcarrot (noisy too):

lourens@CarbonX1:~/src/optcarrot$ benchmark-driver -e "objspace-theap::~/src/ruby/ruby/ruby -I~/src/ruby/ruby/lib -I~/src/ruby/ruby/. -I~/src/ruby/ruby/.ext/x86_64-linux" -e "trunk::~/src/ruby/trunk/ruby -I~/src/ruby/trunk/lib -I~/src/ruby/trunk/. -I~/src/ruby/trunk/.ext/x86_64-linux" --repeat-count 24 --output=all -v benchmark.yml
objspace-theap: ruby 2.7.0dev (2019-09-22T11:43:20Z objspace-theap 11b7839f09) [x86_64-linux]
trunk: ruby 2.7.0dev (2019-09-22T07:39:47Z master 2272efa463) [x86_64-linux]
Calculating -------------------------------------
                           objspace-theap                 trunk 
           optcarrot    42.40538956057937     42.50095691198821 fps
                        42.98025714388297     43.19539965591333 
                        43.17850049383824     43.69380960879121 
                        44.34221997472645     43.75925724088885 
                        45.23015773087887     43.95609333352798 
                        45.60259428038163     44.30873259117270 
                        45.62534786154934     44.50561054139629 
                        45.69848233271295     44.74074528123102 
                        45.72577876475985     44.75584411276473 
                        45.82588019886050     44.90017657928921 
                        45.84436354482752     44.93827167130445 
                        46.72210774150135     45.32808901780013 
                        46.78934236282241     45.40725425997227 
                        46.83007726756269     45.50752517888226 
                        46.84959507374096     45.51210655013940 
                        46.93537135184541     45.51427328345052 
                        47.20234803912213     45.61616028100521 
                        47.36550159135397     45.90162191663695 
                        47.95694822288893     46.18908487592959 
                        48.00296030568151     46.19919623309980 
                        49.21328383054638     46.47376631857036 
                        49.23558095502081     46.85201420357048 
                        49.30196173221466     47.39761548726396 
                        50.07004688586536     47.70501205501753

Updated by ko1 (Koichi Sasada) about 5 years ago

Some internal transient heap structs moved to the header file now leaks into all other reference sites where this source file (transient_heap.c) as previously just used for API

not a big issue, but I don't want to expose them...

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0