ruby-prof 0.18.0 → 1.2.0

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +44 -1
  3. data/LICENSE +2 -2
  4. data/README.rdoc +1 -483
  5. data/Rakefile +3 -6
  6. data/bin/ruby-prof +111 -128
  7. data/ext/ruby_prof/extconf.rb +6 -38
  8. data/ext/ruby_prof/rp_aggregate_call_tree.c +41 -0
  9. data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
  10. data/ext/ruby_prof/rp_allocation.c +259 -0
  11. data/ext/ruby_prof/rp_allocation.h +31 -0
  12. data/ext/ruby_prof/rp_call_tree.c +353 -0
  13. data/ext/ruby_prof/rp_call_tree.h +43 -0
  14. data/ext/ruby_prof/rp_call_trees.c +266 -0
  15. data/ext/ruby_prof/rp_call_trees.h +29 -0
  16. data/ext/ruby_prof/rp_measure_allocations.c +25 -51
  17. data/ext/ruby_prof/rp_measure_memory.c +21 -56
  18. data/ext/ruby_prof/rp_measure_process_time.c +37 -43
  19. data/ext/ruby_prof/rp_measure_wall_time.c +40 -21
  20. data/ext/ruby_prof/rp_measurement.c +221 -0
  21. data/ext/ruby_prof/rp_measurement.h +50 -0
  22. data/ext/ruby_prof/rp_method.c +279 -439
  23. data/ext/ruby_prof/rp_method.h +33 -45
  24. data/ext/ruby_prof/rp_profile.c +902 -0
  25. data/ext/ruby_prof/rp_profile.h +36 -0
  26. data/ext/ruby_prof/rp_stack.c +163 -132
  27. data/ext/ruby_prof/rp_stack.h +18 -28
  28. data/ext/ruby_prof/rp_thread.c +192 -124
  29. data/ext/ruby_prof/rp_thread.h +18 -8
  30. data/ext/ruby_prof/ruby_prof.c +36 -778
  31. data/ext/ruby_prof/ruby_prof.h +11 -45
  32. data/ext/ruby_prof/vc/ruby_prof.vcxproj +18 -12
  33. data/lib/ruby-prof.rb +4 -21
  34. data/lib/ruby-prof/assets/call_stack_printer.html.erb +710 -0
  35. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  36. data/lib/ruby-prof/assets/graph_printer.html.erb +355 -0
  37. data/lib/ruby-prof/call_tree.rb +57 -0
  38. data/lib/ruby-prof/call_tree_visitor.rb +36 -0
  39. data/lib/ruby-prof/compatibility.rb +37 -107
  40. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  41. data/lib/ruby-prof/measurement.rb +17 -0
  42. data/lib/ruby-prof/method_info.rb +47 -90
  43. data/lib/ruby-prof/printers/abstract_printer.rb +73 -50
  44. data/lib/ruby-prof/printers/call_info_printer.rb +24 -12
  45. data/lib/ruby-prof/printers/call_stack_printer.rb +66 -152
  46. data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
  47. data/lib/ruby-prof/printers/dot_printer.rb +5 -5
  48. data/lib/ruby-prof/printers/flat_printer.rb +6 -24
  49. data/lib/ruby-prof/printers/graph_html_printer.rb +6 -192
  50. data/lib/ruby-prof/printers/graph_printer.rb +11 -14
  51. data/lib/ruby-prof/printers/multi_printer.rb +66 -23
  52. data/lib/ruby-prof/profile.rb +10 -3
  53. data/lib/ruby-prof/thread.rb +5 -20
  54. data/lib/ruby-prof/version.rb +1 -1
  55. data/ruby-prof.gemspec +9 -2
  56. data/test/abstract_printer_test.rb +0 -27
  57. data/test/alias_test.rb +126 -0
  58. data/test/basic_test.rb +1 -86
  59. data/test/call_tree_visitor_test.rb +32 -0
  60. data/test/call_trees_test.rb +66 -0
  61. data/test/dynamic_method_test.rb +0 -2
  62. data/test/exclude_methods_test.rb +17 -12
  63. data/test/fiber_test.rb +214 -23
  64. data/test/gc_test.rb +105 -0
  65. data/test/inverse_call_tree_test.rb +175 -0
  66. data/test/line_number_test.rb +118 -40
  67. data/test/marshal_test.rb +115 -0
  68. data/test/measure_allocations.rb +30 -0
  69. data/test/measure_allocations_test.rb +361 -12
  70. data/test/measure_allocations_trace_test.rb +375 -0
  71. data/test/measure_memory_trace_test.rb +1101 -0
  72. data/test/measure_process_time_test.rb +757 -33
  73. data/test/measure_times.rb +56 -0
  74. data/test/measure_wall_time_test.rb +329 -149
  75. data/test/multi_printer_test.rb +1 -34
  76. data/test/pause_resume_test.rb +24 -15
  77. data/test/prime.rb +1 -1
  78. data/test/prime_script.rb +6 -0
  79. data/test/printer_call_stack_test.rb +28 -0
  80. data/test/printer_call_tree_test.rb +31 -0
  81. data/test/printer_flat_test.rb +68 -0
  82. data/test/printer_graph_html_test.rb +60 -0
  83. data/test/printer_graph_test.rb +41 -0
  84. data/test/printers_test.rb +32 -166
  85. data/test/printing_recursive_graph_test.rb +26 -72
  86. data/test/recursive_test.rb +68 -77
  87. data/test/stack_printer_test.rb +2 -15
  88. data/test/start_stop_test.rb +22 -25
  89. data/test/test_helper.rb +6 -261
  90. data/test/thread_test.rb +11 -54
  91. data/test/unique_call_path_test.rb +25 -107
  92. data/test/yarv_test.rb +1 -0
  93. metadata +43 -41
  94. data/examples/flat.txt +0 -50
  95. data/examples/graph.dot +0 -84
  96. data/examples/graph.html +0 -823
  97. data/examples/graph.txt +0 -139
  98. data/examples/multi.flat.txt +0 -23
  99. data/examples/multi.graph.html +0 -760
  100. data/examples/multi.grind.dat +0 -114
  101. data/examples/multi.stack.html +0 -547
  102. data/examples/stack.html +0 -547
  103. data/ext/ruby_prof/rp_call_info.c +0 -425
  104. data/ext/ruby_prof/rp_call_info.h +0 -53
  105. data/ext/ruby_prof/rp_measure.c +0 -40
  106. data/ext/ruby_prof/rp_measure.h +0 -45
  107. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  108. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  109. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  110. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  111. data/lib/ruby-prof/assets/call_stack_printer.css.html +0 -117
  112. data/lib/ruby-prof/assets/call_stack_printer.js.html +0 -385
  113. data/lib/ruby-prof/call_info.rb +0 -115
  114. data/lib/ruby-prof/call_info_visitor.rb +0 -40
  115. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
  116. data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
  117. data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
  118. data/test/aggregate_test.rb +0 -136
  119. data/test/block_test.rb +0 -74
  120. data/test/call_info_test.rb +0 -78
  121. data/test/call_info_visitor_test.rb +0 -31
  122. data/test/issue137_test.rb +0 -63
  123. data/test/measure_cpu_time_test.rb +0 -212
  124. data/test/measure_gc_runs_test.rb +0 -32
  125. data/test/measure_gc_time_test.rb +0 -36
  126. data/test/measure_memory_test.rb +0 -33
  127. data/test/method_elimination_test.rb +0 -84
  128. data/test/module_test.rb +0 -45
  129. data/test/stack_test.rb +0 -138
