|
| 1 | +require_relative "../harness/harness-common" |
| 2 | + |
| 3 | +WARMUP_ITRS = Integer(ENV.fetch('WARMUP_ITRS', 15)) |
| 4 | +MIN_BENCH_ITRS = Integer(ENV.fetch('MIN_BENCH_ITRS', 10)) |
| 5 | +MIN_BENCH_TIME = Integer(ENV.fetch('MIN_BENCH_TIME', 10)) |
| 6 | + |
| 7 | +puts RUBY_DESCRIPTION |
| 8 | + |
| 9 | +def realtime |
| 10 | + r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC) |
| 11 | + yield |
| 12 | + Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0 |
| 13 | +end |
| 14 | + |
| 15 | +def gc_stat_heap_snapshot |
| 16 | + return {} unless GC.respond_to?(:stat_heap) |
| 17 | + GC.stat_heap |
| 18 | +end |
| 19 | + |
| 20 | +def gc_stat_heap_delta(before, after) |
| 21 | + delta = {} |
| 22 | + after.each do |heap_idx, after_stats| |
| 23 | + before_stats = before[heap_idx] || {} |
| 24 | + heap_delta = {} |
| 25 | + after_stats.each do |key, val| |
| 26 | + next unless val.is_a?(Numeric) && before_stats.key?(key) |
| 27 | + heap_delta[key] = val - before_stats[key] |
| 28 | + end |
| 29 | + delta[heap_idx] = heap_delta unless heap_delta.empty? |
| 30 | + end |
| 31 | + delta |
| 32 | +end |
| 33 | + |
| 34 | +def run_benchmark(_num_itrs_hint, **, &block) |
| 35 | + times = [] |
| 36 | + marking_times = [] |
| 37 | + sweeping_times = [] |
| 38 | + gc_counts = [] |
| 39 | + gc_heap_deltas = [] |
| 40 | + total_time = 0 |
| 41 | + num_itrs = 0 |
| 42 | + |
| 43 | + has_marking = GC.stat.key?(:marking_time) |
| 44 | + has_sweeping = GC.stat.key?(:sweeping_time) |
| 45 | + |
| 46 | + header = "itr: time" |
| 47 | + header << " marking" if has_marking |
| 48 | + header << " sweeping" if has_sweeping |
| 49 | + header << " gc_count" |
| 50 | + puts header |
| 51 | + |
| 52 | + begin |
| 53 | + gc_before = GC.stat |
| 54 | + heap_before = gc_stat_heap_snapshot |
| 55 | + |
| 56 | + time = realtime(&block) |
| 57 | + num_itrs += 1 |
| 58 | + |
| 59 | + gc_after = GC.stat |
| 60 | + heap_after = gc_stat_heap_snapshot |
| 61 | + |
| 62 | + time_ms = (1000 * time).to_i |
| 63 | + mark_delta = has_marking ? gc_after[:marking_time] - gc_before[:marking_time] : 0 |
| 64 | + sweep_delta = has_sweeping ? gc_after[:sweeping_time] - gc_before[:sweeping_time] : 0 |
| 65 | + count_delta = gc_after[:count] - gc_before[:count] |
| 66 | + |
| 67 | + itr_str = "%4s %6s" % ["##{num_itrs}:", "#{time_ms}ms"] |
| 68 | + itr_str << " %9.1fms" % mark_delta if has_marking |
| 69 | + itr_str << " %9.1fms" % sweep_delta if has_sweeping |
| 70 | + itr_str << " %9d" % count_delta |
| 71 | + puts itr_str |
| 72 | + |
| 73 | + times << time |
| 74 | + marking_times << mark_delta |
| 75 | + sweeping_times << sweep_delta |
| 76 | + gc_counts << count_delta |
| 77 | + gc_heap_deltas << gc_stat_heap_delta(heap_before, heap_after) |
| 78 | + total_time += time |
| 79 | + end until num_itrs >= WARMUP_ITRS + MIN_BENCH_ITRS and total_time >= MIN_BENCH_TIME |
| 80 | + |
| 81 | + warmup_range = 0...WARMUP_ITRS |
| 82 | + bench_range = WARMUP_ITRS..-1 |
| 83 | + |
| 84 | + extra = {} |
| 85 | + extra["gc_marking_time_warmup"] = marking_times[warmup_range] |
| 86 | + extra["gc_marking_time_bench"] = marking_times[bench_range] |
| 87 | + extra["gc_sweeping_time_warmup"] = sweeping_times[warmup_range] |
| 88 | + extra["gc_sweeping_time_bench"] = sweeping_times[bench_range] |
| 89 | + extra["gc_count_warmup"] = gc_counts[warmup_range] |
| 90 | + extra["gc_count_bench"] = gc_counts[bench_range] |
| 91 | + extra["gc_stat_heap_deltas"] = gc_heap_deltas[bench_range] |
| 92 | + |
| 93 | + return_results(times[warmup_range], times[bench_range], **extra) |
| 94 | + |
| 95 | + non_warmups = times[bench_range] |
| 96 | + if non_warmups.size > 1 |
| 97 | + non_warmups_ms = ((non_warmups.sum / non_warmups.size) * 1000.0).to_i |
| 98 | + puts "Average of last #{non_warmups.size}, non-warmup iters: #{non_warmups_ms}ms" |
| 99 | + |
| 100 | + if has_marking |
| 101 | + mark_bench = marking_times[bench_range] |
| 102 | + avg_mark = mark_bench.sum / mark_bench.size |
| 103 | + puts "Average marking time: %.1fms" % avg_mark |
| 104 | + end |
| 105 | + |
| 106 | + if has_sweeping |
| 107 | + sweep_bench = sweeping_times[bench_range] |
| 108 | + avg_sweep = sweep_bench.sum / sweep_bench.size |
| 109 | + puts "Average sweeping time: %.1fms" % avg_sweep |
| 110 | + end |
| 111 | + end |
| 112 | +end |
0 commit comments