From c30874c99cd5684d7481adae13ffdac02660a11b Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 8 Aug 2025 13:53:47 +0200 Subject: [PATCH 1/2] WIP --- benchmarks/binarytrees/benchmark.rb | 56 ++++++++++++++++------------- harness/harness.rb | 16 ++++++++- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/benchmarks/binarytrees/benchmark.rb b/benchmarks/binarytrees/benchmark.rb index acecf119..9702fab1 100644 --- a/benchmarks/binarytrees/benchmark.rb +++ b/benchmarks/binarytrees/benchmark.rb @@ -5,39 +5,47 @@ # Modified by Wesley Moxam # *reset* -def item_check(left, right) - return 1 if left.nil? - 1 + item_check(*left) + item_check(*right) -end +module Btree + extend self -def bottom_up_tree(depth) - return [nil, nil] unless depth > 0 - depth -= 1 - [bottom_up_tree(depth), bottom_up_tree(depth)] -end + def item_check(left, right) + return 1 if left.nil? + 1 + item_check(*left) + item_check(*right) + end -max_depth = 14 -min_depth = 4 + def bottom_up_tree(depth) + return [nil, nil] unless depth > 0 + depth -= 1 + [bottom_up_tree(depth), bottom_up_tree(depth)] + end -max_depth = min_depth + 2 if min_depth + 2 > max_depth -stretch_depth = max_depth + 1 + def bench + max_depth = 14 + min_depth = 4 -require_relative '../../harness/loader' + max_depth = min_depth + 2 if min_depth + 2 > max_depth + stretch_depth = max_depth + 1 -run_benchmark(60) do - stretch_tree = bottom_up_tree(stretch_depth) - stretch_tree = nil + stretch_tree = bottom_up_tree(stretch_depth) + stretch_tree = nil - long_lived_tree = bottom_up_tree(max_depth) + long_lived_tree = bottom_up_tree(max_depth) - min_depth.step(max_depth, 2) do |depth| - iterations = 2**(max_depth - depth + min_depth) + min_depth.step(max_depth, 2) do |depth| + iterations = 2**(max_depth - depth + min_depth) - check = 0 + check = 0 - for i in 1..iterations - temp_tree = bottom_up_tree(depth) - check += item_check(*temp_tree) + for i in 1..iterations + temp_tree = bottom_up_tree(depth) + check += item_check(*temp_tree) + end end end end + +require_relative '../../harness/loader' + +run_benchmark(60) do + Btree.bench +end diff --git a/harness/harness.rb b/harness/harness.rb index f1dd8405..00dff06a 100644 --- a/harness/harness.rb +++ b/harness/harness.rb @@ -31,6 +31,20 @@ def realtime Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0 end +def run_once(&block) + if parallel = ENV["RACTOR_PARALLEL"] + # block = Ractor.make_shareable(block) + realtime do + ractors = Integer(parallel).times.map do + Ractor.new(&block) + end + ractors.each(&:join) + end + else + realtime(&block) + end +end + # Takes a block as input def run_benchmark(_num_itrs_hint, &block) times = [] @@ -50,7 +64,7 @@ def run_benchmark(_num_itrs_hint, &block) begin yjit_stats&.each_key { |key| yjit_stats[key] = RubyVM::YJIT.runtime_stats(key) } - time = realtime(&block) + time = run_once(&block) num_itrs += 1 # NOTE: we may want to avoid this as it could trigger GC? From c3dda0297dabbe6efc3da92022f3c3e0482614e2 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 8 Aug 2025 14:16:52 +0200 Subject: [PATCH 2/2] Better Ractor benching --- benchmarks/binarytrees/benchmark.rb | 4 +- harness/harness.rb | 71 +++++++++++++++++------------ 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/benchmarks/binarytrees/benchmark.rb b/benchmarks/binarytrees/benchmark.rb index 9702fab1..cfcad98f 100644 --- a/benchmarks/binarytrees/benchmark.rb +++ b/benchmarks/binarytrees/benchmark.rb @@ -46,6 +46,4 @@ def bench require_relative '../../harness/loader' -run_benchmark(60) do - Btree.bench -end +run_benchmark(60, Btree) diff --git a/harness/harness.rb b/harness/harness.rb index 00dff06a..2eb851c8 100644 --- a/harness/harness.rb +++ b/harness/harness.rb @@ -31,40 +31,20 @@ def realtime Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0 end -def run_once(&block) - if parallel = ENV["RACTOR_PARALLEL"] - # block = Ractor.make_shareable(block) - realtime do - ractors = Integer(parallel).times.map do - Ractor.new(&block) - end - ractors.each(&:join) - end - else - realtime(&block) - end -end - -# Takes a block as input -def run_benchmark(_num_itrs_hint, &block) +def run_benchmark_loop(runner, block, yjit_stats) times = [] total_time = 0 num_itrs = 0 - header = "itr: time" - - RubyVM::YJIT.reset_stats! if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? - - # If $YJIT_BENCH_STATS is given, print the diff of these stats at each iteration. - if ENV["YJIT_BENCH_STATS"] - yjit_stats = ENV["YJIT_BENCH_STATS"].split(",").map { |key| [key.to_sym, nil] }.to_h - yjit_stats.each_key { |key| header << " #{key}" } - end - - puts header begin yjit_stats&.each_key { |key| yjit_stats[key] = RubyVM::YJIT.runtime_stats(key) } - time = run_once(&block) + time = realtime do + if runner + runner.bench + else + block.call + end + end num_itrs += 1 # NOTE: we may want to avoid this as it could trigger GC? @@ -84,6 +64,41 @@ def run_benchmark(_num_itrs_hint, &block) times << time total_time += time end until num_itrs >= WARMUP_ITRS + MIN_BENCH_ITRS and total_time >= MIN_BENCH_TIME + [num_itrs, total_time, times.freeze].freeze +end + +# Takes a block as input +def run_benchmark(_num_itrs_hint, runner = nil, &block) + times = [] + total_time = 0 + num_itrs = 0 + header = "itr: time" + + RubyVM::YJIT.reset_stats! if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? + + # If $YJIT_BENCH_STATS is given, print the diff of these stats at each iteration. + if ENV["YJIT_BENCH_STATS"] + yjit_stats = ENV["YJIT_BENCH_STATS"].split(",").map { |key| [key.to_sym, nil] }.to_h.freeze + yjit_stats.each_key { |key| header << " #{key}" } + end + + puts header + if parallel = ENV["RACTOR_PARALLEL"] + Warning[:experimental] = false + ractors = Integer(parallel).times.map do + Ractor.new(runner, block) do |runner, block| + run_benchmark_loop(runner, block, nil) + end + end + ractors.each do |ractor| + r_num_itrs, r_total_time, r_times = Ractor.method_defined?(:value) ? ractor.value : ractor.take + num_itrs += r_num_itrs + total_time += r_total_time + times += r_times + end + else + num_itrs, total_time, times = run_benchmark_loop(runner, block, yjit_stats) + end warmup, bench = times[0...WARMUP_ITRS], times[WARMUP_ITRS..-1] return_results(warmup, bench)