@@ -1,7 +1,14 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module RubyProf
4
+ # This is the base class for all Printers. It is never used directly.
4
5
  class AbstractPrinter
6
+ # :stopdoc:
7
+ def self.needs_dir?
8
+ false
9
+ end
10
+ # :startdoc:
11
+
5
12
  # Create a new printer.
6
13
  #
7
14
  # result should be the output generated from a profiling run
@@ -10,72 +17,63 @@ module RubyProf
10
17
  @output = nil
11
18
  end
12
19
 
13
- # Specify print options.
20
+ # Returns the min_percent of total time a method must take to be included in a profiling report
21
+ def min_percent
22
+ @options[:min_percent] || 0
23
+ end
24
+
25
+ # Returns the time format used to show when a profile was run
26
+ def time_format
27
+ '%A, %B %-d at %l:%M:%S %p (%Z)'
28
+ end
29
+
30
+ # Returns how profile data should be sorted
31
+ def sort_method
32
+ @options[:sort_method]
33
+ end
34
+
35
+ # Prints a report to the provided output.
36
+ #
37
+ # output - Any IO object, including STDOUT or a file.
38
+ # The default value is STDOUT.
39
+ #
40
+ # options - Hash of print options. Note that each printer can
41
+ # define its own set of options.
14
42
  #
