README.md in benchmark-inputs-1.0.1 vs README.md in benchmark-inputs-1.1.0

- old
+ new

@@ -1,63 +1,67 @@ # benchmark-inputs -Input-focused benchmarking for Ruby. Given one or more blocks and a -list of inputs to yield to them, benchmark-inputs will measure the speed -(in invocations per second) of each block. Blocks which execute very -quickly, as in microbenchmarks, are automatically invoked repeatedly to -provide accurate measurements. +Input-focused benchmarking for Ruby. Given one or more blocks and an +array of inputs to yield to each of them, benchmark-inputs will measure +the speed (in invocations per second) of each block. Blocks which +execute very quickly, as in microbenchmarks, are automatically invoked +repeatedly to provide accurate measurements. ## Motivation I <3 [Fast Ruby][fast-ruby]. By extension, I <3 [benchmark-ips]. But, -for certain usages, benchmark-ips doesn't let me write benchmarks the -way I'd like. Consider the following example, *using benchmark-ips*: +for some use cases, benchmark-ips doesn't let me write benchmarks the +way I'd like. Consider the following example, *using benchmark-ips*: ```ruby -require 'benchmark/ips' ### USING benchmark-ips (NOT benchmark-inputs) +require "benchmark/ips" ### USING benchmark-ips (NOT benchmark-inputs) -STRINGS = ['abc', 'aaa', 'xyz', ''] +STRINGS = ["abc", "aaa", "xyz", ""] Benchmark.ips do |job| - job.report('String#tr'){ STRINGS.each{|s| s.tr('a', 'A') } } - job.report('String#gsub'){ STRINGS.each{|s| s.gsub(/a/, 'A') } } + job.report("String#tr"){ STRINGS.each{|s| s.tr("a", "A") } } + job.report("String#gsub"){ STRINGS.each{|s| s.gsub(/a/, "A") } } job.compare! end ``` -The calls to `STRINGS.each` introduce performance overhead which skews +The calls to `STRINGS.each` introduce performance overhead that skews the time measurements. The less time the target function takes, the -more relative overhead, and thus the more skew. For a microbenchmark -this can be a problem. A possible workaround is to invoke the function -on each value individually, but that is more verbose and error-prone: +more relative overhead, and thus more skew. For a microbenchmark this +can be a problem. A possible workaround is to invoke the function on +each value individually, but that is more verbose and more error-prone: ```ruby -require 'benchmark/ips' ### USING benchmark-ips (NOT benchmark-inputs) +require "benchmark/ips" ### USING benchmark-ips (NOT benchmark-inputs) -s1 = 'abc'; s2 = 'aaa'; s3 = 'xyz'; s4 = '' +s1, s2, s3, s4 = ["abc", "aaa", "xyz", ""] Benchmark.ips do |job| - job.report('String#tr') do - s1.tr('a', 'A'); s2.tr('a', 'A') - s3.tr('a', 'A'); s4.tr('a', 'A') + job.report("String#tr") do + s1.tr("a", "A") + s2.tr("a", "A") + s3.tr("a", "A") + s4.tr("a", "A") end - job.report('String#gsub') do - s1.gsub(/a/, 'A'); s2.gsub(/a/, 'A') - s3.gsub(/a/, 'A'); s4.gsub(/a/, 'A') + job.report("String#gsub") do + s1.gsub(/a/, "A") + s2.gsub(/a/, "A") + s3.gsub(/a/, "A") + s4.gsub(/a/, "A") end job.compare! end ``` *Enter benchmark-inputs*. Here is how the same benchmark looks using this gem: <a name="example1"></a> ```ruby -require 'benchmark/inputs' ### USING benchmark-inputs +require "benchmark/inputs" ### USING benchmark-inputs -Benchmark.inputs(['abc', 'aaa', 'xyz', '']) do |job| - job.report('String#tr'){|s| s.tr('a', 'A') } - job.report('String#gsub'){|s| s.gsub(/a/, 'A') } +Benchmark.inputs(["abc", "aaa", "xyz", ""]) do |job| + job.report("String#tr"){|s| s.tr("a", "A") } + job.report("String#gsub"){|s| s.gsub(/a/, "A") } job.compare! end ``` Which prints something like the following to `$stdout`: @@ -78,22 +82,21 @@ Destructive operations also pose a challenge for microbenchmarks. Each invocation needs to operate on the same data, but `dup`ing the data introduces too much overhead and skew. -benchmark-inputs' solution is to estimate the overhead incurred by -`dup`, and exclude that from time measurements. Because the benchmark -job already controls the input data, all of this can be handled with a -single configuration line: +benchmark-inputs' solution is to estimate the overhead incurred by each +`dup`, and exclude that from the time measurements. Because the +benchmark job already controls the input data, everything can be handled +behind the scenes. To enable this, use the `dup_inputs` option: ```ruby -require 'benchmark/inputs' +require "benchmark/inputs" -Benchmark.inputs(['abc', 'aaa', 'xyz', '']) do |job| - job.dup_inputs = true # <--- single configuration line - job.report('String#tr!'){|s| s.tr!('a', 'A') } - job.report('String#gsub!'){|s| s.gsub!(/a/, 'A') } +Benchmark.inputs(["abc", "aaa", "xyz", ""], dup_inputs: true) do |job| + job.report("String#tr!"){|s| s.tr!("a", "A") } + job.report("String#gsub!"){|s| s.gsub!(/a/, "A") } job.compare! end ``` Which prints out something like: @@ -109,11 +112,11 @@ String#gsub!: 281588.6 i/s - 6.37x slower ``` That shows a slightly larger performance gap than the previous benchmark. This makes sense because the overhead of allocating new -strings--previously via a non-bang method, but now via `dup`--is now +strings -- previously via a non-bang method, but now via `dup` -- is now excluded from the timings. Thus, the speed of `tr!` relative to `gsub!` is further emphasized. ## Limitations @@ -127,23 +130,25 @@ problem. ## Installation - $ gem install benchmark-inputs +```bash +$ gem install benchmark-inputs +``` ## Usage -See the [example above](#example1), or check the -[documentation](http://www.rubydoc.info/gems/benchmark-inputs). +See the [example above](#example1), or check out the +[API documentation](http://www.rubydoc.info/gems/benchmark-inputs). ## License [MIT License](http://opensource.org/licenses/MIT) [fast-ruby]: https://github.com/JuanitoFatas/fast-ruby -[benchmark-ips]: https://github.com/evanphx/benchmark-ips +[benchmark-ips]: https://rubygems.org/gems/benchmark-ips