diff --git a/Gemfile b/Gemfile index c4c9c13..7edc325 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ end group :tools do gem 'rubocop', '~> 0.31' + gem 'faker' gem 'guard' gem 'guard-rspec' gem 'guard-rubocop' diff --git a/README.md b/README.md index 3d2af0b..1a90a6d 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,16 @@ Resources: - [Guides](http://rom-rb.org/guides/basics/mappers/) - [Importing Data with ROM and Transproc](http://solnic.eu/2015/07/15/importing-data-with-rom-and-transproc.html) +Contributing + +[Fork it](https://github.com/rom-rb/rom-mapper/fork) +Create your feature branch (`git checkout -b my-new-feature`) +Run the benchmark suite (`bin/benchmarks`) +Commit your changes (`git commit -am 'Add some feature'`) +Run the benchmark suite again for comparison (`bin/benchmarks`) +Push to the branch (`git push origin my-new-feature`) +Create a new Pull Request + ## License -See `LICENSE` file. +See [LICENSE](blob/master/LICENSE) file. diff --git a/benchmarks/model_instantiation b/benchmarks/model_instantiation new file mode 100755 index 0000000..d4fdeb0 --- /dev/null +++ b/benchmarks/model_instantiation @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +require_relative 'utils/setup.rb' + +user_model = Class.new(OpenStruct) + +mapper = build_mapper do + attribute :name + attribute :email + model user_model +end + +tuples = create_tuple_collection(100) do + { + name: Faker::Name.name, + email: Faker::Internet.email + } +end + +run('model_instantiation') do |x| + x.report { mapper.call(tuples) } +end diff --git a/benchmarks/noop b/benchmarks/noop new file mode 100755 index 0000000..7e28600 --- /dev/null +++ b/benchmarks/noop @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +require_relative 'utils/setup.rb' + +mapper = build_mapper do + attribute :name + attribute :email +end + +tuples = create_tuple_collection(100) do + { + name: Faker::Name.name, + email: Faker::Internet.email + } +end + +run('noop') do |x| + x.report { mapper.call(tuples) } +end diff --git a/benchmarks/reject_keys b/benchmarks/reject_keys new file mode 100755 index 0000000..a1362b5 --- /dev/null +++ b/benchmarks/reject_keys @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +require_relative 'utils/setup.rb' + +mapper = build_mapper do + reject_keys true + attribute :name + attribute :email +end + +tuples = create_tuple_collection(100) do + { + name: Faker::Name.name, + email: Faker::Internet.email, + Faker::Lorem.word => Faker::Lorem.word + } +end + +run('reject_keys') do |x| + x.report { mapper.call(tuples) } +end diff --git a/benchmarks/rename_keys b/benchmarks/rename_keys new file mode 100755 index 0000000..1cc478b --- /dev/null +++ b/benchmarks/rename_keys @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +require_relative 'utils/setup.rb' + +mapper = build_mapper do + attribute :name, from: 'name' + attribute :email, from: 'email' +end + +tuples = create_tuple_collection(100) do + { + 'name' => Faker::Name.name, + 'email' => Faker::Internet.email + } +end + +run('rename_keys') do |x| + x.report { mapper.call(tuples) } +end diff --git a/benchmarks/results/model_instantiation b/benchmarks/results/model_instantiation new file mode 100644 index 0000000..030e415 --- /dev/null +++ b/benchmarks/results/model_instantiation @@ -0,0 +1,10 @@ +=> benchmark: model_instantiation +=> host: andy-HP-ENVY-TS-15-Notebook-PC +=> revision: b7df14f0aacb67d1e006bf1795e0ca45481bc925 +=> repo_state: clean + +Calculating ------------------------------------- + 167.000 i/100ms +------------------------------------------------- + 1.612k (±10.0%) i/s - 8.016k +******************************************************************************** diff --git a/benchmarks/results/noop b/benchmarks/results/noop new file mode 100644 index 0000000..058ff07 --- /dev/null +++ b/benchmarks/results/noop @@ -0,0 +1,10 @@ +=> benchmark: noop +=> host: andy-HP-ENVY-TS-15-Notebook-PC +=> revision: b7df14f0aacb67d1e006bf1795e0ca45481bc925 +=> repo_state: clean + +Calculating ------------------------------------- + 90.342k i/100ms +------------------------------------------------- + 1.497M (± 4.5%) i/s - 7.498M +******************************************************************************** diff --git a/benchmarks/results/reject_keys b/benchmarks/results/reject_keys new file mode 100644 index 0000000..d93113f --- /dev/null +++ b/benchmarks/results/reject_keys @@ -0,0 +1,10 @@ +=> benchmark: reject_keys +=> host: andy-HP-ENVY-TS-15-Notebook-PC +=> revision: b7df14f0aacb67d1e006bf1795e0ca45481bc925 +=> repo_state: clean + +Calculating ------------------------------------- + 492.000 i/100ms +------------------------------------------------- + 4.925k (± 6.8%) i/s - 24.600k +******************************************************************************** diff --git a/benchmarks/results/rename_keys b/benchmarks/results/rename_keys new file mode 100644 index 0000000..bc84ab1 --- /dev/null +++ b/benchmarks/results/rename_keys @@ -0,0 +1,10 @@ +=> benchmark: rename_keys +=> host: andy-HP-ENVY-TS-15-Notebook-PC +=> revision: b7df14f0aacb67d1e006bf1795e0ca45481bc925 +=> repo_state: clean + +Calculating ------------------------------------- + 889.000 i/100ms +------------------------------------------------- + 9.028k (± 3.9%) i/s - 45.339k +******************************************************************************** diff --git a/benchmarks/results/symbolize_keys b/benchmarks/results/symbolize_keys new file mode 100644 index 0000000..218d7b9 --- /dev/null +++ b/benchmarks/results/symbolize_keys @@ -0,0 +1,10 @@ +=> benchmark: symbolize_keys +=> host: andy-HP-ENVY-TS-15-Notebook-PC +=> revision: b7df14f0aacb67d1e006bf1795e0ca45481bc925 +=> repo_state: clean + +Calculating ------------------------------------- + 899.000 i/100ms +------------------------------------------------- + 9.164k (± 3.8%) i/s - 45.849k +******************************************************************************** diff --git a/benchmarks/symbolize_keys b/benchmarks/symbolize_keys new file mode 100755 index 0000000..90e716f --- /dev/null +++ b/benchmarks/symbolize_keys @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +require_relative 'utils/setup.rb' + +mapper = build_mapper do + symbolize_keys true + attribute :name + attribute :email +end + +tuples = create_tuple_collection(100) do + { + 'name' => Faker::Name.name, + 'email' => Faker::Internet.email + } +end + +run('symbolize_keys') do |x| + x.report { mapper.call(tuples) } +end diff --git a/benchmarks/utils/setup.rb b/benchmarks/utils/setup.rb new file mode 100644 index 0000000..d5a88f4 --- /dev/null +++ b/benchmarks/utils/setup.rb @@ -0,0 +1,84 @@ +require 'bundler' +Bundler.require + +require 'socket' +require 'ostruct' +require 'benchmark/ips' +require 'faker' +require 'rom-mapper' + +begin + require 'byebug' +rescue LoadError +end + +# Enable and start GC before each job run. Disable GC afterwards. +# +# Inspired by https://www.omniref.com/ruby/2.2.1/symbols/Benchmark/bm?#annotation=4095926&line=182 +class GCSuite + def warming(*) + run_gc + end + + def running(*) + run_gc + end + + def warmup_stats(*) + end + + def add_report(*) + end + + private + + def run_gc + GC.enable + GC.start + GC.disable + end +end + +def hr + puts "*" * 80 +end + +def run(title, &block) + benchmark(title, &block) +end + +def git_state + state = `git status -uno --porcelain`.split($/).reject do |line| + line.split(' ').last.start_with?('benchmarks/results/') + end + + state.empty? ? 'clean' : "#{$/} => #{state.join("#{$/} => ")}" +end + +def benchmark(title) + puts "=> benchmark: #{title}" + puts "=> host: #{Socket.gethostname}" + puts "=> revision: #{`git rev-parse HEAD`}" + puts "=> repo_state: #{git_state}" + puts $/ + Benchmark.ips do |x| + x.config(suite: GCSuite.new) + yield x + x.compare! + end + hr +end + +def create_mapper(&block) + Class.new(ROM::Mapper).tap do |mapper_klass| + mapper_klass.instance_eval(&block) + end +end + +def build_mapper(&block) + create_mapper(&block).build +end + +def create_tuple_collection(size, &block) + size.times.map { block.call } +end diff --git a/bin/benchmark b/bin/benchmark new file mode 100755 index 0000000..26c7315 --- /dev/null +++ b/bin/benchmark @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby +# encoding: utf-8 + +BENCHMARK_DIR = File.expand_path('../../benchmarks', __FILE__) +RESULTS_DIR = File.expand_path('../../benchmarks/results', __FILE__) +BENCHMARKS = Dir[File.join(BENCHMARK_DIR, '*')].select {|f| File.file?(f) }.sort +RESULTS = BENCHMARKS.map { |bm| File.join(RESULTS_DIR, File.basename(bm)) } + +BENCHMARKS.zip(RESULTS).each do |benchmark, result| + system("#{benchmark} | tee #{result}") +end