Module: BenchmarkForRails

Defined in:
lib/benchmark_for_rails.rb,
lib/reporting.rb,
lib/benchmark_for_rails/log_parser.rb,
lib/benchmark_for_rails/rewatching.rb,
lib/benchmark_for_rails/resource_path.rb

Overview

BenchmarkForRails addresses a few issues with ActionController’s benchmarking:

  • hidden query costs (ActiveRecord’s cost of building a query)

  • no visibility on the cost of before/after filters

  • no visibility on cost of session management

Other strengths:

  • very easy to benchmark new things without implementing your own alias_method_chain (use BenchmarkForRails.watch)

  • automatically handles methods called multiple times (e.g. ActiveRecord::Base#find)

Defined Under Namespace

Classes: LogParser, Report, ResourcePath

Class Method Summary collapse

Class Method Details

.loggerObject

:nodoc:



58
59
60
# File 'lib/benchmark_for_rails.rb', line 58

def logger #:nodoc:
  Rails.logger
end

.measure(name, &block) ⇒ Object

Used by watch to record the time of a method call without losing the method’s return value



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/benchmark_for_rails.rb', line 41

def measure(name, &block)
  if self.running? name
    yield
  else
    result = nil
    self.running << name
    begin
      self.results[name] += Benchmark.ms{result = yield} / 1000
    rescue
      raise
    ensure
      self.running.delete(name)
    end
    result
  end
end

.report(request) ⇒ Object

Prints the benchmarks for the request into the log, with some basic ASCII formatting (yay). Uses a multi-line format for development mode, and a one-line format for production mode.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/reporting.rb', line 6

def report(request)
  request_action = "#{request.method.to_s.upcase} #{request.path.chomp('/')}"
  request_time   = results.delete(:request) || 0.0

  if RAILS_ENV.to_sym == :production
    # in production mode, we want to use a one-line format that makes it easy to
    # parse logs generated by multiple processes.
    benchmarks = ["request: #{'%.4f' % request_time}"]
    benchmarks += results.to_a.collect{|(name, seconds)| "#{name}: #{'%.4f' % seconds}"}

    logger.info "B4R: [#{request_action}] #{benchmarks.join(' | ')}"
  else
    # in development mode, we want to use a multi-line format that makes it easy
    # for a human to read.
    logger.info "- [#{'%.4f' % request_time}] #{request_action} ".ljust(50, '-')

    results.to_a.sort_by{|(name, seconds)| seconds}.reverse.each do |(name, seconds)|
      logger.info "   #{'%.4f' % seconds} #{name}"
    end

    logger.info " BenchmarkForRails -".rjust(50, '-')
  end

  results.clear
end

.resultsObject

:nodoc:



35
36
37
# File 'lib/benchmark_for_rails.rb', line 35

def results #:nodoc:
  Thread.current[:results] ||= Hash.new(0)
end

.rewatch!Object



3
4
5
6
7
# File 'lib/benchmark_for_rails/rewatching.rb', line 3

def rewatch!
  rewatchables.each do |(name, object_name, method, instance)|
    watch(name, object_name.constantize, method, instance)
  end
end

.rewatchable(*args) ⇒ Object



9
10
11
# File 'lib/benchmark_for_rails/rewatching.rb', line 9

def rewatchable(*args)
  rewatchables << args unless rewatchables.include? args
end

.watch(name, obj, method, instance = true) ⇒ Object

Starts benchmarking for some method. Results will be automatically logged after the request finishes processing.

Arguments:

  • name: how to refer to this benchmark in the logs

  • obj: the object that defines the method

  • method: the name of the method to be benchmarked

  • instance: whether the method is an instance method or not



21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/benchmark_for_rails.rb', line 21

def watch(name, obj, method, instance = true)
  rewatchable(name, obj.to_s, method, instance) if ActiveSupport::Dependencies.will_unload?(obj)

  obj.class_eval <<-EOL, __FILE__, __LINE__
    #{"class << self" unless instance}
    def #{method}_with_benchmark_for_rails(*args, &block)
      BenchmarkForRails.measure(#{name.inspect}) {#{method}_without_benchmark_for_rails(*args, &block)}
    end

    alias_method_chain :#{method}, :benchmark_for_rails
    #{"end" unless instance}
  EOL
end