ruby-prof 0.18.0-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES +500 -0
- data/LICENSE +25 -0
- data/README.rdoc +487 -0
- data/Rakefile +113 -0
- data/bin/ruby-prof +345 -0
- data/bin/ruby-prof-check-trace +45 -0
- data/examples/flat.txt +50 -0
- data/examples/graph.dot +84 -0
- data/examples/graph.html +823 -0
- data/examples/graph.txt +139 -0
- data/examples/multi.flat.txt +23 -0
- data/examples/multi.graph.html +760 -0
- data/examples/multi.grind.dat +114 -0
- data/examples/multi.stack.html +547 -0
- data/examples/stack.html +547 -0
- data/ext/ruby_prof/extconf.rb +68 -0
- data/ext/ruby_prof/rp_call_info.c +425 -0
- data/ext/ruby_prof/rp_call_info.h +53 -0
- data/ext/ruby_prof/rp_measure.c +40 -0
- data/ext/ruby_prof/rp_measure.h +45 -0
- data/ext/ruby_prof/rp_measure_allocations.c +76 -0
- data/ext/ruby_prof/rp_measure_cpu_time.c +136 -0
- data/ext/ruby_prof/rp_measure_gc_runs.c +73 -0
- data/ext/ruby_prof/rp_measure_gc_time.c +60 -0
- data/ext/ruby_prof/rp_measure_memory.c +77 -0
- data/ext/ruby_prof/rp_measure_process_time.c +71 -0
- data/ext/ruby_prof/rp_measure_wall_time.c +45 -0
- data/ext/ruby_prof/rp_method.c +630 -0
- data/ext/ruby_prof/rp_method.h +75 -0
- data/ext/ruby_prof/rp_stack.c +173 -0
- data/ext/ruby_prof/rp_stack.h +63 -0
- data/ext/ruby_prof/rp_thread.c +277 -0
- data/ext/ruby_prof/rp_thread.h +27 -0
- data/ext/ruby_prof/ruby_prof.c +794 -0
- data/ext/ruby_prof/ruby_prof.h +60 -0
- data/ext/ruby_prof/vc/ruby_prof.sln +31 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +141 -0
- data/lib/2.6.3/ruby_prof.so +0 -0
- data/lib/ruby-prof.rb +68 -0
- data/lib/ruby-prof/aggregate_call_info.rb +76 -0
- data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
- data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
- data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
- data/lib/ruby-prof/call_info.rb +115 -0
- data/lib/ruby-prof/call_info_visitor.rb +40 -0
- data/lib/ruby-prof/compatibility.rb +179 -0
- data/lib/ruby-prof/method_info.rb +121 -0
- data/lib/ruby-prof/printers/abstract_printer.rb +104 -0
- data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
- data/lib/ruby-prof/printers/call_stack_printer.rb +265 -0
- data/lib/ruby-prof/printers/call_tree_printer.rb +143 -0
- data/lib/ruby-prof/printers/dot_printer.rb +132 -0
- data/lib/ruby-prof/printers/flat_printer.rb +70 -0
- data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +83 -0
- data/lib/ruby-prof/printers/graph_html_printer.rb +249 -0
- data/lib/ruby-prof/printers/graph_printer.rb +116 -0
- data/lib/ruby-prof/printers/multi_printer.rb +84 -0
- data/lib/ruby-prof/profile.rb +26 -0
- data/lib/ruby-prof/profile/exclude_common_methods.rb +207 -0
- data/lib/ruby-prof/profile/legacy_method_elimination.rb +50 -0
- data/lib/ruby-prof/rack.rb +174 -0
- data/lib/ruby-prof/task.rb +147 -0
- data/lib/ruby-prof/thread.rb +35 -0
- data/lib/ruby-prof/version.rb +3 -0
- data/lib/unprof.rb +10 -0
- data/ruby-prof.gemspec +58 -0
- data/test/abstract_printer_test.rb +53 -0
- data/test/aggregate_test.rb +136 -0
- data/test/basic_test.rb +128 -0
- data/test/block_test.rb +74 -0
- data/test/call_info_test.rb +78 -0
- data/test/call_info_visitor_test.rb +31 -0
- data/test/duplicate_names_test.rb +32 -0
- data/test/dynamic_method_test.rb +55 -0
- data/test/enumerable_test.rb +21 -0
- data/test/exceptions_test.rb +24 -0
- data/test/exclude_methods_test.rb +146 -0
- data/test/exclude_threads_test.rb +53 -0
- data/test/fiber_test.rb +79 -0
- data/test/issue137_test.rb +63 -0
- data/test/line_number_test.rb +80 -0
- data/test/measure_allocations_test.rb +26 -0
- data/test/measure_cpu_time_test.rb +212 -0
- data/test/measure_gc_runs_test.rb +32 -0
- data/test/measure_gc_time_test.rb +36 -0
- data/test/measure_memory_test.rb +33 -0
- data/test/measure_process_time_test.rb +61 -0
- data/test/measure_wall_time_test.rb +255 -0
- data/test/method_elimination_test.rb +84 -0
- data/test/module_test.rb +45 -0
- data/test/multi_printer_test.rb +104 -0
- data/test/no_method_class_test.rb +15 -0
- data/test/pause_resume_test.rb +166 -0
- data/test/prime.rb +54 -0
- data/test/printers_test.rb +275 -0
- data/test/printing_recursive_graph_test.rb +127 -0
- data/test/rack_test.rb +157 -0
- data/test/recursive_test.rb +215 -0
- data/test/singleton_test.rb +38 -0
- data/test/stack_printer_test.rb +77 -0
- data/test/stack_test.rb +138 -0
- data/test/start_stop_test.rb +112 -0
- data/test/test_helper.rb +267 -0
- data/test/thread_test.rb +187 -0
- data/test/unique_call_path_test.rb +202 -0
- data/test/yarv_test.rb +55 -0
- metadata +199 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RubyProf
|
4
|
+
# Helper class to simplify printing profiles of several types from
|
5
|
+
# one profiling run. Currently prints a flat profile, a callgrind
|
6
|
+
# profile, a call stack profile and a graph profile.
|
7
|
+
class MultiPrinter
|
8
|
+
def initialize(result, printers = [:stack, :graph, :tree, :flat])
|
9
|
+
@stack_printer = CallStackPrinter.new(result) if printers.include?(:stack)
|
10
|
+
@graph_printer = GraphHtmlPrinter.new(result) if printers.include?(:graph)
|
11
|
+
@tree_printer = CallTreePrinter.new(result) if printers.include?(:tree)
|
12
|
+
@flat_printer = FlatPrinter.new(result) if printers.include?(:flat)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.needs_dir?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# create profile files under options[:path] or the current
|
20
|
+
# directory. options[:profile] is used as the base name for the
|
21
|
+
# pofile file, defaults to "profile".
|
22
|
+
def print(options)
|
23
|
+
validate_print_params(options)
|
24
|
+
|
25
|
+
@profile = options.delete(:profile) || "profile"
|
26
|
+
@directory = options.delete(:path) || File.expand_path(".")
|
27
|
+
|
28
|
+
print_to_stack(options) if @stack_printer
|
29
|
+
print_to_graph(options) if @graph_printer
|
30
|
+
print_to_tree(options) if @tree_printer
|
31
|
+
print_to_flat(options) if @flat_printer
|
32
|
+
end
|
33
|
+
|
34
|
+
# the name of the call stack profile file
|
35
|
+
def stack_profile
|
36
|
+
"#{@directory}/#{@profile}.stack.html"
|
37
|
+
end
|
38
|
+
|
39
|
+
# the name of the graph profile file
|
40
|
+
def graph_profile
|
41
|
+
"#{@directory}/#{@profile}.graph.html"
|
42
|
+
end
|
43
|
+
|
44
|
+
# the name of the callgrind profile file
|
45
|
+
def tree_profile
|
46
|
+
"#{@directory}/#{@profile}.callgrind.out.#{$$}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# the name of the flat profile file
|
50
|
+
def flat_profile
|
51
|
+
"#{@directory}/#{@profile}.flat.txt"
|
52
|
+
end
|
53
|
+
|
54
|
+
def print_to_stack(options)
|
55
|
+
File.open(stack_profile, "w") do |f|
|
56
|
+
@stack_printer.print(f, options.merge(:graph => "#{@profile}.graph.html"))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def print_to_graph(options)
|
61
|
+
File.open(graph_profile, "w") do |f|
|
62
|
+
@graph_printer.print(f, options)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def print_to_tree(options)
|
67
|
+
@tree_printer.print(options.merge(:path => @directory, :profile => @profile))
|
68
|
+
end
|
69
|
+
|
70
|
+
def print_to_flat(options)
|
71
|
+
File.open(flat_profile, "w") do |f|
|
72
|
+
@flat_printer.print(f, options)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_print_params(options)
|
77
|
+
if options.is_a?(IO)
|
78
|
+
raise ArgumentError, "#{self.class.name}#print cannot print to IO objects"
|
79
|
+
elsif !options.is_a?(Hash)
|
80
|
+
raise ArgumentError, "#{self.class.name}#print requires an options hash"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'ruby-prof/profile/exclude_common_methods'
|
4
|
+
require 'ruby-prof/profile/legacy_method_elimination'
|
5
|
+
|
6
|
+
module RubyProf
|
7
|
+
class Profile
|
8
|
+
include LegacyMethodElimination
|
9
|
+
|
10
|
+
# Hides methods that, when represented as a call graph, have
|
11
|
+
# extremely large in and out degrees and make navigation impossible.
|
12
|
+
def exclude_common_methods!
|
13
|
+
ExcludeCommonMethods.apply!(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def exclude_methods!(mod, *method_or_methods)
|
17
|
+
[method_or_methods].flatten.each do |name|
|
18
|
+
exclude_method!(mod, name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def exclude_singleton_methods!(mod, *method_or_methods)
|
23
|
+
exclude_methods!(mod.singleton_class, *method_or_methods)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module RubyProf
|
4
|
+
class Profile
|
5
|
+
class ExcludeCommonMethods
|
6
|
+
ENUMERABLE_NAMES = Enumerable.instance_methods(false)
|
7
|
+
|
8
|
+
def self.apply!(profile)
|
9
|
+
new(profile).apply!
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(profile)
|
13
|
+
@profile = profile
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply!
|
17
|
+
##
|
18
|
+
# Kernel Methods
|
19
|
+
##
|
20
|
+
|
21
|
+
exclude_methods Kernel, [
|
22
|
+
:dup,
|
23
|
+
:initialize_dup,
|
24
|
+
:tap,
|
25
|
+
:send,
|
26
|
+
:public_send,
|
27
|
+
]
|
28
|
+
|
29
|
+
##
|
30
|
+
# Fundamental Types
|
31
|
+
##
|
32
|
+
|
33
|
+
exclude_methods BasicObject, :"!="
|
34
|
+
exclude_methods Method, :"[]"
|
35
|
+
exclude_methods Module, :new
|
36
|
+
exclude_methods Class, :new
|
37
|
+
exclude_methods Proc, :call, :yield
|
38
|
+
exclude_methods Range, :each
|
39
|
+
exclude_methods Integer, :times
|
40
|
+
|
41
|
+
##
|
42
|
+
# Value Types
|
43
|
+
##
|
44
|
+
|
45
|
+
exclude_methods String, [
|
46
|
+
:sub,
|
47
|
+
:sub!,
|
48
|
+
:gsub,
|
49
|
+
:gsub!,
|
50
|
+
]
|
51
|
+
|
52
|
+
##
|
53
|
+
# Emumerables
|
54
|
+
##
|
55
|
+
|
56
|
+
exclude_enumerable Enumerable
|
57
|
+
exclude_enumerable Enumerator
|
58
|
+
|
59
|
+
##
|
60
|
+
# Collections
|
61
|
+
##
|
62
|
+
|
63
|
+
exclude_enumerable Array, [
|
64
|
+
:each_index,
|
65
|
+
:map!,
|
66
|
+
:select!,
|
67
|
+
:reject!,
|
68
|
+
:collect!,
|
69
|
+
:sort!,
|
70
|
+
:sort_by!,
|
71
|
+
:index,
|
72
|
+
:delete_if,
|
73
|
+
:keep_if,
|
74
|
+
:drop_while,
|
75
|
+
:uniq,
|
76
|
+
:uniq!,
|
77
|
+
:"==",
|
78
|
+
:eql?,
|
79
|
+
:hash,
|
80
|
+
:to_json,
|
81
|
+
:as_json,
|
82
|
+
:encode_json,
|
83
|
+
]
|
84
|
+
|
85
|
+
exclude_enumerable Hash, [
|
86
|
+
:dup,
|
87
|
+
:initialize_dup,
|
88
|
+
:fetch,
|
89
|
+
:"[]",
|
90
|
+
:"[]=",
|
91
|
+
:each_key,
|
92
|
+
:each_value,
|
93
|
+
:each_pair,
|
94
|
+
:map!,
|
95
|
+
:select!,
|
96
|
+
:reject!,
|
97
|
+
:collect!,
|
98
|
+
:delete_if,
|
99
|
+
:keep_if,
|
100
|
+
:slice,
|
101
|
+
:slice!,
|
102
|
+
:except,
|
103
|
+
:except!,
|
104
|
+
:"==",
|
105
|
+
:eql?,
|
106
|
+
:hash,
|
107
|
+
:to_json,
|
108
|
+
:as_json,
|
109
|
+
:encode_json,
|
110
|
+
]
|
111
|
+
|
112
|
+
exclude_enumerable Set, [
|
113
|
+
:map!,
|
114
|
+
:select!,
|
115
|
+
:reject!,
|
116
|
+
:collect!,
|
117
|
+
:classify,
|
118
|
+
:delete_if,
|
119
|
+
:keep_if,
|
120
|
+
:divide,
|
121
|
+
:"==",
|
122
|
+
:eql?,
|
123
|
+
:hash,
|
124
|
+
:to_json,
|
125
|
+
:as_json,
|
126
|
+
:encode_json,
|
127
|
+
]
|
128
|
+
|
129
|
+
##
|
130
|
+
# Garbage Collection
|
131
|
+
##
|
132
|
+
|
133
|
+
exclude_singleton_methods GC, [
|
134
|
+
:start
|
135
|
+
]
|
136
|
+
|
137
|
+
##
|
138
|
+
# Unicorn
|
139
|
+
##
|
140
|
+
|
141
|
+
if defined?(Unicorn)
|
142
|
+
exclude_methods Unicorn::HttpServer, :process_client
|
143
|
+
end
|
144
|
+
|
145
|
+
if defined?(Unicorn::OobGC)
|
146
|
+
exclude_methods Unicorn::OobGC, :process_client
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# New Relic
|
151
|
+
##
|
152
|
+
|
153
|
+
if defined?(NewRelic::Agent)
|
154
|
+
if defined?(NewRelic::Agent::Instrumentation::MiddlewareTracing)
|
155
|
+
exclude_methods NewRelic::Agent::Instrumentation::MiddlewareTracing, [
|
156
|
+
:call
|
157
|
+
]
|
158
|
+
end
|
159
|
+
|
160
|
+
if defined?(NewRelic::Agent::MethodTracerHelpers)
|
161
|
+
exclude_methods NewRelic::Agent::MethodTracerHelpers, [
|
162
|
+
:trace_execution_scoped,
|
163
|
+
:log_errors,
|
164
|
+
]
|
165
|
+
|
166
|
+
exclude_singleton_methods NewRelic::Agent::MethodTracerHelpers, [
|
167
|
+
:trace_execution_scoped,
|
168
|
+
:log_errors,
|
169
|
+
]
|
170
|
+
end
|
171
|
+
|
172
|
+
if defined?(NewRelic::Agent::MethodTracer)
|
173
|
+
exclude_methods NewRelic::Agent::MethodTracer, [
|
174
|
+
:trace_execution_scoped,
|
175
|
+
:trace_execution_unscoped,
|
176
|
+
]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Miscellaneous Methods
|
182
|
+
##
|
183
|
+
|
184
|
+
if defined?(Mustache)
|
185
|
+
exclude_methods Mustache::Context, [
|
186
|
+
:fetch
|
187
|
+
]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def exclude_methods(mod, *method_or_methods)
|
194
|
+
@profile.exclude_methods!(mod, method_or_methods)
|
195
|
+
end
|
196
|
+
|
197
|
+
def exclude_singleton_methods(mod, *method_or_methods)
|
198
|
+
@profile.exclude_singleton_methods!(mod, method_or_methods)
|
199
|
+
end
|
200
|
+
|
201
|
+
def exclude_enumerable(mod, *method_or_methods)
|
202
|
+
exclude_methods(mod, [:each, *method_or_methods])
|
203
|
+
exclude_methods(mod, ENUMERABLE_NAMES)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RubyProf
|
2
|
+
class Profile
|
3
|
+
module LegacyMethodElimination
|
4
|
+
# eliminate some calls from the graph by merging the information into callers.
|
5
|
+
# matchers can be a list of strings or regular expressions or the name of a file containing regexps.
|
6
|
+
def eliminate_methods!(matchers)
|
7
|
+
RubyProf.deprecation_warning(
|
8
|
+
"Method 'eliminate_methods!' is deprecated",
|
9
|
+
"Please call 'exclude_methods!' before starting the profile run instead."
|
10
|
+
)
|
11
|
+
matchers = read_regexps_from_file(matchers) if matchers.is_a?(String)
|
12
|
+
eliminated = []
|
13
|
+
threads.each do |thread|
|
14
|
+
matchers.each{ |matcher| eliminated.concat(eliminate_methods(thread.methods, matcher)) }
|
15
|
+
end
|
16
|
+
eliminated
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# read regexps from file
|
22
|
+
def read_regexps_from_file(file_name)
|
23
|
+
matchers = []
|
24
|
+
File.open(file_name).each_line do |l|
|
25
|
+
next if (l =~ /^(#.*|\s*)$/) # emtpy lines and lines starting with #
|
26
|
+
matchers << Regexp.new(l.strip)
|
27
|
+
end
|
28
|
+
matchers
|
29
|
+
end
|
30
|
+
|
31
|
+
# eliminate methods matching matcher
|
32
|
+
def eliminate_methods(methods, matcher)
|
33
|
+
eliminated = []
|
34
|
+
i = 0
|
35
|
+
while i < methods.size
|
36
|
+
method_info = methods[i]
|
37
|
+
method_name = method_info.full_name
|
38
|
+
if matcher === method_name
|
39
|
+
raise "can't eliminate root method" if method_info.root?
|
40
|
+
eliminated << methods.delete_at(i)
|
41
|
+
method_info.eliminate!
|
42
|
+
else
|
43
|
+
i += 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
eliminated
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class RubyProf
|
6
|
+
def initialize(app, options = {})
|
7
|
+
@app = app
|
8
|
+
|
9
|
+
options[:min_percent] ||= 1
|
10
|
+
|
11
|
+
options[:path] ||= Dir.tmpdir
|
12
|
+
FileUtils.mkdir_p(options[:path])
|
13
|
+
|
14
|
+
@skip_paths = options[:skip_paths] || [%r{^/assets}, %r{\.(css|js|png|jpeg|jpg|gif)$}]
|
15
|
+
@only_paths = options[:only_paths]
|
16
|
+
|
17
|
+
@max_requests = options[:max_requests]
|
18
|
+
|
19
|
+
@options = options
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(env)
|
23
|
+
request = Rack::Request.new(env)
|
24
|
+
|
25
|
+
if should_profile?(request.path)
|
26
|
+
profiler.resume
|
27
|
+
begin
|
28
|
+
result = @app.call(env)
|
29
|
+
ensure
|
30
|
+
profiler.pause
|
31
|
+
end
|
32
|
+
|
33
|
+
if profiler.max_requests_reached?
|
34
|
+
prefix = if aggregate_requests?
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
request.path.gsub('/', '-')[1..-1]
|
38
|
+
end
|
39
|
+
|
40
|
+
profiler.print!(prefix)
|
41
|
+
delete_profiler!
|
42
|
+
end
|
43
|
+
|
44
|
+
result
|
45
|
+
else
|
46
|
+
@app.call(env)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
class RackProfiler
|
53
|
+
def initialize(options)
|
54
|
+
@options = options
|
55
|
+
|
56
|
+
@profile = ::RubyProf::Profile.new(profiling_options)
|
57
|
+
@profile.start
|
58
|
+
@profile.pause
|
59
|
+
|
60
|
+
@printer_klasses = options[:printers] || default_printers
|
61
|
+
|
62
|
+
@tmpdir = options[:path]
|
63
|
+
|
64
|
+
@max_requests = options[:max_requests] || 1
|
65
|
+
@requests_count = 0
|
66
|
+
|
67
|
+
@printed = false
|
68
|
+
# if running across multiple requests, we want to make sure that the
|
69
|
+
# ongoing profile is not lost if the process shuts down before the
|
70
|
+
# max request count is reached
|
71
|
+
ObjectSpace.define_finalizer(self, proc { print! })
|
72
|
+
end
|
73
|
+
|
74
|
+
def resume
|
75
|
+
@profile.resume
|
76
|
+
end
|
77
|
+
|
78
|
+
def pause
|
79
|
+
@profile.pause
|
80
|
+
@requests_count += 1
|
81
|
+
end
|
82
|
+
|
83
|
+
def max_requests_reached?
|
84
|
+
@requests_count >= @max_requests
|
85
|
+
end
|
86
|
+
|
87
|
+
def print!(prefix = nil)
|
88
|
+
return false if @printed || @requests_count == 0
|
89
|
+
|
90
|
+
data = @profile.stop
|
91
|
+
|
92
|
+
prefix ||= "multi-requests-#{@requests_count}"
|
93
|
+
|
94
|
+
@printer_klasses.each do |printer_klass, base_name|
|
95
|
+
printer = printer_klass.new(data)
|
96
|
+
|
97
|
+
if base_name.respond_to?(:call)
|
98
|
+
base_name = base_name.call
|
99
|
+
end
|
100
|
+
|
101
|
+
if printer_klass == ::RubyProf::MultiPrinter \
|
102
|
+
|| printer_klass == ::RubyProf::CallTreePrinter
|
103
|
+
printer.print(@options.merge(:profile => "#{prefix}-#{base_name}"))
|
104
|
+
else
|
105
|
+
file_name = ::File.join(@tmpdir, "#{prefix}-#{base_name}")
|
106
|
+
::File.open(file_name, 'wb') do |file|
|
107
|
+
printer.print(file, @options)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
@printed = true
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def profiling_options
|
118
|
+
options = {}
|
119
|
+
options[:measure_mode] = ::RubyProf.measure_mode
|
120
|
+
options[:exclude_threads] =
|
121
|
+
if @options[:ignore_existing_threads]
|
122
|
+
Thread.list.select{|t| t != Thread.current}
|
123
|
+
else
|
124
|
+
::RubyProf.exclude_threads
|
125
|
+
end
|
126
|
+
if @options[:request_thread_only]
|
127
|
+
options[:include_threads] = [Thread.current]
|
128
|
+
end
|
129
|
+
if @options[:merge_fibers]
|
130
|
+
options[:merge_fibers] = true
|
131
|
+
end
|
132
|
+
options
|
133
|
+
end
|
134
|
+
|
135
|
+
def default_printers
|
136
|
+
{::RubyProf::FlatPrinter => 'flat.txt',
|
137
|
+
::RubyProf::GraphPrinter => 'graph.txt',
|
138
|
+
::RubyProf::GraphHtmlPrinter => 'graph.html',
|
139
|
+
::RubyProf::CallStackPrinter => 'call_stack.html'}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def profiler
|
144
|
+
if aggregate_requests?
|
145
|
+
@@_shared_profiler ||= RackProfiler.new(@options)
|
146
|
+
else
|
147
|
+
@_profiler ||= RackProfiler.new(@options)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def delete_profiler!
|
152
|
+
if aggregate_requests?
|
153
|
+
@@_shared_profiler.print! if @@_shared_profiler
|
154
|
+
@@_shared_profiler = nil
|
155
|
+
else
|
156
|
+
@_profiler = nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def aggregate_requests?
|
161
|
+
!@max_requests.nil?
|
162
|
+
end
|
163
|
+
|
164
|
+
def should_profile?(path)
|
165
|
+
return false if paths_match?(path, @skip_paths)
|
166
|
+
|
167
|
+
@only_paths ? paths_match?(path, @only_paths) : true
|
168
|
+
end
|
169
|
+
|
170
|
+
def paths_match?(path, paths)
|
171
|
+
paths.any? { |skip_path| skip_path =~ path }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|