ruby-prof 0.16.2 → 1.1.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 (203) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +532 -467
  3. data/LICENSE +24 -24
  4. data/README.rdoc +5 -454
  5. data/Rakefile +110 -113
  6. data/bin/ruby-prof +380 -340
  7. data/bin/ruby-prof-check-trace +45 -45
  8. data/ext/ruby_prof/extconf.rb +36 -64
  9. data/ext/ruby_prof/rp_allocation.c +279 -0
  10. data/ext/ruby_prof/rp_allocation.h +31 -0
  11. data/ext/ruby_prof/rp_call_info.c +271 -407
  12. data/ext/ruby_prof/rp_call_info.h +35 -48
  13. data/ext/ruby_prof/rp_measure_allocations.c +52 -76
  14. data/ext/ruby_prof/rp_measure_memory.c +42 -77
  15. data/ext/ruby_prof/rp_measure_process_time.c +67 -71
  16. data/ext/ruby_prof/rp_measure_wall_time.c +62 -45
  17. data/ext/ruby_prof/rp_measurement.c +230 -0
  18. data/ext/ruby_prof/rp_measurement.h +50 -0
  19. data/ext/ruby_prof/rp_method.c +630 -411
  20. data/ext/ruby_prof/rp_method.h +70 -52
  21. data/ext/ruby_prof/rp_profile.c +895 -0
  22. data/ext/ruby_prof/rp_profile.h +37 -0
  23. data/ext/ruby_prof/rp_stack.c +196 -128
  24. data/ext/ruby_prof/rp_stack.h +56 -51
  25. data/ext/ruby_prof/rp_thread.c +337 -273
  26. data/ext/ruby_prof/rp_thread.h +36 -27
  27. data/ext/ruby_prof/ruby_prof.c +48 -671
  28. data/ext/ruby_prof/ruby_prof.h +17 -56
  29. data/ext/ruby_prof/vc/ruby_prof.sln +20 -21
  30. data/ext/ruby_prof/vc/{ruby_prof_20.vcxproj → ruby_prof.vcxproj} +38 -5
  31. data/lib/ruby-prof.rb +52 -58
  32. data/lib/ruby-prof/assets/call_stack_printer.html.erb +713 -0
  33. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  34. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  35. data/lib/ruby-prof/call_info.rb +57 -126
  36. data/lib/ruby-prof/call_info_visitor.rb +38 -40
  37. data/lib/ruby-prof/compatibility.rb +109 -178
  38. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  39. data/lib/ruby-prof/measurement.rb +14 -0
  40. data/lib/ruby-prof/method_info.rb +90 -129
  41. data/lib/ruby-prof/printers/abstract_printer.rb +127 -85
  42. data/lib/ruby-prof/printers/call_info_printer.rb +51 -41
  43. data/lib/ruby-prof/printers/call_stack_printer.rb +182 -260
  44. data/lib/ruby-prof/printers/call_tree_printer.rb +151 -130
  45. data/lib/ruby-prof/printers/dot_printer.rb +132 -132
  46. data/lib/ruby-prof/printers/flat_printer.rb +52 -70
  47. data/lib/ruby-prof/printers/graph_html_printer.rb +63 -244
  48. data/lib/ruby-prof/printers/graph_printer.rb +114 -116
  49. data/lib/ruby-prof/printers/multi_printer.rb +127 -58
  50. data/lib/ruby-prof/profile.rb +33 -55
  51. data/lib/ruby-prof/rack.rb +171 -95
  52. data/lib/ruby-prof/task.rb +147 -147
  53. data/lib/ruby-prof/thread.rb +35 -41
  54. data/lib/ruby-prof/version.rb +3 -3
  55. data/lib/unprof.rb +10 -10
  56. data/ruby-prof.gemspec +58 -57
  57. data/test/abstract_printer_test.rb +26 -0
  58. data/test/alias_test.rb +129 -0
  59. data/test/basic_test.rb +129 -128
  60. data/test/call_info_visitor_test.rb +31 -31
  61. data/test/duplicate_names_test.rb +32 -32
  62. data/test/dynamic_method_test.rb +53 -55
  63. data/test/enumerable_test.rb +21 -21
  64. data/test/exceptions_test.rb +24 -16
  65. data/test/exclude_methods_test.rb +146 -0
  66. data/test/exclude_threads_test.rb +53 -53
  67. data/test/fiber_test.rb +73 -79
  68. data/test/gc_test.rb +96 -0
  69. data/test/line_number_test.rb +161 -71
  70. data/test/marshal_test.rb +119 -0
  71. data/test/measure_allocations.rb +30 -0
  72. data/test/measure_allocations_test.rb +385 -26
  73. data/test/measure_allocations_trace_test.rb +385 -0
  74. data/test/measure_memory_trace_test.rb +756 -0
  75. data/test/measure_process_time_test.rb +849 -63
  76. data/test/measure_times.rb +54 -0
  77. data/test/measure_wall_time_test.rb +459 -255
  78. data/test/multi_printer_test.rb +71 -83
  79. data/test/no_method_class_test.rb +15 -15
  80. data/test/parser_timings.rb +24 -0
  81. data/test/pause_resume_test.rb +166 -166
  82. data/test/prime.rb +56 -54
  83. data/test/printer_call_stack_test.rb +28 -0
  84. data/test/printer_call_tree_test.rb +31 -0
  85. data/test/printer_flat_test.rb +68 -0
  86. data/test/printer_graph_html_test.rb +60 -0
  87. data/test/printer_graph_test.rb +41 -0
  88. data/test/printers_test.rb +141 -255
  89. data/test/printing_recursive_graph_test.rb +81 -127
  90. data/test/rack_test.rb +157 -93
  91. data/test/recursive_test.rb +210 -215
  92. data/test/singleton_test.rb +38 -38
  93. data/test/stack_printer_test.rb +64 -78
  94. data/test/start_stop_test.rb +109 -112
  95. data/test/test_helper.rb +24 -264
  96. data/test/thread_test.rb +144 -187
  97. data/test/unique_call_path_test.rb +190 -202
  98. data/test/yarv_test.rb +56 -55
  99. metadata +34 -114
  100. data/doc/LICENSE.html +0 -114
  101. data/doc/README_rdoc.html +0 -603
  102. data/doc/Rack.html +0 -95
  103. data/doc/Rack/RubyProf.html +0 -226
  104. data/doc/RubyProf.html +0 -962
  105. data/doc/RubyProf/AbstractPrinter.html +0 -546
  106. data/doc/RubyProf/AggregateCallInfo.html +0 -551
  107. data/doc/RubyProf/CallInfo.html +0 -639
  108. data/doc/RubyProf/CallInfoPrinter.html +0 -120
  109. data/doc/RubyProf/CallInfoVisitor.html +0 -198
  110. data/doc/RubyProf/CallStackPrinter.html +0 -1121
  111. data/doc/RubyProf/CallTreePrinter.html +0 -641
  112. data/doc/RubyProf/Cmd.html +0 -631
  113. data/doc/RubyProf/DotPrinter.html +0 -257
  114. data/doc/RubyProf/FlatPrinter.html +0 -163
  115. data/doc/RubyProf/FlatPrinterWithLineNumbers.html +0 -208
  116. data/doc/RubyProf/GraphHtmlPrinter.html +0 -552
  117. data/doc/RubyProf/GraphPrinter.html +0 -139
  118. data/doc/RubyProf/MethodInfo.html +0 -745
  119. data/doc/RubyProf/MultiPrinter.html +0 -360
  120. data/doc/RubyProf/Profile.html +0 -763
  121. data/doc/RubyProf/ProfileTask.html +0 -490
  122. data/doc/RubyProf/Thread.html +0 -310
  123. data/doc/created.rid +0 -31
  124. data/doc/css/fonts.css +0 -167
  125. data/doc/css/rdoc.css +0 -590
  126. data/doc/examples/flat_txt.html +0 -138
  127. data/doc/examples/graph_html.html +0 -909
  128. data/doc/examples/graph_txt.html +0 -247
  129. data/doc/fonts/Lato-Light.ttf +0 -0
  130. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  131. data/doc/fonts/Lato-Regular.ttf +0 -0
  132. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  133. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  134. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  135. data/doc/images/add.png +0 -0
  136. data/doc/images/arrow_up.png +0 -0
  137. data/doc/images/brick.png +0 -0
  138. data/doc/images/brick_link.png +0 -0
  139. data/doc/images/bug.png +0 -0
  140. data/doc/images/bullet_black.png +0 -0
  141. data/doc/images/bullet_toggle_minus.png +0 -0
  142. data/doc/images/bullet_toggle_plus.png +0 -0
  143. data/doc/images/date.png +0 -0
  144. data/doc/images/delete.png +0 -0
  145. data/doc/images/find.png +0 -0
  146. data/doc/images/loadingAnimation.gif +0 -0
  147. data/doc/images/macFFBgHack.png +0 -0
  148. data/doc/images/package.png +0 -0
  149. data/doc/images/page_green.png +0 -0
  150. data/doc/images/page_white_text.png +0 -0
  151. data/doc/images/page_white_width.png +0 -0
  152. data/doc/images/plugin.png +0 -0
  153. data/doc/images/ruby.png +0 -0
  154. data/doc/images/tag_blue.png +0 -0
  155. data/doc/images/tag_green.png +0 -0
  156. data/doc/images/transparent.png +0 -0
  157. data/doc/images/wrench.png +0 -0
  158. data/doc/images/wrench_orange.png +0 -0
  159. data/doc/images/zoom.png +0 -0
  160. data/doc/index.html +0 -626
  161. data/doc/js/darkfish.js +0 -161
  162. data/doc/js/jquery.js +0 -4
  163. data/doc/js/navigation.js +0 -142
  164. data/doc/js/navigation.js.gz +0 -0
  165. data/doc/js/search.js +0 -109
  166. data/doc/js/search_index.js +0 -1
  167. data/doc/js/search_index.js.gz +0 -0
  168. data/doc/js/searcher.js +0 -228
  169. data/doc/js/searcher.js.gz +0 -0
  170. data/doc/table_of_contents.html +0 -942
  171. data/examples/cachegrind.out.1 +0 -114
  172. data/examples/cachegrind.out.1.32313213 +0 -114
  173. data/examples/flat.txt +0 -50
  174. data/examples/graph.dot +0 -84
  175. data/examples/graph.html +0 -823
  176. data/examples/graph.txt +0 -139
  177. data/examples/multi.flat.txt +0 -23
  178. data/examples/multi.graph.html +0 -760
  179. data/examples/multi.grind.dat +0 -114
  180. data/examples/multi.stack.html +0 -547
  181. data/examples/stack.html +0 -547
  182. data/ext/ruby_prof/rp_measure.c +0 -40
  183. data/ext/ruby_prof/rp_measure.h +0 -45
  184. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  185. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  186. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  187. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +0 -108
  188. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +0 -110
  189. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  190. data/lib/ruby-prof/assets/call_stack_printer.css.html +0 -117
  191. data/lib/ruby-prof/assets/call_stack_printer.js.html +0 -385
  192. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -64
  193. data/test/aggregate_test.rb +0 -136
  194. data/test/block_test.rb +0 -74
  195. data/test/call_info_test.rb +0 -78
  196. data/test/issue137_test.rb +0 -63
  197. data/test/measure_cpu_time_test.rb +0 -213
  198. data/test/measure_gc_runs_test.rb +0 -32
  199. data/test/measure_gc_time_test.rb +0 -36
  200. data/test/measure_memory_test.rb +0 -33
  201. data/test/method_elimination_test.rb +0 -84
  202. data/test/module_test.rb +0 -45
  203. data/test/stack_test.rb +0 -138