15
- # options - Hash table
16
43
  # :min_percent - Number 0 to 100 that specifes the minimum
17
44
  # %self (the methods self time divided by the
18
45
  # overall total time) that a method must take
19
46
  # for it to be printed out in the report.
20
47
  # Default value is 0.
21
48
  #
22
- # :print_file - True or false. Specifies if a method's source
23
- # file should be printed. Default value if false.
24
- #
25
49
  # :sort_method - Specifies method used for sorting method infos.
26
50
  # Available values are :total_time, :self_time,
27
51
  # :wait_time, :children_time
28
52
  # Default value is :total_time
29
- # :editor_uri - Specifies editor uri scheme used for opening files
30
- # e.g. :atm or :mvim. For OS X default is :txmt.
31
- # Pass false to print bare filenames.
32
- # Use RUBY_PROF_EDITOR_URI environment variable to override.
33
- def setup_options(options = {})
34
- @options = options
35
- end
36
-
37
- def min_percent
38
- @options[:min_percent] || 0
39
- end
40
-
41
- def print_file
42
- @options[:print_file] || false
53
+ def print(output = STDOUT, options = {})
54
+ @output = output
55
+ setup_options(options)
56
+ print_threads
43
57
  end
44
58
 
45
- def sort_method
46
- @options[:sort_method] || :total_time
59
+ # :nodoc:
60
+ def setup_options(options = {})
61
+ @options = options
47
62
  end
48
63
 
49
- def editor_uri
50
- if ENV.key?('RUBY_PROF_EDITOR_URI')
51
- ENV['RUBY_PROF_EDITOR_URI'] || false
52
- elsif @options.key?(:editor_uri)
53
- @options[:editor_uri]
54
- else
55
- RUBY_PLATFORM =~ /darwin/ ? 'txmt' : false
64
+ def method_location(method)
65
+ if method.source_file
66
+ "#{method.source_file}:#{method.line}"
56
67
  end
57
68
  end
58
69
 
59
- def method_name(method)
60
- name = method.full_name
61
- if print_file
62
- name += " (#{method.source_file}:#{method.line}}"
63
- end
64
- name
70
+ def method_href(thread, method)
71
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
65
72
  end
66
73
 
67
- # Print a profiling report to the provided output.
68
- #
69
- # output - Any IO object, including STDOUT or a file.
70
- # The default value is STDOUT.
71
- #
72
- # options - Hash of print options. See #setup_options
73
- # for more information. Note that each printer can
74
- # define its own set of options.
75
- def print(output = STDOUT, options = {})
76
- @output = output
77
- setup_options(options)
78
- print_threads
74
+ def open_asset(file)
75
+ path = File.join(File.expand_path('../../assets', __FILE__), file)
76
+ File.open(path, 'rb').read
79
77
  end
80
78
 
81
79
  def print_threads
@@ -91,14 +89,39 @@ module RubyProf
91
89
  end
92
90
 
93
91
  def print_header(thread)
