ruby-prof 0.11.0.rc1-x86-mingw32 → 0.11.0.rc2-x86-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.
- data/CHANGES +20 -5
- data/README.rdoc +10 -3
- data/ext/ruby_prof/rp_call_info.c +108 -79
- data/ext/ruby_prof/rp_call_info.h +1 -0
- data/ext/ruby_prof/rp_measure_cpu_time.c +111 -111
- data/ext/ruby_prof/rp_measure_gc_runs.c +1 -1
- data/ext/ruby_prof/rp_measure_memory.c +1 -1
- data/ext/ruby_prof/rp_measure_process_time.c +71 -71
- data/ext/ruby_prof/rp_measure_wall_time.c +1 -1
- data/ext/ruby_prof/rp_method.c +143 -73
- data/ext/ruby_prof/rp_method.h +7 -4
- data/ext/ruby_prof/rp_stack.c +16 -1
- data/ext/ruby_prof/rp_stack.h +4 -1
- data/ext/ruby_prof/rp_thread.c +165 -35
- data/ext/ruby_prof/rp_thread.h +8 -2
- data/ext/ruby_prof/ruby_prof.c +164 -171
- data/ext/ruby_prof/ruby_prof.h +53 -54
- data/ext/ruby_prof/vc/ruby_prof.sln +26 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +109 -0
- data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +105 -0
- data/lib/1.8/ruby_prof.so +0 -0
- data/lib/1.9/ruby_prof.so +0 -0
- data/lib/ruby-prof/aggregate_call_info.rb +9 -7
- data/lib/ruby-prof/call_info.rb +2 -27
- data/lib/ruby-prof/call_info_visitor.rb +42 -0
- data/lib/ruby-prof/{empty.png → images/empty.png} +0 -0
- data/lib/ruby-prof/{minus.png → images/minus.png} +0 -0
- data/lib/ruby-prof/{plus.png → images/plus.png} +0 -0
- data/lib/ruby-prof/method_info.rb +13 -15
- data/lib/ruby-prof/{abstract_printer.rb → printers/abstract_printer.rb} +36 -2
- data/lib/ruby-prof/printers/call_info_printer.rb +40 -0
- data/lib/ruby-prof/{call_stack_printer.rb → printers/call_stack_printer.rb} +11 -16
- data/lib/ruby-prof/{call_tree_printer.rb → printers/call_tree_printer.rb} +4 -4
- data/lib/ruby-prof/{dot_printer.rb → printers/dot_printer.rb} +11 -31
- data/lib/ruby-prof/{flat_printer.rb → printers/flat_printer.rb} +26 -35
- data/lib/ruby-prof/{flat_printer_with_line_numbers.rb → printers/flat_printer_with_line_numbers.rb} +14 -25
- data/lib/ruby-prof/printers/graph_html_printer.rb +248 -0
- data/lib/ruby-prof/{graph_printer.rb → printers/graph_printer.rb} +31 -73
- data/lib/ruby-prof/{multi_printer.rb → printers/multi_printer.rb} +0 -0
- data/lib/ruby-prof/profile.rb +27 -22
- data/lib/ruby-prof/rack.rb +22 -12
- data/ruby-prof.gemspec +58 -0
- data/test/aggregate_test.rb +6 -6
- data/test/call_info_visitor_test.rb +31 -0
- data/test/duplicate_names_test.rb +1 -1
- data/test/dynamic_method_test.rb +1 -1
- data/test/enumerable_test.rb +1 -1
- data/test/exclude_threads_test.rb +2 -2
- data/test/gc_test.rb +35 -0
- data/test/line_number_test.rb +2 -2
- data/test/measure_cpu_time_test.rb +5 -5
- data/test/measure_process_time_test.rb +5 -5
- data/test/measure_wall_time_test.rb +5 -5
- data/test/method_elimination_test.rb +3 -3
- data/test/module_test.rb +1 -1
- data/test/no_method_class_test.rb +1 -1
- data/test/printers_test.rb +16 -8
- data/test/recursive_test.rb +115 -91
- data/test/stack_test.rb +1 -1
- data/test/start_stop_test.rb +13 -13
- data/test/summarize_test.rb +48 -0
- data/test/test_suite.rb +1 -0
- data/test/thread_test.rb +16 -12
- data/test/unique_call_path_test.rb +10 -10
- metadata +65 -85
- data/lib/1.9/ruby_prof.exp +0 -0
- data/lib/1.9/ruby_prof.ilk +0 -0
- data/lib/1.9/ruby_prof.lib +0 -0
- data/lib/1.9/ruby_prof.pdb +0 -0
- data/lib/ruby-prof.rb +0 -70
- data/lib/ruby-prof/graph_html_printer.rb +0 -286
- data/lib/ruby-prof/symbol_to_proc.rb +0 -10
- data/lib/ruby_prof.exp +0 -0
- data/lib/ruby_prof.ilk +0 -0
- data/lib/ruby_prof.lib +0 -0
- data/lib/ruby_prof.pdb +0 -0
- data/lib/ruby_prof.so +0 -0
- data/lib/unprof.rb +0 -10
- data/test/do_nothing.rb +0 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# The call info visitor class does a depth-first traversal
|
2
|
+
# across a thread's call stack. At each call_info node,
|
3
|
+
# the visitor executes the block provided in the
|
4
|
+
# #visit method. The block is passed two parameters, the
|
5
|
+
# event and the call_info instance. Event will be
|
6
|
+
# either :enter or :exit.
|
7
|
+
#
|
8
|
+
# visitor = RubyProf::CallInfoVisitor.new(result.threads.first)
|
9
|
+
#
|
10
|
+
# method_names = Array.new
|
11
|
+
#
|
12
|
+
# visitor.visit do |call_info, event|
|
13
|
+
# method_names << call_info.target.full_name if event == :enter
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# puts method_names
|
17
|
+
|
18
|
+
module RubyProf
|
19
|
+
class CallInfoVisitor
|
20
|
+
attr_reader :block, :thread
|
21
|
+
|
22
|
+
def initialize(thread)
|
23
|
+
@thread = thread
|
24
|
+
end
|
25
|
+
|
26
|
+
def visit(&block)
|
27
|
+
@block = block
|
28
|
+
|
29
|
+
self.thread.top_method.call_infos.each do |call_info|
|
30
|
+
self.visit_call_info(call_info)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def visit_call_info(call_info)
|
35
|
+
self.block.call(call_info, :enter)
|
36
|
+
call_info.children.each do |child|
|
37
|
+
visit_call_info(child)
|
38
|
+
end
|
39
|
+
self.block.call(call_info, :exit)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -29,7 +29,7 @@ module RubyProf
|
|
29
29
|
def total_time
|
30
30
|
@total_time ||= begin
|
31
31
|
call_infos.inject(0) do |sum, call_info|
|
32
|
-
sum += call_info.total_time
|
32
|
+
sum += call_info.total_time unless call_info.recursive
|
33
33
|
sum
|
34
34
|
end
|
35
35
|
end
|
@@ -38,7 +38,8 @@ module RubyProf
|
|
38
38
|
def self_time
|
39
39
|
@self_time ||= begin
|
40
40
|
call_infos.inject(0) do |sum, call_info|
|
41
|
-
sum += call_info.self_time
|
41
|
+
sum += call_info.self_time unless call_info.recursive
|
42
|
+
sum
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
@@ -46,7 +47,8 @@ module RubyProf
|
|
46
47
|
def wait_time
|
47
48
|
@wait_time ||= begin
|
48
49
|
call_infos.inject(0) do |sum, call_info|
|
49
|
-
sum += call_info.wait_time
|
50
|
+
sum += call_info.wait_time unless call_info.recursive
|
51
|
+
sum
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
@@ -54,7 +56,7 @@ module RubyProf
|
|
54
56
|
def children_time
|
55
57
|
@children_time ||= begin
|
56
58
|
call_infos.inject(0) do |sum, call_info|
|
57
|
-
sum += call_info.children_time
|
59
|
+
sum += call_info.children_time unless call_info.recursive
|
58
60
|
sum
|
59
61
|
end
|
60
62
|
end
|
@@ -74,6 +76,12 @@ module RubyProf
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
79
|
+
def recursive?
|
80
|
+
call_infos.detect do |call_info|
|
81
|
+
call_info.recursive
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
77
85
|
def children
|
78
86
|
@children ||= begin
|
79
87
|
call_infos.map do |call_info|
|
@@ -109,17 +117,7 @@ module RubyProf
|
|
109
117
|
end
|
110
118
|
|
111
119
|
def to_s
|
112
|
-
full_name
|
113
|
-
end
|
114
|
-
|
115
|
-
def dump
|
116
|
-
res = ""
|
117
|
-
res << "MINFO: #{klass_name}##{method_name} total_time: #{total_time} (#{full_name})\n"
|
118
|
-
call_infos.each do |ci|
|
119
|
-
pinfo = ci.root? ? "TOPLEVEL" : (p=ci.parent.target; "#{p.klass_name}##{p.method_name} (#{ci.parent.object_id}) (#{p.full_name})")
|
120
|
-
res << "CINFO[#{ci.object_id}] called #{ci.called} times from #{pinfo}\n"
|
121
|
-
end
|
122
|
-
res
|
120
|
+
"#{self.full_name} (c: #{self.called}, tt: #{self.total_time}, st: #{self.self_time}, ct: #{self.children_time})"
|
123
121
|
end
|
124
122
|
|
125
123
|
# remove method from the call graph. should not be called directly.
|
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
module RubyProf
|
4
4
|
class AbstractPrinter
|
5
|
+
# Create a new printer.
|
6
|
+
#
|
7
|
+
# result should be the output generated from a profiling run
|
5
8
|
def initialize(result)
|
6
9
|
@result = result
|
7
10
|
@output = nil
|
8
|
-
@options = {}
|
9
11
|
end
|
10
12
|
|
11
13
|
# Specify print options.
|
@@ -47,5 +49,37 @@ module RubyProf
|
|
47
49
|
end
|
48
50
|
name
|
49
51
|
end
|
52
|
+
|
53
|
+
# Print a profiling report to the provided output.
|
54
|
+
#
|
55
|
+
# output - Any IO object, including STDOUT or a file.
|
56
|
+
# The default value is STDOUT.
|
57
|
+
#
|
58
|
+
# options - Hash of print options. See #setup_options
|
59
|
+
# for more information. Note that each printer can
|
60
|
+
# define its own set of options.
|
61
|
+
def print(output = STDOUT, options = {})
|
62
|
+
@output = output
|
63
|
+
setup_options(options)
|
64
|
+
print_threads
|
65
|
+
end
|
66
|
+
|
67
|
+
def print_threads
|
68
|
+
@result.threads.each do |thread|
|
69
|
+
print_thread(thread)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def print_thread(thread)
|
74
|
+
print_header(thread)
|
75
|
+
print_methods(thread)
|
76
|
+
print_footer(thread)
|
77
|
+
end
|
78
|
+
|
79
|
+
def print_header(thread)
|
80
|
+
end
|
81
|
+
|
82
|
+
def print_footer(thread)
|
83
|
+
end
|
50
84
|
end
|
51
|
-
end
|
85
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RubyProf
|
4
|
+
# Prints out the call graph based on CallInfo instances. This
|
5
|
+
# is mainly for debugging purposes as it provides access into
|
6
|
+
# into RubyProf's internals.
|
7
|
+
|
8
|
+
class CallInfoPrinter < AbstractPrinter
|
9
|
+
TIME_WIDTH = 0
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def print_header(thread)
|
14
|
+
@output << "Thread ID: #{thread.id}\n"
|
15
|
+
@output << "Total Time: #{thread.top_method.total_time}\n"
|
16
|
+
@output << "Sort by: #{sort_method}\n"
|
17
|
+
@output << "\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_methods(thread)
|
21
|
+
visitor = CallInfoVisitor.new(thread)
|
22
|
+
|
23
|
+
visitor.visit do |call_info, event|
|
24
|
+
if event == :enter
|
25
|
+
@output << " " * call_info.depth
|
26
|
+
@output << call_info.target.full_name
|
27
|
+
@output << " ("
|
28
|
+
@output << "tt:#{sprintf("%#{TIME_WIDTH}.2f", call_info.total_time)}, "
|
29
|
+
@output << "st:#{sprintf("%#{TIME_WIDTH}.2f", call_info.self_time)}, "
|
30
|
+
@output << "wt:#{sprintf("%#{TIME_WIDTH}.2f", call_info.wait_time)}, "
|
31
|
+
@output << "ct:#{sprintf("%#{TIME_WIDTH}.2f", call_info.children_time)}, "
|
32
|
+
@output << "call:#{call_info.called}, "
|
33
|
+
@output << "rec:#{call_info.recursive}"
|
34
|
+
@output << ")"
|
35
|
+
@output << "\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -42,28 +42,23 @@ module RubyProf
|
|
42
42
|
@graph_html = "file://" + @graph_html if @graph_html[0]=="/"
|
43
43
|
end
|
44
44
|
|
45
|
-
@overall_threads_time = 0.0
|
46
|
-
@threads_totals = Hash.new
|
47
|
-
@result.threads.each do |thread_id, methods|
|
48
|
-
roots = methods.select{|m| m.root?}
|
49
|
-
thread_total_time = sum(roots.map{|r| self.total_time(r.call_infos)})
|
50
|
-
@overall_threads_time += thread_total_time
|
51
|
-
@threads_totals[thread_id] = thread_total_time
|
52
|
-
end
|
53
|
-
|
54
45
|
print_header
|
55
46
|
|
56
|
-
@result.threads.
|
57
|
-
|
58
|
-
|
59
|
-
|
47
|
+
@overall_threads_time = @result.threads.inject(0) do |val, thread|
|
48
|
+
val += thread.top_method.total_time
|
49
|
+
end
|
50
|
+
|
51
|
+
@result.threads.each do |thread|
|
52
|
+
@current_thread_id = thread.id
|
53
|
+
@overall_time = thread.top_method.total_time
|
54
|
+
@output.print "<div class=\"thread\">Thread: #{thread.id} (#{"%4.2f%%" % ((@overall_time/@overall_threads_time)*100)} ~ #{@overall_time})</div>"
|
60
55
|
@output.print "<ul name=\"thread\">"
|
61
|
-
|
56
|
+
thread.methods.each do |m|
|
62
57
|
# $stderr.print m.dump
|
63
58
|
next unless m.root?
|
64
59
|
m.call_infos.each do |ci|
|
65
60
|
next unless ci.root?
|
66
|
-
print_stack ci,
|
61
|
+
print_stack ci, thread.top_method.total_time
|
67
62
|
end
|
68
63
|
end
|
69
64
|
@output.print "</ul>"
|
@@ -185,7 +180,7 @@ module RubyProf
|
|
185
180
|
def copy_image_files
|
186
181
|
if @output.is_a?(File)
|
187
182
|
target_dir = File.dirname(@output.path)
|
188
|
-
image_dir = File.dirname(__FILE__)
|
183
|
+
image_dir = File.join(File.dirname(__FILE__), '..', 'images')
|
189
184
|
%w(empty plus minus).each do |img|
|
190
185
|
source_file = "#{image_dir}/#{img}.png"
|
191
186
|
target_file = "#{target_dir}/#{img}.png"
|
@@ -54,8 +54,8 @@ module RubyProf
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def print_threads
|
57
|
-
@result.threads.each do |
|
58
|
-
|
57
|
+
@result.threads.each do |thread|
|
58
|
+
print_thread(thread)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
@@ -67,8 +67,8 @@ module RubyProf
|
|
67
67
|
File.expand_path(method.source_file)
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
71
|
-
methods.reverse_each do |method|
|
70
|
+
def print_thread(thread)
|
71
|
+
thread.methods.reverse_each do |method|
|
72
72
|
# Print out the file and method name
|
73
73
|
@output << "fl=#{file(method)}\n"
|
74
74
|
@output << "fn=#{method_name(method)}\n"
|
@@ -45,10 +45,8 @@ module RubyProf
|
|
45
45
|
@output = output
|
46
46
|
setup_options(options)
|
47
47
|
|
48
|
-
total_time = thread_times.values.inject{|a,b| a+b}
|
49
|
-
|
50
48
|
puts 'digraph "Profile" {'
|
51
|
-
puts "label=\"#{mode_name} >=#{min_percent}%\\nTotal: #{total_time}\";"
|
49
|
+
#puts "label=\"#{mode_name} >=#{min_percent}%\\nTotal: #{total_time}\";"
|
52
50
|
puts "labelloc=t;"
|
53
51
|
puts "labeljust=l;"
|
54
52
|
print_threads
|
@@ -64,32 +62,14 @@ module RubyProf
|
|
64
62
|
RubyProf.constants.find{|c| RubyProf.const_get(c) == RubyProf.measure_mode}
|
65
63
|
end
|
66
64
|
|
67
|
-
# Computes the total time per thread:
|
68
|
-
def thread_times
|
69
|
-
@thread_times ||= begin
|
70
|
-
times = {}
|
71
|
-
@result.threads.each do |thread_id, methods|
|
72
|
-
toplevel = methods.sort.last
|
73
|
-
|
74
|
-
total_time = toplevel.total_time
|
75
|
-
# This looks like a hack for very small times... from GraphPrinter
|
76
|
-
total_time = 0.01 if total_time == 0
|
77
|
-
times[thread_id] = total_time
|
78
|
-
end
|
79
|
-
|
80
|
-
times
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
65
|
def print_threads
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
print_methods(thread_id, methods)
|
66
|
+
@result.threads.each do |thread|
|
67
|
+
puts "subgraph \"Thread #{thread.id}\" {"
|
68
|
+
|
69
|
+
print_thread(thread)
|
90
70
|
puts "}"
|
91
71
|
|
92
|
-
print_classes(
|
72
|
+
print_classes(thread)
|
93
73
|
end
|
94
74
|
end
|
95
75
|
|
@@ -98,9 +78,9 @@ module RubyProf
|
|
98
78
|
subject.object_id
|
99
79
|
end
|
100
80
|
|
101
|
-
def
|
102
|
-
total_time =
|
103
|
-
methods.sort_by(&sort_method).reverse_each do |method|
|
81
|
+
def print_thread(thread)
|
82
|
+
total_time = thread.top_method.total_time
|
83
|
+
thread.methods.sort_by(&sort_method).reverse_each do |method|
|
104
84
|
total_percentage = (method.total_time/total_time) * 100
|
105
85
|
|
106
86
|
next if total_percentage < min_percent
|
@@ -111,9 +91,9 @@ module RubyProf
|
|
111
91
|
end
|
112
92
|
end
|
113
93
|
|
114
|
-
def print_classes(
|
94
|
+
def print_classes(thread)
|
115
95
|
grouped = {}
|
116
|
-
methods.each{|m| grouped[m.klass_name] ||= []; grouped[m.klass_name] << m}
|
96
|
+
thread.methods.each{|m| grouped[m.klass_name] ||= []; grouped[m.klass_name] << m}
|
117
97
|
grouped.each do |cls, methods2|
|
118
98
|
# Filter down to just seen methods
|
119
99
|
big_methods, small_methods = methods2.partition{|m| @seen_methods.include? m}
|
@@ -12,46 +12,31 @@ module RubyProf
|
|
12
12
|
# printer.print(STDOUT, {})
|
13
13
|
#
|
14
14
|
class FlatPrinter < AbstractPrinter
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
# The default value is STDOUT.
|
19
|
-
#
|
20
|
-
# options - Hash of print options. See #setup_options
|
21
|
-
# for more information.
|
22
|
-
#
|
23
|
-
def print(output = STDOUT, options = {})
|
24
|
-
@output = output
|
25
|
-
# Now sort methods by largest self time by default,
|
26
|
-
# not total time like in other printouts
|
27
|
-
options[:sort_method] ||= :self_time
|
28
|
-
setup_options(options)
|
29
|
-
print_threads
|
15
|
+
# Override for this printer to sort by self time by default
|
16
|
+
def sort_method
|
17
|
+
@options[:sort_method] || :self_time
|
30
18
|
end
|
31
19
|
|
32
20
|
private
|
33
21
|
|
34
|
-
def print_threads
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
def print_methods(thread_id, methods)
|
42
|
-
# Get total time
|
43
|
-
toplevel = methods.max
|
44
|
-
total_time = toplevel.total_time
|
45
|
-
if total_time == 0
|
46
|
-
total_time = 0.01
|
47
|
-
end
|
48
|
-
|
49
|
-
methods = methods.sort_by(&sort_method).reverse
|
22
|
+
#def print_threads
|
23
|
+
# @result.threads.each do |thread|
|
24
|
+
# print_thread(thread)
|
25
|
+
# @output << "\n" * 2
|
26
|
+
# end
|
27
|
+
#end
|
50
28
|
|
51
|
-
|
52
|
-
@output << "
|
29
|
+
def print_header(thread)
|
30
|
+
@output << "Thread ID: %d\n" % thread.id
|
31
|
+
@output << "Total: %0.6f\n" % thread.top_method.total_time
|
32
|
+
@output << "Sort by: #{sort_method}\n"
|
53
33
|
@output << "\n"
|
54
|
-
@output << " %self total self wait child calls
|
34
|
+
@output << " %self total self wait child calls name\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_methods(thread)
|
38
|
+
total_time = thread.top_method.total_time
|
39
|
+
methods = thread.methods.sort_by(&sort_method).reverse
|
55
40
|
|
56
41
|
sum = 0
|
57
42
|
methods.each do |method|
|
@@ -62,16 +47,22 @@ module RubyProf
|
|
62
47
|
#self_time_called = method.called > 0 ? method.self_time/method.called : 0
|
63
48
|
#total_time_called = method.called > 0? method.total_time/method.called : 0
|
64
49
|
|
65
|
-
@output << "%6.2f %8.2f %8.2f %8.2f %8.2f %8d %s\n" % [
|
50
|
+
@output << "%6.2f %8.2f %8.2f %8.2f %8.2f %8d %s%s \n" % [
|
66
51
|
method.self_time / total_time * 100, # %self
|
67
52
|
method.total_time, # total
|
68
53
|
method.self_time, # self
|
69
54
|
method.wait_time, # wait
|
70
55
|
method.children_time, # children
|
71
56
|
method.called, # calls
|
57
|
+
method.recursive? ? "*" : " ", # cycle
|
72
58
|
method_name(method) # name
|
73
59
|
]
|
74
60
|
end
|
75
61
|
end
|
62
|
+
|
63
|
+
def print_footer(thread)
|
64
|
+
@output << "\n"
|
65
|
+
@output << "* in front of method name means it is recursively called\n"
|
66
|
+
end
|
76
67
|
end
|
77
68
|
end
|