Class: Rack::Profiler

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/contrib/profiler.rb,
lib/rack/contrib/perftools_profiler.rb

Overview

Set the profile=process_time query parameter to download a calltree profile of the request.

Pass the :printer option to pick a different result format.

Constant Summary collapse

MODES =
%w(
  process_time
  wall_time
  cpu_time
  allocations
  memory
  gc_runs
  gc_time
)
DEFAULT_PRINTER =
:text
DEFAULT_CONTENT_TYPE =
'application/octet-stream'
PRINTER_CONTENT_TYPE =
{
  RubyProf::FlatPrinter => 'text/plain',
  RubyProf::GraphPrinter => 'text/plain',
  RubyProf::GraphHtmlPrinter => 'text/html'
}
PROFILING_DATA_FILE =
::File.join(self.tmpdir, 'rack_perftools_profiler.prof')
PROFILING_SETTINGS_FILE =
::File.join(self.tmpdir, 'rack_perftools_profiler.config')
DEFAULT_MODE =
:cputime
UNSET_FREQUENCY =
-1

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options) ⇒ Profiler

Accepts a :printer => [:call_tree|:graph_html|:graph|:flat] option defaulting to :call_tree.

Raises:

  • (ArgumentError)


30
31
32
33
34
# File 'lib/rack/contrib/profiler.rb', line 30

def initialize(app, options = {})
  @app = app
  @printer = parse_printer(options[:printer])
  @times = (options[:times] || 1).to_i
end

Class Method Details

.clear_dataObject



174
175
176
# File 'lib/rack/contrib/perftools_profiler.rb', line 174

def self.clear_data
  ::File.delete(PROFILING_DATA_FILE) if ::File.exists?(PROFILING_DATA_FILE)
end

.tmpdirObject



148
149
150
151
152
# File 'lib/rack/contrib/perftools_profiler.rb', line 148

def self.tmpdir
  dir = nil
  Dir.chdir Dir.tmpdir do dir = Dir.pwd end # HACK FOR OSX
  dir
end

Instance Method Details

#call(env) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/rack/contrib/profiler.rb', line 36

def call(env)
  if mode = profiling?(env)
    profile(env, mode)
  else
    @app.call(env)
  end
end

#data(options = {}) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/rack/contrib/perftools_profiler.rb', line 196

def data(options = {})
  printer = (options.fetch('printer') {@printer}).to_sym
  ignore = options.fetch('ignore') { nil }
  focus = options.fetch('focus') { nil }
  if ::File.exists?(PROFILING_DATA_FILE)
    args = "--#{printer}"
    args += " --ignore=#{ignore}" if ignore
    args += " --focus=#{focus}" if focus
    cmd = "pprof.rb #{args} #{PROFILING_DATA_FILE}"
    [printer, `#{cmd}`]
  else
    [:none, nil]
  end
end

#profileObject



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rack/contrib/profiler.rb', line 60

def profile(env, mode)
  RubyProf.measure_mode = RubyProf.const_get(mode.upcase)

  GC.enable_stats if GC.respond_to?(:enable_stats)
  result = RubyProf.profile do
    @times.times { @app.call(env) }
  end
  GC.disable_stats if GC.respond_to?(:disable_stats)

  [200, headers(@printer, env, mode), print(@printer, result)]
end

#profiling?Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rack/contrib/profiler.rb', line 45

def profiling?(env)
  unless RubyProf.running?
    request = Rack::Request.new(env)
    if mode = request.params.delete('profile')
      if RubyProf.const_defined?(mode.upcase)
        mode
      else
        env['rack.errors'].write "Invalid RubyProf measure_mode: " +
          "#{mode}. Use one of #{MODES.to_a.join(', ')}"
        false
      end
    end
  end
end

#startObject



178
179
180
181
182
# File 'lib/rack/contrib/perftools_profiler.rb', line 178

def start
  set_env_vars
  PerfTools::CpuProfiler.start(PROFILING_DATA_FILE)
  self.profiling = true
end

#stopObject



184
185
186
187
188
# File 'lib/rack/contrib/perftools_profiler.rb', line 184

def stop
  PerfTools::CpuProfiler.stop
  self.profiling = false
  unset_env_vars
end