Skip to content

Commit 5aeda13

Browse files
committed
Extract build_output_text method to BenchmarkRunner module
1 parent c2c214f commit 5aeda13

File tree

3 files changed

+168
-14
lines changed

3 files changed

+168
-14
lines changed

lib/benchmark_runner.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'csv'
44
require 'json'
55
require 'rbconfig'
6+
require_relative 'table_formatter'
67

78
# Extracted helper methods from run_benchmarks.rb for testing
89
module BenchmarkRunner
@@ -46,6 +47,28 @@ def write_csv(output_path, ruby_descriptions, table)
4647
out_csv_path
4748
end
4849

50+
# Build output text string with metadata, table, and legend
51+
def build_output_text(ruby_descriptions, table, format, bench_failures, base_name, other_names)
52+
output_str = +""
53+
54+
ruby_descriptions.each do |key, value|
55+
output_str << "#{key}: #{value}\n"
56+
end
57+
58+
output_str << "\n"
59+
output_str << TableFormatter.new(table, format, bench_failures).to_s + "\n"
60+
61+
unless other_names.empty?
62+
output_str << "Legend:\n"
63+
other_names.each do |name|
64+
output_str << "- #{name} 1st itr: ratio of #{base_name}/#{name} time for the first benchmarking iteration.\n"
65+
output_str << "- #{base_name}/#{name}: ratio of #{base_name}/#{name} time. Higher is better for #{name}. Above 1 represents a speedup.\n"
66+
end
67+
end
68+
69+
output_str
70+
end
71+
4972
# Render a graph from JSON benchmark data
5073
def render_graph(json_path)
5174
png_path = json_path.sub(/\.json$/, '.png')

run_benchmarks.rb

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
require_relative 'lib/cpu_config'
1212
require_relative 'lib/benchmark_runner'
1313
require_relative 'lib/benchmark_suite'
14-
require_relative 'lib/table_formatter'
1514
require_relative 'lib/argument_parser'
1615
require_relative 'lib/results_table_builder'
1716

@@ -77,19 +76,7 @@
7776
BenchmarkRunner.write_csv(output_path, ruby_descriptions, table)
7877

7978
# Save the output in a text file that we can easily refer to
80-
output_str = ""
81-
ruby_descriptions.each do |key, value|
82-
output_str << "#{key}: #{value}\n"
83-
end
84-
output_str += "\n"
85-
output_str += TableFormatter.new(table, format, bench_failures).to_s + "\n"
86-
unless other_names.empty?
87-
output_str << "Legend:\n"
88-
other_names.each do |name|
89-
output_str << "- #{name} 1st itr: ratio of #{base_name}/#{name} time for the first benchmarking iteration.\n"
90-
output_str << "- #{base_name}/#{name}: ratio of #{base_name}/#{name} time. Higher is better for #{name}. Above 1 represents a speedup.\n"
91-
end
92-
end
79+
output_str = BenchmarkRunner.build_output_text(ruby_descriptions, table, format, bench_failures, base_name, other_names)
9380
out_txt_path = output_path + ".txt"
9481
File.open(out_txt_path, "w") { |f| f.write output_str }
9582

test/benchmark_runner_test.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,150 @@
365365
end
366366
end
367367