92
+ @output << "Measure Mode: %s\n" % RubyProf.measure_mode_string
93
+ @output << "Thread ID: %d\n" % thread.id
94
+ @output << "Fiber ID: %d\n" % thread.fiber_id unless thread.id == thread.fiber_id
95
+ @output << "Total: %0.6f\n" % thread.total_time
96
+ @output << "Sort by: #{sort_method}\n"
97
+ @output << "\n"
98
+ print_column_headers
94
99
  end
95
100
 
96
- def print_footer(thread)
101
+ def print_column_headers
97
102
  end
98
103
 
99
- # whether this printer need a :path option pointing to a directory
100
- def self.needs_dir?
101
- false
104
+ def print_footer(thread)
105
+ @output << <<~EOT
106
+
107
+ * recursively called methods
108
+
109
+ Columns are:
110
+
111
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
112
+ total - The time spent in this method and its children.
113
+ self - The time spent in this method.
114
+ wait - The amount of time this method waited for other threads.
115
+ child - The time spent in this method's children.
116
+ calls - The number of times this method was called.
117
+ name - The name of the method.
118
+ location - The location of the method.
119
+
120
+ The interpretation of method names is:
121
+
122
+ * MyObject#test - An instance method "test" of the class "MyObject"
123
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
124
+ EOT
102
125
  end
103
126
  end
104
127
  end
@@ -1,16 +1,25 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module RubyProf
4
- # Prints out the call graph based on CallInfo instances. This
4
+ # Prints out the call graph based on CallTree instances. This
5
5
  # is mainly for debugging purposes as it provides access into
6
6
  # into RubyProf's internals.
7
-
7
+ #
8
+ # To use the printer:
9
+ #
10
+ # result = RubyProf.profile do
11
+ # [code to profile]
12
+ # end
13
+ #
14
+ # printer = RubyProf::CallInfoPrinter.new(result)
15
+ # printer.print(STDOUT)
8
16
  class CallInfoPrinter < AbstractPrinter
9
17
  TIME_WIDTH = 0
10
18
 
11
19
  private
12
20
 
13
21
  def print_header(thread)
22
+ @output << "----------------------------------------------------\n"
14
23
  @output << "Thread ID: #{thread.id}\n"
15
24
  @output << "Fiber ID: #{thread.fiber_id}\n"
16
25
  @output << "Total Time: #{thread.total_time}\n"
@@ -19,23 +28,26 @@ module RubyProf
19
28
  end
20
29
 
21
30
  def print_methods(thread)
22
- visitor = CallInfoVisitor.new(thread.top_call_infos)
31
+ visitor = CallTreeVisitor.new(thread.call_tree)
23
32
 
24
- visitor.visit do |call_info, event|
33
+ visitor.visit do |call_tree, event|
25
34
  if event == :enter
26
- @output << " " * call_info.depth
27
- @output << call_info.target.full_name
35
+ @output << " " * call_tree.depth
36
+ @output << call_tree.target.full_name
28
37
  @output << " ("
29
- @output << "tt:#{sprintf("%#{TIME_WIDTH}.2f", call_info.total_time)}, "
30
- @output << "st:#{sprintf("%#{TIME_WIDTH}.2f", call_info.self_time)}, "
31
- @output << "wt:#{sprintf("%#{TIME_WIDTH}.2f", call_info.wait_time)}, "
32
- @output << "ct:#{sprintf("%#{TIME_WIDTH}.2f", call_info.children_time)}, "
33
- @output << "call:#{call_info.called}, "
34
- @output << "rec:#{call_info.recursive?}"
38
+ @output << "tt:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.total_time)}, "
39
+ @output << "st:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.self_time)}, "
40
+ @output << "wt:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.wait_time)}, "
41
+ @output << "ct:#{sprintf("%#{TIME_WIDTH}.2f", call_tree.children_time)}, "
42
+ @output << "call:#{call_tree.called}, "
35
43
  @output << ")"
36
44
  @output << "\n"
37
45
  end
38
46
  end
39
47
  end
48
+
49
+ def print_footer(thread)
50
+ @output << "\n" << "\n"
51
+ end
40
52
  end
