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
-
.logger ⇒ Object
:nodoc:.
-
.measure(name, &block) ⇒ Object
Used by watch to record the time of a method call without losing the method’s return value.
-
.report(request) ⇒ Object
Prints the benchmarks for the request into the log, with some basic ASCII formatting (yay).
-
.results ⇒ Object
:nodoc:.
- .rewatch! ⇒ Object
- .rewatchable(*args) ⇒ Object
-
.watch(name, obj, method, instance = true) ⇒ Object
Starts benchmarking for some method.
Class Method Details
.logger ⇒ Object
: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 |
.results ⇒ Object
: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 |