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.
Files changed (79) hide show
  1. data/CHANGES +20 -5
  2. data/README.rdoc +10 -3
  3. data/ext/ruby_prof/rp_call_info.c +108 -79
  4. data/ext/ruby_prof/rp_call_info.h +1 -0
  5. data/ext/ruby_prof/rp_measure_cpu_time.c +111 -111
  6. data/ext/ruby_prof/rp_measure_gc_runs.c +1 -1
  7. data/ext/ruby_prof/rp_measure_memory.c +1 -1
  8. data/ext/ruby_prof/rp_measure_process_time.c +71 -71
  9. data/ext/ruby_prof/rp_measure_wall_time.c +1 -1
  10. data/ext/ruby_prof/rp_method.c +143 -73
  11. data/ext/ruby_prof/rp_method.h +7 -4
  12. data/ext/ruby_prof/rp_stack.c +16 -1
  13. data/ext/ruby_prof/rp_stack.h +4 -1
  14. data/ext/ruby_prof/rp_thread.c +165 -35
  15. data/ext/ruby_prof/rp_thread.h +8 -2
  16. data/ext/ruby_prof/ruby_prof.c +164 -171
  17. data/ext/ruby_prof/ruby_prof.h +53 -54
  18. data/ext/ruby_prof/vc/ruby_prof.sln +26 -0
  19. data/ext/ruby_prof/vc/ruby_prof.vcxproj +109 -0
  20. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +105 -0
  21. data/lib/1.8/ruby_prof.so +0 -0
  22. data/lib/1.9/ruby_prof.so +0 -0
  23. data/lib/ruby-prof/aggregate_call_info.rb +9 -7
  24. data/lib/ruby-prof/call_info.rb +2 -27
  25. data/lib/ruby-prof/call_info_visitor.rb +42 -0
  26. data/lib/ruby-prof/{empty.png → images/empty.png} +0 -0
  27. data/lib/ruby-prof/{minus.png → images/minus.png} +0 -0
  28. data/lib/ruby-prof/{plus.png → images/plus.png} +0 -0
  29. data/lib/ruby-prof/method_info.rb +13 -15
  30. data/lib/ruby-prof/{abstract_printer.rb → printers/abstract_printer.rb} +36 -2
  31. data/lib/ruby-prof/printers/call_info_printer.rb +40 -0
  32. data/lib/ruby-prof/{call_stack_printer.rb → printers/call_stack_printer.rb} +11 -16
  33. data/lib/ruby-prof/{call_tree_printer.rb → printers/call_tree_printer.rb} +4 -4
  34. data/lib/ruby-prof/{dot_printer.rb → printers/dot_printer.rb} +11 -31
  35. data/lib/ruby-prof/{flat_printer.rb → printers/flat_printer.rb} +26 -35
  36. data/lib/ruby-prof/{flat_printer_with_line_numbers.rb → printers/flat_printer_with_line_numbers.rb} +14 -25
  37. data/lib/ruby-prof/printers/graph_html_printer.rb +248 -0
  38. data/lib/ruby-prof/{graph_printer.rb → printers/graph_printer.rb} +31 -73
  39. data/lib/ruby-prof/{multi_printer.rb → printers/multi_printer.rb} +0 -0
  40. data/lib/ruby-prof/profile.rb +27 -22
  41. data/lib/ruby-prof/rack.rb +22 -12
  42. data/ruby-prof.gemspec +58 -0
  43. data/test/aggregate_test.rb +6 -6
  44. data/test/call_info_visitor_test.rb +31 -0
  45. data/test/duplicate_names_test.rb +1 -1
  46. data/test/dynamic_method_test.rb +1 -1
  47. data/test/enumerable_test.rb +1 -1
  48. data/test/exclude_threads_test.rb +2 -2
  49. data/test/gc_test.rb +35 -0
  50. data/test/line_number_test.rb +2 -2
  51. data/test/measure_cpu_time_test.rb +5 -5
  52. data/test/measure_process_time_test.rb +5 -5
  53. data/test/measure_wall_time_test.rb +5 -5
  54. data/test/method_elimination_test.rb +3 -3
  55. data/test/module_test.rb +1 -1
  56. data/test/no_method_class_test.rb +1 -1
  57. data/test/printers_test.rb +16 -8
  58. data/test/recursive_test.rb +115 -91
  59. data/test/stack_test.rb +1 -1
  60. data/test/start_stop_test.rb +13 -13
  61. data/test/summarize_test.rb +48 -0
  62. data/test/test_suite.rb +1 -0
  63. data/test/thread_test.rb +16 -12
  64. data/test/unique_call_path_test.rb +10 -10
  65. metadata +65 -85
  66. data/lib/1.9/ruby_prof.exp +0 -0
  67. data/lib/1.9/ruby_prof.ilk +0 -0
  68. data/lib/1.9/ruby_prof.lib +0 -0
  69. data/lib/1.9/ruby_prof.pdb +0 -0
  70. data/lib/ruby-prof.rb +0 -70
  71. data/lib/ruby-prof/graph_html_printer.rb +0 -286
  72. data/lib/ruby-prof/symbol_to_proc.rb +0 -10
  73. data/lib/ruby_prof.exp +0 -0
  74. data/lib/ruby_prof.ilk +0 -0
  75. data/lib/ruby_prof.lib +0 -0
  76. data/lib/ruby_prof.pdb +0 -0
  77. data/lib/ruby_prof.so +0 -0
  78. data/lib/unprof.rb +0 -10
  79. 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 if call_info.minimal?
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 if call_info.minimal?
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.keys.sort.each do |thread_id|
57
- @current_thread_id = thread_id
58
- @overall_time = @threads_totals[thread_id]
59
- @output.print "<div class=\"thread\">Thread: #{thread_id} (#{"%4.2f%%" % ((@overall_time/@overall_threads_time)*100)} ~ #{@overall_time})</div>"
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
- @result.threads[thread_id].each do |m|
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, @threads_totals[thread_id]
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 |thread_id, methods|
58
- print_methods(thread_id, methods)
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 print_methods(thread_id, methods)
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
- # sort assumes that spawned threads have higher object_ids
86
- @result.threads.sort.each do |thread_id, methods|
87
- puts "subgraph \"Thread #{thread_id}\" {"
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(thread_id, methods)
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 print_methods(thread_id, methods)
102
- total_time = thread_times[thread_id]
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(thread_id, methods)
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
- # Print a flat profile report to the provided output.
16
- #
17
- # output - Any IO object, including STDOUT or a file.
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
- @result.threads.each do |thread_id, methods|
36
- print_methods(thread_id, methods)
37
- @output << "\n" * 2
38
- end
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
- @output << "Thread ID: %d\n" % thread_id
52
- @output << "Total: %0.6f\n" % total_time
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 name\n"
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