41
53
  end
@@ -3,9 +3,20 @@
3
3
  require 'erb'
4
4
  require 'fileutils'
5
5
  require 'base64'
6
+ require 'set'
6
7
 
7
8
  module RubyProf
8
- # prints a HTML visualization of the call tree
9
+ # Prints a HTML visualization of the call tree.
10
+ #
11
+ # To use the printer:
12
+ #
13
+ # result = RubyProf.profile do
14
+ # [code to profile]
15
+ # end
16
+ #
17
+ # printer = RubyProf::CallStackPrinter.new(result)
18
+ # printer.print(STDOUT)
19
+
9
20
  class CallStackPrinter < AbstractPrinter
10
21
  include ERB::Util
11
22
 
@@ -18,9 +29,6 @@ module RubyProf
18
29
  # for it to be printed out in the report.
19
30
  # Default value is 0.
20
31
  #
21
- # :print_file - True or false. Specifies if a method's source
22
- # file should be printed. Default value if false.
23
- #
24
32
  # :threshold - a float from 0 to 100 that sets the threshold of
25
33
  # results displayed.
26
34
  # Default value is 1.0
@@ -35,114 +43,85 @@ module RubyProf
35
43
  #
36
44
  # :application - a String to overide the name of the application,
37
45
  # as it appears on the report.
38
- #
39
- # :editor_uri - Specifies editor uri scheme used for opening files
40
- # e.g. :atm or :mvim. For OS X default is :txmt.
41
- # Use RUBY_PROF_EDITOR_URI environment variable to overide.
42
46
  def print(output = STDOUT, options = {})
43
- @output = output
44
47
  setup_options(options)
45
- @editor = editor_uri
46
- if @graph_html = options.delete(:graph)
47
- @graph_html = "file://" + @graph_html if @graph_html[0]=="/"
48
- end
49
-
50
- print_header
51
-
52
- @overall_threads_time = @result.threads.inject(0) do |val, thread|
53
- val += thread.total_time
54
- end
55
-
56
- @result.threads.each do |thread|
57
- @current_thread_id = thread.fiber_id
58
- @overall_time = thread.total_time
59
- thread_info = String.new("Thread: #{thread.id}")
60
- thread_info << ", Fiber: #{thread.fiber_id}" unless thread.id == thread.fiber_id
61
- thread_info << " (#{"%4.2f%%" % ((@overall_time/@overall_threads_time)*100)} ~ #{@overall_time})"
62
- @output.print "<div class=\"thread\">#{thread_info}</div>"
63
- @output.print "<ul name=\"thread\">"
64
- thread.methods.each do |m|
65
- # $stderr.print m.dump
66
- next unless m.root?
67
- m.call_infos.each do |ci|
68
- next unless ci.root?
69
- print_stack ci, thread.total_time
70
- end
71
- end
72
- @output.print "</ul>"
73
- end
74
-
75
- print_footer
48
+ output << @erb.result(binding)
49
+ end
76
50
 
51
+ # :enddoc:
52
+ def setup_options(options)
53
+ super(options)
54
+ @erb = ERB.new(self.template)
77
55
  end
78
56
 
79
- def print_stack(call_info, parent_time)
80
- total_time = call_info.total_time
57
+ def print_stack(output, visited, call_tree, parent_time)
58
+ total_time = call_tree.total_time
81
59
  percent_parent = (total_time/parent_time)*100
82
60
  percent_total = (total_time/@overall_time)*100
83
61
  return unless percent_total > min_percent
84
62
  color = self.color(percent_total)
85
- kids = call_info.children
86
63
  visible = percent_total >= threshold
87
64
  expanded = percent_total >= expansion
88
65
  display = visible ? "block" : "none"
89
- @output.print "<li class=\"color#{color}\" style=\"display:#{display}\">"
90
- if kids.empty?
91
- @output.print "<a href=\"#\" class=\"toggle empty\" ></a>"
66
+
67
+ output << "<li class=\"color#{color}\" style=\"display:#{display}\">" << "\n"
68
+
69
+ if visited.include?(call_tree)
70
+ output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
71
+ output << "<span>%s %s</span>" % [link(call_tree.target, true), graph_link(call_tree)] << "\n"
92
72
  else
