@@ -24,97 +24,93 @@ jobs:
2424
2525 - name : Run benchmarks with YJIT
2626 run : |
27- bundle exec ruby --yjit bin/benchmark | tee benchmark_output.txt
27+ bundle exec ruby --yjit bin/benchmark --json > benchmark_results.json
2828
29- - name : Parse and format results
29+ - name : Format results as markdown
3030 run : |
31- cat > parse_benchmark .rb << 'EOF'
31+ cat > format_results .rb << 'EOF'
3232 #!/usr/bin/env ruby
33+ require 'json'
3334
34- input = File.read('benchmark_output.txt' )
35+ data = JSON.parse( File.read('benchmark_results.json') )
3536
36- def parse_section(text, title)
37- lines = text.lines.map(&:chomp)
38- results = []
39- comparisons = []
40- in_comparison = false
41- in_calculating = false
42-
43- lines.each do |line|
44- # Start of calculation section
45- if line =~ /^Calculating/
46- in_calculating = true
47- next
48- end
49-
50- # Match result lines after "Calculating" section
51- # Format: " Ruby CSV 463.779 (± 2.4%) i/s (2.16 ms/i) - ..."
52- if in_calculating && line =~ /^\s*(.+?)\s\s+(\d+\.?\d*)\s+\(.+?\)\s+i\/s/
53- name = $1.strip
54- ips = $2
55- results << { name: name, ips: ips }
56- elsif line =~ /^Comparison:/
57- in_comparison = true
58- in_calculating = false
59- elsif in_comparison && line.strip =~ /^(.+?):\s+(.+)/
60- comparisons << "- **#{$1.strip}**: #{$2.strip}"
61- end
62- end
63-
64- return nil if results.empty?
37+ output = "## 🚀 Benchmark Results\n\n"
38+ output += "_Benchmarks run with YJIT enabled on Ruby #{data['ruby_version']}_\n\n"
39+
40+ # Writing benchmark
41+ if data['benchmarks']['writing']
42+ output += "### 📝 CSV Writing Performance\n\n"
43+ output += "| Library | Iterations/sec | Std Dev |\n"
44+ output += "|---------|----------------|----------|\n"
6545
66- # Build markdown table
67- table = "### #{title}\n\n"
68- table += "| Library | Iterations/sec |\n"
69- table += "|---------|---------------|\n"
46+ writing = data['benchmarks']['writing']
47+ sorted_writing = writing.sort_by { |_, v| -v['ips'] }
7048
71- results .each do |result |
72- table += "| #{result[: name] } | #{result[: ips]} |\n"
49+ sorted_writing .each do |name, stats |
50+ output += "| #{name} | #{stats[' ips'].round(1)} | ±#{stats['stddev_percentage'].round(1)}% |\n"
7351 end
7452
75- # Add comparison info
76- if !comparisons.empty?
77- table += "\n**Comparison:**\n\n"
78- table += comparisons.join("\n") + "\n"
53+ # Add comparison
54+ if sorted_writing.length > 1
55+ fastest = sorted_writing.first
56+ output += "\n**Comparison:**\n\n"
57+ sorted_writing.each do |name, stats|
58+ if name == fastest[0]
59+ output += "- **#{name}**: #{stats['ips'].round(1)} i/s (fastest)\n"
60+ else
61+ slowdown = fastest[1]['ips'] / stats['ips']
62+ output += "- **#{name}**: #{stats['ips'].round(1)} i/s - #{slowdown.round(2)}x slower\n"
63+ end
64+ end
7965 end
80-
81- table
66+ output += "\n"
8267 end
8368
84- output = "## 🚀 Benchmark Results\n\n"
85- output += "_Benchmarks run with YJIT enabled on Ruby #{RUBY_VERSION}_\n\n"
86-
87- # Split by === markers to get sections
88- sections = input.split(/^=== /)
89-
90- sections.each do |section|
91- if section.include?("CSV Writing Benchmark")
92- result = parse_section(section, "📝 CSV Writing Performance")
93- output += result + "\n" if result
94- elsif section.include?("CSV Reading Benchmark")
95- result = parse_section(section, "📖 CSV Reading Performance")
96- output += result + "\n" if result
69+ # Reading benchmark
70+ if data['benchmarks']['reading']
71+ output += "### 📖 CSV Reading Performance\n\n"
72+ output += "| Library | Iterations/sec | Std Dev |\n"
73+ output += "|---------|----------------|----------|\n"
74+
75+ reading = data['benchmarks']['reading']
76+ sorted_reading = reading.sort_by { |_, v| -v['ips'] }
77+
78+ sorted_reading.each do |name, stats|
79+ output += "| #{name} | #{stats['ips'].round(1)} | ±#{stats['stddev_percentage'].round(1)}% |\n"
80+ end
81+
82+ # Add comparison
83+ if sorted_reading.length > 1
84+ fastest = sorted_reading.first
85+ output += "\n**Comparison:**\n\n"
86+ sorted_reading.each do |name, stats|
87+ if name == fastest[0]
88+ output += "- **#{name}**: #{stats['ips'].round(1)} i/s (fastest)\n"
89+ else
90+ slowdown = fastest[1]['ips'] / stats['ips']
91+ output += "- **#{name}**: #{stats['ips'].round(1)} i/s - #{slowdown.round(2)}x slower\n"
92+ end
93+ end
9794 end
95+ output += "\n"
9896 end
9997
10098 # Write to GitHub Step Summary
10199 if ENV['GITHUB_STEP_SUMMARY']
102100 File.write(ENV['GITHUB_STEP_SUMMARY'], output)
103101 puts "✅ Results written to GitHub Actions summary"
104- else
105- puts "⚠️ GITHUB_STEP_SUMMARY not available, printing to stdout:"
106102 end
107103
108104 # Also print to stdout
109- puts "\n" + output
105+ puts output
110106 EOF
111107
112- ruby parse_benchmark .rb
108+ ruby format_results .rb
113109
114- - name : Upload benchmark output
110+ - name : Upload benchmark results
115111 uses : actions/upload-artifact@v4
116112 if : always()
117113 with :
118114 name : benchmark-results
119- path : benchmark_output.txt
115+ path : benchmark_results.json
120116 retention-days : 30
0 commit comments