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

root/tools/conductor/lib/request_profiler.rb

Revision 1113, 3.6 kB (checked in by bitsweat, 4 years ago)

Disable GC during request. Insert results before </html> to appease validating browsers.

Line 
1 module ActionController
2   class Base
3     # Profile each request and append the results to the response body.
4     # Requires the ruby-prof C extension by Shugo Maeda which requires
5     # Ruby 1.8 younger than 2005-03-22 (this means CVS.)
6     #
7     # TODO: Prof.started? to test whether profiling has begun
8     # and Prof.clock_mode to read clock mode.
9     #
10     # Timing modes:
11     #   :clock          Use clock(3).  Default for compatibility.
12     #   :gettimeofday   Use gettimeofday(2).
13     #   :cpu            Use the CPU clock counter like RDTSC on Pentium.
14     #                   Available on Pentium and PowerPC only.
15     def self.profile_requests(timing_mode = :clock)
16       if ProfilerFilter.available?
17         ProfilerFilter.timing_mode = timing_mode
18         around_filter ProfilerFilter
19       end
20     end
21   end
22 end
23
24 class ProfilerFilter
25   class << self
26     # Check whether this filter can be used.  It requires the ruby-prof
27     # C extension and Ruby 1.8 younger than 2005-03-22 (this means CVS.)
28     def available?
29       load_prof
30       true
31     rescue LoadError
32       false
33     end
34
35     # Timing modes:
36     #   :clock          Use clock(3).  Default for compatibility.
37     #   :gettimeofday   Use gettimeofday(2).
38     #   :cpu            Use the CPU clock counter like RDTSC on Pentium.
39     #                   Available on Pentium and PowerPC only.
40     def timing_mode=(timing_mode)
41       Prof.clock_mode = TIMING_MODES[timing_mode]
42     rescue
43       # Ignore if mode set while profiling.
44       TIMING_MODES[timing_mode]
45     end
46
47     # Begin profiling.  Ignore if profiling has already begun.
48     def before(controller)
49       GC.disable
50       Prof.start rescue true
51     end
52
53     # Finish profiling.  Append results to response body.
54     def after(controller)
55       results = Prof.stop
56       GC.enable
57       GC.start
58       str = render_results(results)
59       controller.response.body.gsub!(%r(</html>\s*$)m, "#{str}</html>")
60     end
61
62     private
63       # Load ruby-prof library and initialize TIMING_MODES according
64       # to available clock modes.
65       def load_prof
66         require 'prof'
67         unless const_defined?(:TIMING_MODES)
68           const_set :TIMING_MODES, {}
69           %w(CLOCK GETTIMEOFDAY CPU).each do |mode|
70             if Prof.const_defined?(mode)
71               TIMING_MODES[mode.downcase.to_sym] = Prof.const_get(mode)
72             end
73           end
74         end
75       end
76
77       # Preformatted output based on unprof.rb by Shugo Maeda.
78       def render_results(results, percent_limit = 0.95)
79         total = results.inject(0.0) { |sum, r| sum + r.self_time }
80         total = 0.001 if total < 0.001
81
82         str = "<pre>total request time: #{'%8d' % (total * 1000)} ms<br/>"
83         str << "  %%   cumulative   self              self     total\n"
84         str << " time   seconds   seconds    calls  ms/call  ms/call  name\n"
85
86         sum = 0.0
87         for r in results
88           sum += r.self_time
89           break if sum/total > percent_limit
90
91           name =  if r.method_class.nil?
92                     r.method_id.to_s
93                   elsif r.method_class.is_a?(Class)
94                     r.method_class.to_s + "#" + r.method_id.to_s
95                   else
96                     r.method_class.to_s + "." + r.method_id.to_s
97                   end
98
99           str << sprintf(
100             "%6.2f %8.3f  %8.3f %8d %8.2f %8.2f  %s\n",
101             r.self_time / total * 100,
102             sum,
103             r.self_time,
104             r.count,
105             r.self_time * 1000 / r.count,
106             r.total_time * 1000 / r.count,
107             CGI.escapeHTML(name)
108           )
109         end
110
111         str << "</pre>"
112       end
113     end
114   end
Note: See TracBrowser for help on using the browser.