@@ -36,6 +36,8 @@ def run_benchmark(_num_itrs_hint, **, &block)
3636 marking_times = [ ]
3737 sweeping_times = [ ]
3838 gc_counts = [ ]
39+ major_counts = [ ]
40+ minor_counts = [ ]
3941 gc_heap_deltas = [ ]
4042 total_time = 0
4143 num_itrs = 0
@@ -47,6 +49,9 @@ def run_benchmark(_num_itrs_hint, **, &block)
4749 header << " marking" if has_marking
4850 header << " sweeping" if has_sweeping
4951 header << " gc_count"
52+ header << " major"
53+ header << " minor"
54+ header << " maj/min"
5055 puts header
5156
5257 begin
@@ -63,17 +68,25 @@ def run_benchmark(_num_itrs_hint, **, &block)
6368 mark_delta = has_marking ? gc_after [ :marking_time ] - gc_before [ :marking_time ] : 0
6469 sweep_delta = has_sweeping ? gc_after [ :sweeping_time ] - gc_before [ :sweeping_time ] : 0
6570 count_delta = gc_after [ :count ] - gc_before [ :count ]
71+ major_delta = gc_after [ :major_gc_count ] - gc_before [ :major_gc_count ]
72+ minor_delta = gc_after [ :minor_gc_count ] - gc_before [ :minor_gc_count ]
73+ ratio_str = minor_delta > 0 ? "%.2f" % ( major_delta . to_f / minor_delta ) : "-"
6674
6775 itr_str = "%4s %6s" % [ "##{ num_itrs } :" , "#{ time_ms } ms" ]
6876 itr_str << " %9.1fms" % mark_delta if has_marking
6977 itr_str << " %9.1fms" % sweep_delta if has_sweeping
7078 itr_str << " %9d" % count_delta
79+ itr_str << " %9d" % major_delta
80+ itr_str << " %9d" % minor_delta
81+ itr_str << " %9s" % ratio_str
7182 puts itr_str
7283
7384 times << time
7485 marking_times << mark_delta
7586 sweeping_times << sweep_delta
7687 gc_counts << count_delta
88+ major_counts << major_delta
89+ minor_counts << minor_delta
7790 gc_heap_deltas << gc_stat_heap_delta ( heap_before , heap_after )
7891 total_time += time
7992 end until num_itrs >= WARMUP_ITRS + MIN_BENCH_ITRS and total_time >= MIN_BENCH_TIME
@@ -88,8 +101,19 @@ def run_benchmark(_num_itrs_hint, **, &block)
88101 extra [ "gc_sweeping_time_bench" ] = sweeping_times [ bench_range ]
89102 extra [ "gc_count_warmup" ] = gc_counts [ warmup_range ]
90103 extra [ "gc_count_bench" ] = gc_counts [ bench_range ]
104+ extra [ "gc_major_count_warmup" ] = major_counts [ warmup_range ]
105+ extra [ "gc_major_count_bench" ] = major_counts [ bench_range ]
106+ extra [ "gc_minor_count_warmup" ] = minor_counts [ warmup_range ]
107+ extra [ "gc_minor_count_bench" ] = minor_counts [ bench_range ]
91108 extra [ "gc_stat_heap_deltas" ] = gc_heap_deltas [ bench_range ]
92109
110+ # Snapshot heap utilisation after benchmark
111+ if GC . respond_to? ( :stat_heap )
112+ GC . start ( full_mark : true )
113+ heap_snapshot = GC . stat_heap
114+ extra [ "gc_heap_final" ] = heap_snapshot . transform_values { |v | v . is_a? ( Hash ) ? v . dup : v }
115+ end
116+
93117 return_results ( times [ warmup_range ] , times [ bench_range ] , **extra )
94118
95119 non_warmups = times [ bench_range ]
@@ -109,4 +133,27 @@ def run_benchmark(_num_itrs_hint, **, &block)
109133 puts "Average sweeping time: %.1fms" % avg_sweep
110134 end
111135 end
136+
137+ # Print heap utilisation table
138+ if heap_snapshot
139+ page_size = defined? ( GC ::INTERNAL_CONSTANTS ) ? GC ::INTERNAL_CONSTANTS [ :HEAP_PAGE_SIZE ] : nil
140+
141+ puts "\n Heap utilisation (after full GC):"
142+ header = "heap slot_size eden_slots live_slots free_slots eden_pages live_pct mem_KiB"
143+ puts header
144+
145+ heap_snapshot . each do |idx , stats |
146+ slot_size = stats [ :slot_size ] || 0
147+ eden_slots = stats [ :heap_eden_slots ] || 0
148+ live_slots = stats [ :heap_live_slots ] || 0
149+ free_slots = stats [ :heap_free_slots ] || 0
150+ eden_pages = stats [ :heap_eden_pages ] || 0
151+ live_pct = eden_slots > 0 ? ( live_slots * 100.0 / eden_slots ) : 0.0
152+ mem_kib = page_size ? ( eden_pages * page_size / 1024.0 ) : 0.0
153+
154+ puts "%4d %9d %10d %10d %10d %11d %7.1f%% %7.1f" % [
155+ idx , slot_size , eden_slots , live_slots , free_slots , eden_pages , live_pct , mem_kib
156+ ]
157+ end
158+ end
112159end
0 commit comments