@@ -39,11 +39,13 @@ def run_benchmark(_num_itrs_hint, **, &block)
3939 major_counts = [ ]
4040 minor_counts = [ ]
4141 gc_heap_deltas = [ ]
42+ major_reasons_per_itr = [ ]
4243 total_time = 0
4344 num_itrs = 0
4445
4546 has_marking = GC . stat . key? ( :marking_time )
4647 has_sweeping = GC . stat . key? ( :sweeping_time )
48+ has_major_by = GC . respond_to? ( :latest_gc_info ) && GC . latest_gc_info . key? ( :major_by )
4749
4850 header = "itr: time"
4951 header << " marking" if has_marking
@@ -88,6 +90,15 @@ def run_benchmark(_num_itrs_hint, **, &block)
8890 major_counts << major_delta
8991 minor_counts << minor_delta
9092 gc_heap_deltas << gc_stat_heap_delta ( heap_before , heap_after )
93+ if has_major_by && major_delta > 0
94+ # latest_gc_info only reflects the most recent GC event — if a minor
95+ # GC ran after the last major, the reason is lost (shows :none).
96+ reason = GC . latest_gc_info [ :major_by ]
97+ reason = :unknown if reason . nil? || reason == :none
98+ major_reasons_per_itr << { reason => major_delta }
99+ else
100+ major_reasons_per_itr << { }
101+ end
91102 total_time += time
92103 end until num_itrs >= WARMUP_ITRS + MIN_BENCH_ITRS and total_time >= MIN_BENCH_TIME
93104
@@ -107,6 +118,16 @@ def run_benchmark(_num_itrs_hint, **, &block)
107118 extra [ "gc_minor_count_bench" ] = minor_counts [ bench_range ]
108119 extra [ "gc_stat_heap_deltas" ] = gc_heap_deltas [ bench_range ]
109120
121+ if has_major_by
122+ aggregate_reasons = -> ( range ) {
123+ tally = Hash . new ( 0 )
124+ major_reasons_per_itr [ range ] . each { |h | h . each { |r , c | tally [ r ] += c } }
125+ tally . transform_keys ( &:to_s )
126+ }
127+ extra [ "gc_major_reasons_warmup" ] = aggregate_reasons [ warmup_range ]
128+ extra [ "gc_major_reasons_bench" ] = aggregate_reasons [ bench_range ]
129+ end
130+
110131 return_results ( times [ warmup_range ] , times [ bench_range ] , **extra )
111132
112133 non_warmups = times [ bench_range ]
@@ -125,5 +146,16 @@ def run_benchmark(_num_itrs_hint, **, &block)
125146 avg_sweep = sweep_bench . sum / sweep_bench . size
126147 puts "Average sweeping time: %.1fms" % avg_sweep
127148 end
149+
150+ if has_major_by
151+ bench_reasons = extra [ "gc_major_reasons_bench" ]
152+ if bench_reasons . any?
153+ total = bench_reasons . values . sum
154+ puts "\n Major GC triggers (#{ total } across bench iterations):"
155+ bench_reasons . sort_by { |_ , count | -count } . each do |reason , count |
156+ puts " %-20s %d" % [ reason , count ]
157+ end
158+ end
159+ end
128160 end
129161end
0 commit comments