93
- visible_children = kids.any?{|ci| (ci.total_time/@overall_time)*100 >= threshold}
94
- image = visible_children ? (expanded ? "minus" : "plus") : "empty"
95
- @output.print "<a href=\"#\" class=\"toggle #{image}\" ></a>"
96
- end
97
- @output.printf "<span> %4.2f%% (%4.2f%%) %s %s</span>\n", percent_total, percent_parent, link(call_info), graph_link(call_info)
98
- unless kids.empty?
99
- if expanded
100
- @output.print "<ul>"
73
+ visited << call_tree
74
+
75
+ if call_tree.children.empty?
76
+ output << "<a href=\"#\" class=\"toggle empty\" ></a>" << "\n"
101
77
  else
102
- @output.print '<ul style="display:none">'
78
+ visible_children = call_tree.children.any?{|ci| (ci.total_time/@overall_time)*100 >= threshold}
79
+ image = visible_children ? (expanded ? "minus" : "plus") : "empty"
80
+ output << "<a href=\"#\" class=\"toggle #{image}\" ></a>" << "\n"
103
81
  end
104
- kids.sort_by{|c| -c.total_time}.each do |callinfo|
105
- print_stack callinfo, total_time
82
+ output << "<span>%4.2f%% (%4.2f%%) %s %s</span>" % [percent_total, percent_parent,
83
+ link(call_tree.target, false), graph_link(call_tree)] << "\n"
84
+
85
+ unless call_tree.children.empty?
86
+ output << (expanded ? '<ul>' : '<ul style="display:none">') << "\n"
87
+ call_tree.children.sort_by{|c| -c.total_time}.each do |child_call_tree|
88
+ print_stack(output, visited, child_call_tree, total_time)
89
+ end
90
+ output << '</ul>' << "\n"
106
91
  end
107
- @output.print "</ul>"
92
+
93
+ visited.delete(call_tree)
108
94
  end
109
- @output.print "</li>"
95
+ output << '</li>' << "\n"
110
96
  end
111
97
 
112
- def name(call_info)
113
- method = call_info.target
98
+ def name(call_tree)
99
+ method = call_tree.target
114
100
  method.full_name
115
101
  end
116
102
 
117
- def link(call_info)
118
- method = call_info.target
119
- file = File.expand_path(method.source_file)
120
- if file =~ /\/ruby_runtime$/
121
- h(name(call_info))
103
+ def link(method, recursive)
104
+ method_name = "#{recursive ? '*' : ''}#{method.full_name}"
105
+ if method.source_file.nil?
106
+ h method_name
122
107
  else
123
- if @editor
124
- "<a href=\"#{@editor}://" \
125
- "open?url=file://#{file}&line=#{method.line}\">" \
126
- "#{h(name(call_info))}</a>"
127
- else
128
- "<a href=\"file://#{file}##{method.line}\">#{h(name(call_info))}</a>"
129
- end
108
+ file = File.expand_path(method.source_file)
109
+ "<a href=\"file://#{file}##{method.line}\">#{h method_name}</a>"
130
110
  end
131
111
  end
132
112
 
133
- def graph_link(call_info)
134
- total_calls = call_info.target.call_infos.inject(0){|t, ci| t += ci.called}
135
- href = "#{@graph_html}##{method_href(call_info.target)}"
136
- totals = @graph_html ? "<a href='#{href}'>#{total_calls}</a>" : total_calls.to_s
137
- "[#{call_info.called} calls, #{totals} total]"
113
+ def graph_link(call_tree)
114
+ total_calls = call_tree.target.called
115
+ totals = total_calls.to_s
116
+ "[#{call_tree.called} calls, #{totals} total]"
138
117
  end
139
118
 
140
119
  def method_href(method)