368+
describe '.build_output_text' do
369+
it 'builds output text with metadata, table, and legend' do
370+
ruby_descriptions = {
371+
'ruby-base' => 'ruby 3.3.0',
372+
'ruby-yjit' => 'ruby 3.3.0 +YJIT'
373+
}
374+
table = [
375+
['bench', 'ruby-base (ms)', 'stddev (%)', 'ruby-yjit (ms)', 'stddev (%)'],
376+
['fib', '100.0', '5.0', '50.0', '3.0']
377+
]
378+
format = ['%s', '%.1f', '%.1f', '%.1f', '%.1f']
379+
bench_failures = {}
380+
base_name = 'ruby-base'
381+
other_names = ['ruby-yjit']
382+
383+
result = BenchmarkRunner.build_output_text(
384+
ruby_descriptions, table, format, bench_failures, base_name, other_names
385+
)
386+
387+
assert_includes result, 'ruby-base: ruby 3.3.0'
388+
assert_includes result, 'ruby-yjit: ruby 3.3.0 +YJIT'
389+
assert_includes result, 'Legend:'
390+
assert_includes result, '- ruby-yjit 1st itr: ratio of ruby-base/ruby-yjit time for the first benchmarking iteration.'
391+
assert_includes result, '- ruby-base/ruby-yjit: ratio of ruby-base/ruby-yjit time. Higher is better for ruby-yjit. Above 1 represents a speedup.'
392+
end
393+
394+
it 'includes formatted table in output' do
395+
ruby_descriptions = { 'ruby' => 'ruby 3.3.0' }
396+
table = [
397+
['bench', 'ruby (ms)', 'stddev (%)'],
398+
['fib', '100.0', '5.0']
399+
]
400+
format = ['%s', '%.1f', '%.1f']
401+
bench_failures = {}
402+
base_name = 'ruby'
403+
other_names = []
404+
405+
result = BenchmarkRunner.build_output_text(
406+
ruby_descriptions, table, format, bench_failures, base_name, other_names
407+
)
408+
409+
# Should contain table headers
410+
assert_includes result, 'bench'
411+
assert_includes result, 'ruby (ms)'
412+
# Should contain table data
413+
assert_includes result, 'fib'
414+
assert_includes result, '100.0'
415+
end
416+
417+
it 'omits legend when no other executables' do
418+
ruby_descriptions = { 'ruby' => 'ruby 3.3.0' }
419+
table = [['bench', 'ruby (ms)'], ['fib', '100.0']]
420+
format = ['%s', '%.1f']
421+
bench_failures = {}
422+
base_name = 'ruby'
423+
other_names = []
424+
425+
result = BenchmarkRunner.build_output_text(
426+
ruby_descriptions, table, format, bench_failures, base_name, other_names
427+
)
428+
429+
refute_includes result, 'Legend:'
430+
end
431+
432+
it 'handles multiple other executables in legend' do
433+
ruby_descriptions = {
434+
'ruby' => 'ruby 3.3.0',
435+
'ruby-yjit' => 'ruby 3.3.0 +YJIT',
436+
'ruby-rjit' => 'ruby 3.3.0 +RJIT'
437+
}
438+
table = [['bench', 'ruby (ms)', 'ruby-yjit (ms)', 'ruby-rjit (ms)']]
439+
format = ['%s', '%.1f', '%.1f', '%.1f']
440+
bench_failures = {}
441+
base_name = 'ruby'
442+
other_names = ['ruby-yjit', 'ruby-rjit']
443+
444+
result = BenchmarkRunner.build_output_text(
445+
ruby_descriptions, table, format, bench_failures, base_name, other_names
446+
)
447+
448+
assert_includes result, 'ruby-yjit 1st itr'
449+
assert_includes result, 'ruby-rjit 1st itr'
450+
assert_includes result, 'ruby/ruby-yjit'
451+
assert_includes result, 'ruby/ruby-rjit'
452+
end
453+
454+
it 'includes benchmark failures in formatted output' do
455+
ruby_descriptions = { 'ruby' => 'ruby 3.3.0' }
456+
table = [['bench', 'ruby (ms)'], ['fib', '100.0']]
457+
format = ['%s', '%.1f']
458+
bench_failures = {
459+
'ruby' => { 'failed_bench' => 'error message' }
460+
}
461+
base_name = 'ruby'
462+
other_names = []
463+
464+
result = BenchmarkRunner.build_output_text(
465+
ruby_descriptions, table, format, bench_failures, base_name, other_names
466+
)
467+
468+
# TableFormatter handles displaying failures, just verify it's called
469+
assert_kind_of String, result
470+
assert result.length > 0
471+
end
472+
473+
it 'handles empty ruby_descriptions' do
474+
ruby_descriptions = {}
475+
table = [['bench']]
476+
format = ['%s']
477+
bench_failures = {}
478+
base_name = 'ruby'
479+
other_names = []
480+
481+
result = BenchmarkRunner.build_output_text(
482+
ruby_descriptions, table, format, bench_failures, base_name, other_names
483+
)
484+
485+
assert_kind_of String, result
486+
assert result.start_with?("\n") # Should start with newline after empty descriptions
487+
end
488+
489+
it 'preserves order of ruby_descriptions' do
490+
ruby_descriptions = {
491+
'ruby-a' => 'version A',
492+
'ruby-b' => 'version B',
493+
'ruby-c' => 'version C'
494+
}
495+
table = [['bench']]
496+
format = ['%s']
497+
bench_failures = {}
498+
base_name = 'ruby-a'
499+
other_names = []
500+
501+
result = BenchmarkRunner.build_output_text(
502+
ruby_descriptions, table, format, bench_failures, base_name, other_names
503+
)
504+
505+
lines = result.lines
506+
assert_includes lines[0], 'ruby-a: version A'
507+
assert_includes lines[1], 'ruby-b: version B'
508+
assert_includes lines[2], 'ruby-c: version C'
509+
end
510+
end
511+
368512
describe '.render_graph' do
369513
it 'delegates to GraphRenderer and returns calculated png_path' do
370514
Dir.mktmpdir do |dir|

0 commit comments

Comments
 (0)