@@ -1,132 +1,132 @@
1
- # encoding: utf-8
2
-
3
- require 'set'
4
-
5
- module RubyProf
6
- # Generates a graphviz graph in dot format.
7
- # To use the dot printer:
8
- #
9
- # result = RubyProf.profile do
10
- # [code to profile]
11
- # end
12
- #
13
- # printer = RubyProf::DotPrinter.new(result)
14
- # printer.print(STDOUT)
15
- #
16
- # You can use either dot viewer such as GraphViz, or the dot command line tool
17
- # to reformat the output into a wide variety of outputs:
18
- #
19
- # dot -Tpng graph.dot > graph.png
20
- #
21
- class DotPrinter < RubyProf::AbstractPrinter
22
- CLASS_COLOR = '"#666666"'
23
- EDGE_COLOR = '"#666666"'
24
-
25
- # Creates the DotPrinter using a RubyProf::Proile.
26
- def initialize(result)
27
- super(result)
28
- @seen_methods = Set.new
29
- end
30
-
31
- # Print a graph report to the provided output.
32
- #
33
- # output - Any IO object, including STDOUT or a file. The default value is
34
- # STDOUT.
35
- #
36
- # options - Hash of print options. See #setup_options
37
- # for more information.
38
- #
39
- # When profiling results that cover a large number of method calls it
40
- # helps to use the :min_percent option, for example:
41
- #
42
- # DotPrinter.new(result).print(STDOUT, :min_percent=>5)
43
- #
44
- def print(output = STDOUT, options = {})
45
- @output = output
46
- setup_options(options)
47
-
48
- puts 'digraph "Profile" {'
49
- #puts "label=\"#{mode_name} >=#{min_percent}%\\nTotal: #{total_time}\";"
50
- puts "labelloc=t;"
51
- puts "labeljust=l;"
52
- print_threads
53
- puts '}'
54
- end
55
-
56
- private
57
-
58
- # Something of a hack, figure out which constant went with the
59
- # RubyProf.measure_mode so that we can display it. Otherwise it's easy to
60
- # forget what measurement was made.
61
- def mode_name
62
- RubyProf.constants.find{|c| RubyProf.const_get(c) == RubyProf.measure_mode}
63
- end
64
-
65
- def print_threads
66
- @result.threads.each do |thread|
67
- puts "subgraph \"Thread #{thread.id}\" {"
68
-
69
- print_thread(thread)
70
- puts "}"
71
-
72
- print_classes(thread)
73
- end
74
- end
75
-
76
- # Determines an ID to use to represent the subject in the Dot file.
77
- def dot_id(subject)
78
- subject.object_id
79
- end
80
-
81
- def print_thread(thread)
82
- total_time = thread.total_time
83
- thread.methods.sort_by(&sort_method).reverse_each do |method|
84
- total_percentage = (method.total_time/total_time) * 100
85
-
86
- next if total_percentage < min_percent
87
- name = method_name(method).split("#").last
88
- puts "#{dot_id(method)} [label=\"#{name}\\n(#{total_percentage.round}%)\"];"
89
- @seen_methods << method
90
- print_edges(total_time, method)
91
- end
92
- end
93
-
94
- def print_classes(thread)
95
- grouped = {}
96
- thread.methods.each{|m| grouped[m.klass_name] ||= []; grouped[m.klass_name] << m}
97
- grouped.each do |cls, methods2|
98
- # Filter down to just seen methods
99
- big_methods = methods2.select{|m| @seen_methods.include? m}
100
-
101
- if !big_methods.empty?
102
- puts "subgraph cluster_#{cls.object_id} {"
103
- puts "label = \"#{cls}\";"
104
- puts "fontcolor = #{CLASS_COLOR};"
105
- puts "fontsize = 16;"
106
- puts "color = #{CLASS_COLOR};"
107
- big_methods.each do |m|
108
- puts "#{m.object_id};"
109
- end
110
- puts "}"
111
- end
112
- end
113
- end
114
-
115
- def print_edges(total_time, method)
116
- method.aggregate_children.sort_by(&:total_time).reverse.each do |child|
117
-
118
- target_percentage = (child.target.total_time / total_time) * 100.0
119
- next if target_percentage < min_percent
120
-
121
- # Get children method
122
- puts "#{dot_id(method)} -> #{dot_id(child.target)} [label=\"#{child.called}/#{child.target.called}\" fontsize=10 fontcolor=#{EDGE_COLOR}];"
123
- end
124
- end
125
-
126
- # Silly little helper for printing to the @output
127
- def puts(str)
128
- @output.puts(str)
129
- end
130
-
131
- end
132
- end
1
+ # encoding: utf-8
2
+
3
+ require 'set'
4
+
5
+ module RubyProf
6
+ # Generates a graphviz graph in dot format.
7
+ #
8
+ # To use the dot printer:
9
+ #
10
+ # result = RubyProf.profile do
11
+ # [code to profile]
12
+ # end
13
+ #
14
+ # printer = RubyProf::DotPrinter.new(result)
15
+ # printer.print(STDOUT)
16
+ #
17
+ # You can use either dot viewer such as GraphViz, or the dot command line tool
18
+ # to reformat the output into a wide variety of outputs:
19
+ #
20
+ # dot -Tpng graph.dot > graph.png
21
+ #
22
+ class DotPrinter < RubyProf::AbstractPrinter
23
+ CLASS_COLOR = '"#666666"'
24
+ EDGE_COLOR = '"#666666"'
25
+
26
+ # Creates the DotPrinter using a RubyProf::Proile.
27
+ def initialize(result)
28
+ super(result)
29
+ @seen_methods = Set.new
30
+ end
31
+
32
+ # Print a graph report to the provided output.
33
+ #
34
+ # output - Any IO object, including STDOUT or a file. The default value is
35
+ # STDOUT.
36
+ #
37
+ # options - Hash of print options. See #setup_options
38
+ # for more information.
39
+ #
40
+ # When profiling results that cover a large number of method calls it
41
+ # helps to use the :min_percent option, for example:
42
+ #
43
+ # DotPrinter.new(result).print(STDOUT, :min_percent=>5)
44
+ #
45
+ def print(output = STDOUT, options = {})
46
+ @output = output
47
+ setup_options(options)
48
+
49
+ puts 'digraph "Profile" {'
50
+ #puts "label=\"#{mode_name} >=#{min_percent}%\\nTotal: #{total_time}\";"
51
+ puts "labelloc=t;"
52
+ puts "labeljust=l;"
53
+ print_threads
54
+ puts '}'
55
+ end
56
+
57
+ private
58
+
59
+ # Something of a hack, figure out which constant went with the
60
+ # RubyProf.measure_mode so that we can display it. Otherwise it's easy to
61
+ # forget what measurement was made.
62
+ def mode_name
63
+ RubyProf.constants.find{|c| RubyProf.const_get(c) == RubyProf.measure_mode}
64
+ end
65
+
66
+ def print_threads
67
+ @result.threads.each do |thread|
68
+ puts "subgraph \"Thread #{thread.id}\" {"
69
+
70
+ print_thread(thread)
71
+ puts "}"
72
+
73
+ print_classes(thread)
74
+ end
75
+ end
76
+
77
+ # Determines an ID to use to represent the subject in the Dot file.
78
+ def dot_id(subject)
79
+ subject.object_id
80
+ end
81
+
82
+ def print_thread(thread)
83
+ total_time = thread.total_time
84
+ thread.methods.sort_by(&sort_method).reverse_each do |method|
85
+ total_percentage = (method.total_time/total_time) * 100
86
+
87
+ next if total_percentage < min_percent
88
+ name = method.full_name.split("#").last
89
+ puts "#{dot_id(method)} [label=\"#{name}\\n(#{total_percentage.round}%)\"];"
90
+ @seen_methods << method
91
+ print_edges(total_time, method)
92
+ end
93
+ end
94
+
95
+ def print_classes(thread)
96
+ grouped = {}
97
+ thread.methods.each{|m| grouped[m.klass_name] ||= []; grouped[m.klass_name] << m}
98
+ grouped.each do |cls, methods2|
99
+ # Filter down to just seen methods
100
+ big_methods = methods2.select{|m| @seen_methods.include? m}
101
+
102
+ if !big_methods.empty?
103
+ puts "subgraph cluster_#{cls.object_id} {"
104
+ puts "label = \"#{cls}\";"
105
+ puts "fontcolor = #{CLASS_COLOR};"
106
+ puts "fontsize = 16;"
107
+ puts "color = #{CLASS_COLOR};"
108
+ big_methods.each do |m|
109
+ puts "#{m.object_id};"
110
+ end
111
+ puts "}"
112
+ end
113
+ end
114
+ end
115
+
116
+ def print_edges(total_time, method)
117
+ method.callers.sort_by(&:total_time).reverse.each do |call_info|
118
+ target_percentage = (call_info.target.total_time / total_time) * 100.0
119
+ next if target_percentage < min_percent
120
+
121
+ # Get children method
122
+ puts "#{dot_id(method)} -> #{dot_id(call_info.target)} [label=\"#{call_info.called}/#{call_info.target.called}\" fontsize=10 fontcolor=#{EDGE_COLOR}];"
123
+ end
124
+ end
125
+
126
+ # Silly little helper for printing to the @output
127
+ def puts(str)
128
+ @output.puts(str)
129
+ end
130
+
131
+ end
132
+ end
@@ -1,70 +1,52 @@
1
- # encoding: utf-8
2
-
3
- module RubyProf
4
- # Generates flat[link:files/examples/flat_txt.html] profile reports as text.
5
- # To use the flat printer:
6
- #
7
- # result = RubyProf.profile do
8
- # [code to profile]
9
- # end
10
- #
11
- # printer = RubyProf::FlatPrinter.new(result)
12
- # printer.print(STDOUT, {})
13
- #
14
- class FlatPrinter < AbstractPrinter
15
- # Override for this printer to sort by self time by default
16
- def sort_method
17
- @options[:sort_method] || :self_time
18
- end
19
-
20
- private
21
-
22
- #def print_threads
23
- # @result.threads.each do |thread|
24
- # print_thread(thread)
25
- # @output << "\n" * 2
26
- # end
27
- #end
28
-
29
- def print_header(thread)
30
- @output << "Measure Mode: %s\n" % RubyProf.measure_mode_string
31
- @output << "Thread ID: %d\n" % thread.id
32
- @output << "Fiber ID: %d\n" % thread.fiber_id unless thread.id == thread.fiber_id
33
- @output << "Total: %0.6f\n" % thread.total_time
34
- @output << "Sort by: #{sort_method}\n"
35
- @output << "\n"
36
- @output << " %self total self wait child calls name\n"
37
- end
38
-
39
- def print_methods(thread)
40
- total_time = thread.total_time
41
- methods = thread.methods.sort_by(&sort_method).reverse
42
-
43
- sum = 0
44
- methods.each do |method|
45
- self_percent = (method.self_time / total_time) * 100
46
- next if self_percent < min_percent
47
-
48
- sum += method.self_time
49
- #self_time_called = method.called > 0 ? method.self_time/method.called : 0
50
- #total_time_called = method.called > 0? method.total_time/method.called : 0
51
-
52
- @output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%s\n" % [
53
- method.self_time / total_time * 100, # %self
54
- method.total_time, # total
55
- method.self_time, # self
56
- method.wait_time, # wait
57
- method.children_time, # children
58
- method.called, # calls
59
- method.recursive? ? "*" : " ", # cycle
60
- method_name(method) # name
61
- ]
62
- end
63
- end
64
-
65
- def print_footer(thread)
66
- @output << "\n"
67
- @output << "* indicates recursively called methods\n"
68
- end
69
- end
70
- end
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # Generates flat[link:files/examples/flat_txt.html] profile reports as text.
5
+ # To use the flat printer:
6
+ #
7
+ # result = RubyProf.profile do
8
+ # [code to profile]
9
+ # end
10
+ #
11
+ # printer = RubyProf::FlatPrinter.new(result)
12
+ # printer.print(STDOUT, {})
13
+ #
14
+ class FlatPrinter < AbstractPrinter
15
+ # Override for this printer to sort by self time by default
16
+ def sort_method
17
+ @options[:sort_method] || :self_time
18
+ end
19
+
20
+ private
21
+
22
+ def print_column_headers
23
+ @output << " %self total self wait child calls name location\n"
24
+ end
25
+
26
+ def print_methods(thread)
27
+ total_time = thread.total_time
28
+ methods = thread.methods.sort_by(&sort_method).reverse
29
+
30
+ sum = 0
31
+ methods.each do |method|
32
+ self_percent = (method.self_time / total_time) * 100
33
+ next if self_percent < min_percent
34
+
35
+ sum += method.self_time
36
+ #self_time_called = method.called > 0 ? method.self_time/method.called : 0
37
+ #total_time_called = method.called > 0? method.total_time/method.called : 0
38
+
39
+ @output << "%6.2f %9.3f %9.3f %9.3f %9.3f %8d %s%-30s %s\n" % [
40
+ method.self_time / total_time * 100, # %self
41
+ method.total_time, # total
42
+ method.self_time, # self
43
+ method.wait_time, # wait
44
+ method.children_time, # children
45
+ method.called, # calls
46
+ method.recursive? ? "*" : " ", # cycle
47
+ method.full_name, # method_name]
48
+ method_location(method)] # location]
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,244 +1,63 @@
1
- # encoding: utf-8
2
-
3
- require 'erb'
4
-
5
- module RubyProf
6
- # Generates graph[link:files/examples/graph_html.html] profile reports as html.
7
- # To use the graph html printer:
8
- #
9
- # result = RubyProf.profile do
10
- # [code to profile]
11
- # end
12
- #
13
- # printer = RubyProf::GraphHtmlPrinter.new(result)
14
- # printer.print(STDOUT, :min_percent=>0)
15
- #
16
- # The Graph printer takes the following options in its print methods:
17
- # :filename - specify a file to use that contains the ERB
18
- # template to use, instead of the built-in self.template
19
- #
20
- # :template - specify an ERB template to use, instead of the
21
- # built-in self.template
22
- #
23
-
24
- class GraphHtmlPrinter < AbstractPrinter
25
- include ERB::Util
26
-
27
- def setup_options(options)
28
- super(options)
29
-
30
- filename = options[:filename]
31
- template = filename ? File.read(filename).untaint : (options[:template] || self.template)
32
- @erb = ERB.new(template)
33
- @erb.filename = filename
34
- end
35
-
36
- def print(output = STDOUT, options = {})
37
- @output = output
38
- setup_options(options)
39
- @output << @erb.result(binding).split("\n").map(&:rstrip).join("\n") << "\n"
40
- end
41
-
42
- # Creates a link to a method. Note that we do not create
43
- # links to methods which are under the min_perecent
44
- # specified by the user, since they will not be
45
- # printed out.
46
- def create_link(thread, overall_time, method)
47
- total_percent = (method.total_time/overall_time) * 100
48
- if total_percent < min_percent
49
- # Just return name
50
- h method.full_name
51
- else
52
- href = '#' + method_href(thread, method)
53
- "<a href=\"#{href}\">#{h method.full_name}</a>"
54
- end
55
- end
56
-
57
- def method_href(thread, method)
58
- h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
59
- end
60
-
61
- def file_link(path, linenum)
62
- srcfile = File.expand_path(path)
63
- if srcfile =~ /\/ruby_runtime$/
64
- ""
65
- else
66
- if RUBY_PLATFORM =~ /darwin/
67
- "<a href=\"txmt://open?url=file://#{h srcfile}&line=#{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
68
- else
69
- "<a href=\"file://#{h srcfile}##{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
70
- end
71
- end
72
- end
73
-
74
- def template
75
- '
76
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
77
- <html>
78
- <head>
79
- <style media="all" type="text/css">
80
- table {
81
- border-collapse: collapse;
82
- border: 1px solid #CCC;
83
- font-family: Verdana, Arial, Helvetica, sans-serif;
84
- font-size: 9pt;
85
- line-height: normal;
86
- width: 100%;
87
- }
88
-
89
- th {
90
- text-align: center;
91
- border-top: 1px solid #FB7A31;
92
- border-bottom: 1px solid #FB7A31;
93
- background: #FFC;
94
- padding: 0.3em;
95
- border-left: 1px solid silver;
96
- }
97
-
98
- tr.break td {
99
- border: 0;
100
- border-top: 1px solid #FB7A31;
101
- padding: 0;
102
- margin: 0;
103
- }
104
-
105
- tr.method td {
106
- font-weight: bold;
107
- }
108
-
109
- td {
110
- padding: 0.3em;
111
- }
112
-
113
- td:first-child {
114
- width: 190px;
115
- }
116
-
117
- td {
118
- border-left: 1px solid #CCC;
119
- text-align: center;
120
- }
121
-
122
- .method_name {
123
- text-align: left;
124
- }
125
-
126
- tfoot td {
127
- text-align: left;
128
- }
129
- </style>
130
- </head>
131
- <body>
132
- <h1>Profile Report: <%= RubyProf.measure_mode_string %></h1>
133
- <!-- Threads Table -->
134
- <table>
135
- <tr>
136
- <th>Thread ID</th>
137
- <th>Fiber ID</th>
138
- <th>Total Time</th>
139
- </tr>
140
- <% for thread in @result.threads %>
141
- <tr>
142
- <td><%= thread.id %></td>
143
- <td><a href="#<%= thread.fiber_id %>"><%= thread.fiber_id %></a></td>
144
- <td><%= thread.total_time %></td>
145
- </tr>
146
- <% end %>
147
- </table>
148
- <!-- Methods Tables -->
149
- <%
150
- for thread in @result.threads
151
- methods = thread.methods
152
- total_time = thread.total_time
153
- %>
154
- <h2><a name="<%= thread.fiber_id %>">Thread <%= thread.id %>, Fiber: <%= thread.fiber_id %></a></h2>
155
- <table>
156
- <thead>
157
- <tr>
158
- <th>%Total</th>
159
- <th>%Self</th>
160
- <th>Total</th>
161
- <th>Self</th>
162
- <th>Wait</th>
163
- <th>Child</th>
164
- <th>Calls</th>
165
- <th class="method_name">Name</th>
166
- <th>Line</th>
167
- </tr>
168
- </thead>
169
- <tbody>
170
- <%
171
- min_time = @options[:min_time] || (@options[:nonzero] ? 0.005 : nil)
172
- methods.sort_by(&sort_method).reverse_each do |method|
173
- total_percentage = (method.total_time/total_time) * 100
174
- next if total_percentage < min_percent
175
- next if min_time && method.total_time < min_time
176
- self_percentage = (method.self_time/total_time) * 100
177
- %>
178
- <!-- Parents -->
179
- <%
180
- for caller in method.aggregate_parents.sort_by(&:total_time)
181
- next unless caller.parent
182
- next if min_time && caller.total_time < min_time
183
- %>
184
- <tr>
185
- <td>&nbsp;</td>
186
- <td>&nbsp;</td>
187
- <td><%= sprintf("%.2f", caller.total_time) %></td>
188
- <td><%= sprintf("%.2f", caller.self_time) %></td>
189
- <td><%= sprintf("%.2f", caller.wait_time) %></td>
190
- <td><%= sprintf("%.2f", caller.children_time) %></td>
191
- <td><%= "#{caller.called}/#{method.called}" %></td>
192
- <td class="method_name"><%= create_link(thread, total_time, caller.parent.target) %></td>
193
- <td><%= file_link(caller.parent.target.source_file, caller.line) %></td>
194
- </tr>
195
- <% end %>
196
- <tr class="method">
197
- <td><%= sprintf("%.2f\%", total_percentage) %></td>
198
- <td><%= sprintf("%.2f\%", self_percentage) %></td>
199
- <td><%= sprintf("%.2f", method.total_time) %></td>
200
- <td><%= sprintf("%.2f", method.self_time) %></td>
201
- <td><%= sprintf("%.2f", method.wait_time) %></td>
202
- <td><%= sprintf("%.2f", method.children_time) %></td>
203
- <td><%= sprintf("%i", method.called) %></td>
204
- <td class="method_name">
205
- <a name="<%= method_href(thread, method) %>">
206
- <%= method.recursive? ? "*" : " "%><%= h method.full_name %>
207
- </a>
208
- </td>
209
- <td><%= file_link(method.source_file, method.line) %></td>
210
- </tr>
211
- <!-- Children -->
212
- <%
213
- for callee in method.aggregate_children.sort_by(&:total_time).reverse
214
- next if min_time && callee.total_time < min_time
215
- %>
216
- <tr>
217
- <td>&nbsp;</td>
218
- <td>&nbsp;</td>
219
- <td><%= sprintf("%.2f", callee.total_time) %></td>
220
- <td><%= sprintf("%.2f", callee.self_time) %></td>
221
- <td><%= sprintf("%.2f", callee.wait_time) %></td>
222
- <td><%= sprintf("%.2f", callee.children_time) %></td>
223
- <td><%= "#{callee.called}/#{callee.target.called}" %></td>
224
- <td class="method_name"><%= create_link(thread, total_time, callee.target) %></td>
225
- <td><%= file_link(method.source_file, callee.line) %></td>
226
- </tr>
227
- <% end %>
228
- <!-- Create divider row -->
229
- <tr class="break"><td colspan="9"></td></tr>
230
- <% end %>
231
- </tbody>
232
- <tfoot>
233
- <tr>
234
- <td colspan="9">* indicates recursively called methods</td>
235
- </tr>
236
- </tfoot>
237
- </table>
238
- <% end %>
239
- </body>
240
- </html>'
241
- end
242
- end
243
- end
244
-
1
+ # encoding: utf-8
2
+
3
+ require 'erb'
4
+
5
+ module RubyProf
6
+ # Generates graph[link:files/examples/graph_html.html] profile reports as html.
7
+ # To use the graph html printer:
8
+ #
9
+ # result = RubyProf.profile do
10
+ # [code to profile]
11
+ # end
12
+ #
13
+ # printer = RubyProf::GraphHtmlPrinter.new(result)
14
+ # printer.print(STDOUT, :min_percent=>0)
15
+ #
16
+ # The Graph printer takes the following options in its print methods:
17
+
18
+ class GraphHtmlPrinter < AbstractPrinter
19
+ include ERB::Util
20
+
21
+ def setup_options(options)
22
+ super(options)
23
+ @erb = ERB.new(self.template)
24
+ end
25
+
26
+ def print(output = STDOUT, options = {})
27
+ setup_options(options)
28
+ output << @erb.result(binding)
29
+ end
30
+
31
+ # Creates a link to a method. Note that we do not create
32
+ # links to methods which are under the min_perecent
33
+ # specified by the user, since they will not be
34
+ # printed out.
35
+ def create_link(thread, overall_time, method)
36
+ total_percent = (method.total_time/overall_time) * 100
37
+ if total_percent < min_percent
38
+ # Just return name
39
+ h method.full_name
40
+ else
41
+ href = '#' + method_href(thread, method)
42
+ "<a href=\"#{href}\">#{h method.full_name}</a>"
43
+ end
44
+ end
45
+
46
+ def method_href(thread, method)
47
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
48
+ end
49
+
50
+ def file_link(path, linenum)
51
+ if path.nil?
52
+ ""
53
+ else
54
+ srcfile = File.expand_path(path)
55
+ "<a href=\"file://#{h srcfile}##{linenum}\" title=\"#{h srcfile}:#{linenum}\">#{linenum}</a>"
56
+ end
57
+ end
58
+
59
+ def template
60
+ open_asset('graph_printer.html.erb')
61
+ end
62
+ end
63
+ end