141
- h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + @current_thread_id.to_s)
120
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_"))
142
121
  end
143
122
 
144
- def total_time(call_infos)
145
- sum(call_infos.map{|ci| ci.total_time})
123
+ def total_time(call_trees)
124
+ sum(call_trees.map{|ci| ci.total_time})
146
125
  end
147
126
 
148
127
  def sum(a)
@@ -186,80 +165,15 @@ module RubyProf
186
165
  @options[:expansion] || 10.0
187
166
  end
188
167
 
189
- def print_header
190
- @output.puts "<html><head>"
191
- @output.puts '<meta http-equiv="content-type" content="text/html; charset=utf-8">'
192
- @output.puts "<title>#{h title}</title>"
193
- print_css
194
- print_java_script
195
- @output.puts '</head><body><div style="display: inline-block;">'
196
- print_title_bar
197
- print_commands
198
- print_help
199
- end
200
-
201
- def print_footer
202
- @output.puts '<div id="sentinel"></div></div></body></html>'
203
- end
204
-
205
- def open_asset(file)
206
- path = File.join(File.expand_path('../../assets', __FILE__), file)
207
- File.open(path, 'rb').read
208
- end
209
-
210
- def print_css
211
- html = open_asset('call_stack_printer.css.html')
212
- @output.puts html.gsub('%s', base64_image)
213
- end
214
-
215
168
  def base64_image
216
- file = open_asset('call_stack_printer.png')
217
- Base64.encode64(file).gsub(/\n/, '')
218
- end
219
-
220
- def print_java_script
221
- html = open_asset('call_stack_printer.js.html')
222
- @output.puts html
223
- end
224
-
225
- def print_title_bar
226
- @output.puts <<-"end_title_bar"
227
- <div id="titlebar">
228
- Call tree for application <b>#{h application} #{h arguments}</b><br/>
229
- Generated on #{Time.now} with options #{h @options.inspect}<br/>
230
- </div>
231
- end_title_bar
232
- end
233
-
234
- def print_commands
235
- @output.puts <<-"end_commands"
236
- <div id=\"commands\">
237
- <span style=\"font-size: 11pt; font-weight: bold;\">Threshold:</span>
238
- <input value=\"#{h threshold}\" size=\"3\" id=\"threshold\" type=\"text\">
239
- <input value=\"Apply\" onclick=\"setThreshold();\" type=\"submit\">
240
- <input value=\"Expand All\" onclick=\"expandAll(event);\" type=\"submit\">
241
- <input value=\"Collapse All\" onclick=\"collapseAll(event);\" type=\"submit\">
242
- <input value=\"Show Help\" onclick=\"toggleHelp(this);\" type=\"submit\">
243
- </div>
244
- end_commands
169
+ @data ||= begin
170
+ file = open_asset('call_stack_printer.png')
171
+ Base64.encode64(file).gsub(/\n/, '')
172
+ end
245
173
  end
246
174
 
247
- def print_help
248
- @output.puts <<-'end_help'
249
- <div style="display: none;" id="help">
250
- &#8226; Enter a decimal value <i>d</i> into the threshold field and click "Apply"
251
- to hide all nodes marked with time values lower than <i>d</i>.<br>
252
- &#8226; Click on "Expand All" for full tree expansion.<br>
253
- &#8226; Click on "Collapse All" to show only top level nodes.<br>
254
- &#8226; Use a, s, d, w as in Quake or Urban Terror to navigate the tree.<br>
255
- &#8226; Use f and b to navigate the tree in preorder forward and backwards.<br>
256
- &#8226; Use x to toggle visibility of a subtree.<br>
257
- &#8226; Use * to expand/collapse a whole subtree.<br>
258
- &#8226; Use h to navigate to thread root.<br>
259
- &#8226; Use n and p to navigate between threads.<br>
260
- &#8226; Click on background to move focus to a subtree.<br>
261
- </div>
262
- end_help
175
+ def template
176
+ open_asset('call_stack_printer.html.erb')
263
177
  end
264
178
  end
265
179
  end