Module: Elasticsearch::Extensions::Test::Profiling

Defined in:
lib/elasticsearch/extensions/test/profiling.rb

Overview

Allows to define and execute profiling tests within [Shoulda](github.com/thoughtbot/shoulda) contexts.

Measures operations and reports statistics, including code profile.

Uses the “benchmark” standard library and the “ruby-prof” gem.

File: profiling_test.rb

require 'test/unit'
require 'shoulda/context'
require 'elasticsearch/extensions/test/profiling'

class ProfilingTest < Test::Unit::TestCase
  extend Elasticsearch::Extensions::Test::Profiling

  context "Mathematics" do
    measure "divide numbers", count: 10_000 do
      assert_nothing_raised { 1/2 }
    end
  end

end

$ QUIET=y ruby profiling_test.rb

...
ProfilingTest

-------------------------------------------------------------------------------
Context: Mathematics should divide numbers (10000x)
mean: 0.03ms | avg: 0.03ms | max: 0.14ms
-------------------------------------------------------------------------------
     PASS (0:00:00.490) test: Mathematics should divide numbers (10000x).
...

Instance Method Summary collapse

Instance Method Details

#measure(name, options = {}, &block) ⇒ Object

TODO:

Try to make progress bar not to interfere with tests

Profiles the passed block of code.

measure "divide numbers", count: 10_000 do
 assert_nothing_raised { 1/2 }
end


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/elasticsearch/extensions/test/profiling.rb', line 54

def measure(name, options={}, &block)
  ___          = '-'*ANSI::Terminal.terminal_width
  test_name    = self.name.split('::').last
  context_name = self.context(nil) {}.first.parent.name
  count        = Integer(ENV['COUNT'] || options[:count] || 1_000)
  ticks        = []
  # progress   = ANSI::Progressbar.new("#{name} (#{count}x)", count)

  should "#{name} (#{count}x)" do
    RubyProf.start

    count.times do
      ticks << Benchmark.realtime { self.instance_eval(&block) }
      # RubyProf.pause
      # progress.inc
      # RubyProf.resume
    end

    result = RubyProf.stop
    # progress.finish

    total = result.threads.reduce(0) { |total,info| total += info.total_time; total }
    mean  = (ticks.sort[(ticks.size/2).round-1])*1000
    avg   = (ticks.inject {|sum,el| sum += el; sum}.to_f/ticks.size)*1000
    max   = ticks.max*1000


    result.eliminate_methods!([/Integer#times|Benchmark.realtime|ANSI::Code#.*|ANSI::ProgressBar#.*/])
    printer = RubyProf::FlatPrinter.new(result)
    # printer = RubyProf::GraphPrinter.new(result)

    puts "\n",
         ___,
         'Context: ' + ANSI.bold(context_name) + ' should ' + ANSI.bold(name) + " (#{count}x)",
         "mean: #{sprintf('%.2f', mean)}ms | " +
         "avg: #{sprintf('%.2f',  avg)}ms | " +
         "max: #{sprintf('%.2f',  max)}ms",
         ___
    printer.print(STDOUT, {}) unless ENV['QUIET'] || options[:quiet]
  end
end