benchmarks/rufus_decision.rb
# frozen_string_literal: true
require 'benchmark/ips'
require 'benchmark/memory'
require 'rufus/decision'
require_relative '../lib/csv_decision'
SPEC_DATA_VALID ||= File.join(CSVDecision.root, 'spec', 'data', 'valid')
CSV_OPTIONS = { regexp_implicit: true }.freeze
RUFUS_OPTIONS = { open_uri: false, ruby_eval: false }.freeze
benchmarks = [
{
name: 'String compares only with index',
data: 'index_example.csv',
input: { 'topic' => 'politics', 'region' => 'Arctic' },
# Expected results for first_match and accumulate
first_match: { 'team_member' => 'Henry' },
accumulate: { 'team_member' => ['Henry', 'Zach'] }
},
{
name: 'String compares only',
data: 'simple_example.csv',
input: { 'topic' => 'culture', 'region' => 'America' },
# Expected results for first_match and accumulate
first_match: { 'team_member' => 'Zach' },
accumulate: { 'team_member' => 'Zach' }
},
{
name: 'Regular expressions',
data: 'benchmark_regexp.csv',
input: { 'age' => '40', 'trait' => 'cheerful' },
# Expected results for first_match and accumulate
first_match: { 'salesperson' => 'Swanson' },
accumulate: { 'salesperson' => %w[Swanson Korolev] }
}
].freeze
tag_width = 70
puts ""
puts "Benchmarking Decisions per Second"
puts '=' * tag_width
puts ""
# First match true and false run options
[true, false].each do |first_match|
puts "Table Decision Option: first_match: #{first_match}"
puts '-' * tag_width
csv_options = CSV_OPTIONS.merge(first_match: first_match)
rufus_options = RUFUS_OPTIONS.merge(first_match: first_match, accumulate: !first_match)
benchmarks.each do |test|
name = test[:name]
data = Pathname(File.join(SPEC_DATA_VALID, test[:data]))
rufus_table = Rufus::Decision::Table.new(data.to_s, rufus_options)
csv_table = CSVDecision.parse(data, csv_options)
# Prepare input hash
input = test[:input].deep_dup
input_symbolized = input.symbolize_keys
# Test expected results
expected = first_match ? test[:first_match] : test[:accumulate]
result = rufus_table.transform(input)
unless result.slice(*expected.keys).eql?(expected)
raise "Rufus expected results check failed for test: #{name}"
end
result = csv_table.decide!(input_symbolized)
unless result.eql?(expected.symbolize_keys)
raise "CSV Decision expected results check failed for test: #{name}"
end
Benchmark.ips do |x|
GC.start
x.report("CSV decision (first_match: #{first_match}) - #{name}: ") do |count|
count.times { csv_table.decide!(input_symbolized) }
end
GC.start
x.report("Rufus decision (first_match: #{first_match}) - #{name}: ") do |count|
count.times { rufus_table.transform!(input) }
end
x.compare!
end
end
end
puts ""
puts "Benchmarking Memory"
puts '=' * tag_width
puts ""
def benchmark_memory(test, quiet: false)
name = test[:name]
data = Pathname(File.join(SPEC_DATA_VALID, test[:data]))
file_name = data.to_s
rufus_tables = {}
csv_tables = {}
key = File.basename(file_name, '.csv').to_sym
Benchmark.memory(quiet: quiet) do |x|
GC.start
x.report("Rufus new table - #{name} ") do
rufus_tables[key] = Rufus::Decision::Table.new(file_name, RUFUS_OPTIONS)
end
GC.start
x.report("CSV Decision new table - #{name} ") do
csv_tables[key] = CSVDecision.parse(data, CSV_OPTIONS)
end
x.compare!
end
end
# Warmup
benchmarks.each { |test| benchmark_memory(test, quiet: true) }
# Run the test
benchmarks.each { |test| benchmark_memory(test, quiet: false) }
puts ""
puts "Benchmarking Table Loads per Second"
puts '=' * tag_width
puts ""
benchmarks.each do |test|
name = test[:name]
data = Pathname(File.join(SPEC_DATA_VALID, test[:data]))
file_name = data.to_s
Benchmark.ips do |x|
GC.start
x.report("CSV new table - #{name}: ") do |count|
count.times { CSVDecision.parse(data) }
end
GC.start
x.report("Rufus new table - #{name}: ") do |count|
count.times { Rufus::Decision::Table.new(file_name, RUFUS_OPTIONS) }
end
x.compare!
end
end