Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/actionpack/lib/action_controller/benchmarking.rb

Revision 8958, 3.7 kB (checked in by nzkoz, 4 months ago)

Use realtime to reduce garbage. [adymo]

Line 
1 require 'benchmark'
2
3 module ActionController #:nodoc:
4   # The benchmarking module times the performance of actions and reports to the logger. If the Active Record
5   # package has been included, a separate timing section for database calls will be added as well.
6   module Benchmarking #:nodoc:
7     def self.included(base)
8       base.extend(ClassMethods)
9
10       base.class_eval do
11         alias_method_chain :perform_action, :benchmark
12         alias_method_chain :render, :benchmark
13       end
14     end
15
16     module ClassMethods
17       # Log and benchmark the workings of a single block and silence whatever logging that may have happened inside it
18       # (unless <tt>use_silence</tt> is set to false).
19       #
20       # The benchmark is only recorded if the current level of the logger matches the <tt>log_level</tt>, which makes it
21       # easy to include benchmarking statements in production software that will remain inexpensive because the benchmark
22       # will only be conducted if the log level is low enough.
23       def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
24         if logger && logger.level == log_level
25           result = nil
26           seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
27           logger.add(log_level, "#{title} (#{'%.5f' % seconds})")
28           result
29         else
30           yield
31         end
32       end
33
34       # Silences the logger for the duration of the block.
35       def silence
36         old_logger_level, logger.level = logger.level, Logger::ERROR if logger
37         yield
38       ensure
39         logger.level = old_logger_level if logger
40       end
41     end
42
43     protected
44       def render_with_benchmark(options = nil, extra_options = {}, &block)
45         unless logger
46           render_without_benchmark(options, extra_options, &block)
47         else
48           db_runtime = ActiveRecord::Base.connection.reset_runtime if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
49
50           render_output = nil
51           @rendering_runtime = Benchmark::realtime{ render_output = render_without_benchmark(options, extra_options, &block) }
52
53           if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
54             @db_rt_before_render = db_runtime
55             @db_rt_after_render = ActiveRecord::Base.connection.reset_runtime
56             @rendering_runtime -= @db_rt_after_render
57           end
58
59           render_output
60         end
61       end   
62
63     private
64       def perform_action_with_benchmark
65         unless logger
66           perform_action_without_benchmark
67         else
68           runtime = [ Benchmark::measure{ perform_action_without_benchmark }.real, 0.0001 ].max
69
70           log_message  = "Completed in #{sprintf("%.5f", runtime)} (#{(1 / runtime).floor} reqs/sec)"
71           log_message << rendering_runtime(runtime) if defined?(@rendering_runtime)
72           log_message << active_record_runtime(runtime) if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
73           log_message << " | #{headers["Status"]}"
74           log_message << " [#{complete_request_uri rescue "unknown"}]"
75
76           logger.info(log_message)
77           response.headers["X-Runtime"] = sprintf("%.5f", runtime)
78         end
79       end
80
81       def rendering_runtime(runtime)
82         percentage = @rendering_runtime * 100 / runtime
83         " | Rendering: %.5f (%d%%)" % [@rendering_runtime, percentage.to_i]
84       end
85
86       def active_record_runtime(runtime)
87         db_runtime    = ActiveRecord::Base.connection.reset_runtime
88         db_runtime    += @db_rt_before_render if @db_rt_before_render
89         db_runtime    += @db_rt_after_render if @db_rt_after_render
90         db_percentage = db_runtime * 100 / runtime
91         " | DB: %.5f (%d%%)" % [db_runtime, db_percentage.to_i]
92       end
93   end
94 end
Note: See TracBrowser for help on using the browser.