ruby-prof 1.7.1 → 2.0.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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/{CHANGES → CHANGELOG.md} +118 -176
  3. data/README.md +5 -5
  4. data/bin/ruby-prof +1 -4
  5. data/docs/advanced-usage.md +132 -0
  6. data/docs/alternatives.md +98 -0
  7. data/docs/architecture.md +122 -0
  8. data/docs/best-practices.md +27 -0
  9. data/docs/getting-started.md +130 -0
  10. data/docs/history.md +11 -0
  11. data/docs/index.md +45 -0
  12. data/docs/profiling-rails.md +64 -0
  13. data/docs/public/examples/example.rb +33 -0
  14. data/docs/public/examples/generate_reports.rb +92 -0
  15. data/docs/public/examples/reports/call_info.txt +27 -0
  16. data/docs/public/examples/reports/call_stack.html +835 -0
  17. data/docs/public/examples/reports/callgrind.out +150 -0
  18. data/docs/public/examples/reports/flame_graph.html +408 -0
  19. data/docs/public/examples/reports/flat.txt +45 -0
  20. data/docs/public/examples/reports/graph.dot +129 -0
  21. data/docs/public/examples/reports/graph.html +1319 -0
  22. data/docs/public/examples/reports/graph.txt +100 -0
  23. data/docs/public/examples/reports/graphviz_viewer.html +1 -0
  24. data/docs/public/images/call_stack.png +0 -0
  25. data/docs/public/images/class_diagram.png +0 -0
  26. data/docs/public/images/dot_printer.png +0 -0
  27. data/docs/public/images/flame_graph.png +0 -0
  28. data/docs/public/images/flat.png +0 -0
  29. data/docs/public/images/graph.png +0 -0
  30. data/docs/public/images/graph_html.png +0 -0
  31. data/docs/public/images/ruby-prof-logo.svg +1 -0
  32. data/docs/reports.md +150 -0
  33. data/docs/stylesheets/extra.css +80 -0
  34. data/ext/ruby_prof/extconf.rb +23 -22
  35. data/ext/ruby_prof/rp_allocation.c +0 -15
  36. data/ext/ruby_prof/rp_allocation.h +29 -33
  37. data/ext/ruby_prof/rp_call_tree.c +3 -0
  38. data/ext/ruby_prof/rp_call_tree.h +1 -4
  39. data/ext/ruby_prof/rp_call_trees.c +296 -296
  40. data/ext/ruby_prof/rp_call_trees.h +25 -28
  41. data/ext/ruby_prof/rp_measure_allocations.c +47 -47
  42. data/ext/ruby_prof/rp_measure_process_time.c +64 -66
  43. data/ext/ruby_prof/rp_measure_wall_time.c +52 -64
  44. data/ext/ruby_prof/rp_measurement.c +0 -5
  45. data/ext/ruby_prof/rp_measurement.h +49 -53
  46. data/ext/ruby_prof/rp_method.c +554 -551
  47. data/ext/ruby_prof/rp_method.h +1 -4
  48. data/ext/ruby_prof/rp_profile.c +1 -1
  49. data/ext/ruby_prof/rp_profile.h +1 -5
  50. data/ext/ruby_prof/rp_stack.c +212 -212
  51. data/ext/ruby_prof/rp_stack.h +50 -53
  52. data/ext/ruby_prof/rp_thread.h +1 -4
  53. data/ext/ruby_prof/ruby_prof.c +50 -50
  54. data/ext/ruby_prof/ruby_prof.h +4 -6
  55. data/ext/ruby_prof/vc/ruby_prof.vcxproj +7 -8
  56. data/lib/ruby-prof/assets/call_stack_printer.html.erb +746 -711
  57. data/lib/ruby-prof/assets/flame_graph_printer.html.erb +412 -0
  58. data/lib/ruby-prof/assets/graph_printer.html.erb +355 -355
  59. data/lib/ruby-prof/call_tree.rb +57 -57
  60. data/lib/ruby-prof/call_tree_visitor.rb +36 -36
  61. data/lib/ruby-prof/exclude_common_methods.rb +204 -204
  62. data/lib/ruby-prof/measurement.rb +17 -17
  63. data/lib/ruby-prof/printers/abstract_printer.rb +142 -138
  64. data/lib/ruby-prof/printers/call_info_printer.rb +53 -53
  65. data/lib/ruby-prof/printers/call_stack_printer.rb +168 -180
  66. data/lib/ruby-prof/printers/call_tree_printer.rb +132 -145
  67. data/lib/ruby-prof/printers/dot_printer.rb +177 -132
  68. data/lib/ruby-prof/printers/flame_graph_printer.rb +79 -0
  69. data/lib/ruby-prof/printers/flat_printer.rb +52 -52
  70. data/lib/ruby-prof/printers/graph_html_printer.rb +62 -63
  71. data/lib/ruby-prof/printers/graph_printer.rb +112 -113
  72. data/lib/ruby-prof/printers/multi_printer.rb +134 -127
  73. data/lib/ruby-prof/profile.rb +13 -0
  74. data/lib/ruby-prof/rack.rb +114 -105
  75. data/lib/ruby-prof/task.rb +147 -147
  76. data/lib/ruby-prof/thread.rb +20 -20
  77. data/lib/ruby-prof/version.rb +3 -3
  78. data/lib/ruby-prof.rb +50 -52
  79. data/lib/unprof.rb +10 -10
  80. data/ruby-prof.gemspec +66 -65
  81. data/test/abstract_printer_test.rb +25 -27
  82. data/test/alias_test.rb +203 -117
  83. data/test/call_tree_builder.rb +126 -126
  84. data/test/call_tree_visitor_test.rb +27 -27
  85. data/test/call_trees_test.rb +66 -66
  86. data/test/duplicate_names_test.rb +32 -32
  87. data/test/dynamic_method_test.rb +50 -62
  88. data/test/enumerable_test.rb +23 -21
  89. data/test/exceptions_test.rb +24 -24
  90. data/test/exclude_methods_test.rb +363 -257
  91. data/test/exclude_threads_test.rb +48 -48
  92. data/test/fiber_test.rb +195 -195
  93. data/test/gc_test.rb +104 -102
  94. data/test/inverse_call_tree_test.rb +174 -174
  95. data/test/line_number_test.rb +563 -289
  96. data/test/marshal_test.rb +144 -145
  97. data/test/measure_allocations.rb +26 -26
  98. data/test/measure_allocations_test.rb +1511 -1081
  99. data/test/measure_process_time_test.rb +3286 -2477
  100. data/test/measure_times.rb +56 -56
  101. data/test/measure_wall_time_test.rb +773 -568
  102. data/test/measurement_test.rb +82 -82
  103. data/test/merge_test.rb +146 -146
  104. data/test/method_info_test.rb +100 -95
  105. data/test/multi_printer_test.rb +52 -66
  106. data/test/no_method_class_test.rb +15 -15
  107. data/test/pause_resume_test.rb +171 -171
  108. data/test/prime.rb +54 -54
  109. data/test/prime_script.rb +5 -5
  110. data/test/printer_call_stack_test.rb +28 -27
  111. data/test/printer_call_tree_test.rb +30 -30
  112. data/test/printer_flame_graph_test.rb +82 -0
  113. data/test/printer_flat_test.rb +99 -99
  114. data/test/printer_graph_html_test.rb +62 -59
  115. data/test/printer_graph_test.rb +42 -40
  116. data/test/printers_test.rb +162 -135
  117. data/test/printing_recursive_graph_test.rb +81 -81
  118. data/test/profile_test.rb +101 -101
  119. data/test/rack_test.rb +103 -93
  120. data/test/recursive_test.rb +796 -622
  121. data/test/scheduler.rb +4 -0
  122. data/test/singleton_test.rb +39 -38
  123. data/test/stack_printer_test.rb +61 -61
  124. data/test/start_stop_test.rb +106 -106
  125. data/test/test_helper.rb +24 -20
  126. data/test/thread_test.rb +229 -231
  127. data/test/unique_call_path_test.rb +123 -136
  128. data/test/yarv_test.rb +56 -60
  129. metadata +68 -16
  130. data/ext/ruby_prof/rp_measure_memory.c +0 -46
  131. data/lib/ruby-prof/compatibility.rb +0 -113
  132. data/test/compatibility_test.rb +0 -49
  133. data/test/crash2.rb +0 -144
  134. data/test/measure_memory_test.rb +0 -1456
@@ -1,138 +1,142 @@
1
- # encoding: utf-8
2
-
3
- module RubyProf
4
- # This is the base class for all Printers. It is never used directly.
5
- class AbstractPrinter
6
- # :stopdoc:
7
- def self.needs_dir?
8
- false
9
- end
10
- # :startdoc:
11
-
12
- # Create a new printer.
13
- #
14
- # result should be the output generated from a profiling run
15
- def initialize(result)
16
- @result = result
17
- @output = nil
18
- end
19
-
20
- # Returns the min_percent of 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 max_percent of time a method can take to be included in a profiling report
26
- def max_percent
27
- @options[:max_percent] || 100
28
- end
29
-
30
- # Returns the method to filter methods by (when using min_percent and max_percent)
31
- def filter_by
32
- @options[:filter_by] || :self_time
33
- end
34
-
35
- # Returns the time format used to show when a profile was run
36
- def time_format
37
- '%A, %B %-d at %l:%M:%S %p (%Z)'
38
- end
39
-
40
- # Returns how profile data should be sorted
41
- def sort_method
42
- @options[:sort_method]
43
- end
44
-
45
- # Prints a report to the provided output.
46
- #
47
- # output - Any IO object, including STDOUT or a file.
48
- # The default value is STDOUT.
49
- #
50
- # options - Hash of print options. Note that each printer can
51
- # define its own set of options.
52
- #
53
- # :min_percent - Number 0 to 100 that specifies the minimum
54
- # %self (the methods self time divided by the
55
- # overall total time) that a method must take
56
- # for it to be printed out in the report.
57
- # Default value is 0.
58
- #
59
- # :sort_method - Specifies method used for sorting method infos.
60
- # Available values are :total_time, :self_time,
61
- # :wait_time, :children_time
62
- # Default value is :total_time
63
- def print(output = STDOUT, options = {})
64
- @output = output
65
- setup_options(options)
66
- print_threads
67
- end
68
-
69
- # :nodoc:
70
- def setup_options(options = {})
71
- @options = options
72
- end
73
-
74
- def method_location(method)
75
- if method.source_file
76
- "#{method.source_file}:#{method.line}"
77
- end
78
- end
79
-
80
- def method_href(thread, method)
81
- h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
82
- end
83
-
84
- def open_asset(file)
85
- path = File.join(File.expand_path('../../assets', __FILE__), file)
86
- File.open(path, 'rb').read
87
- end
88
-
89
- def print_threads
90
- @result.threads.each do |thread|
91
- print_thread(thread)
92
- end
93
- end
94
-
95
- def print_thread(thread)
96
- print_header(thread)
97
- print_methods(thread)
98
- print_footer(thread)
99
- end
100
-
101
- def print_header(thread)
102
- @output << "Measure Mode: %s\n" % @result.measure_mode_string
103
- @output << "Thread ID: %d\n" % thread.id
104
- @output << "Fiber ID: %d\n" % thread.fiber_id unless thread.id == thread.fiber_id
105
- @output << "Total: %0.6f\n" % thread.total_time
106
- @output << "Sort by: #{sort_method}\n"
107
- @output << "\n"
108
- print_column_headers
109
- end
110
-
111
- def print_column_headers
112
- end
113
-
114
- def print_footer(thread)
115
- @output << <<~EOT
116
-
117
- * recursively called methods
118
-
119
- Columns are:
120
-
121
- %self - The percentage of time spent in this method, derived from self_time/total_time.
122
- total - The time spent in this method and its children.
123
- self - The time spent in this method.
124
- wait - The amount of time this method waited for other threads.
125
- child - The time spent in this method's children.
126
- calls - The number of times this method was called.
127
- name - The name of the method.
128
- location - The location of the method.
129
-
130
- The interpretation of method names is:
131
-
132
- * MyObject#test - An instance method "test" of the class "MyObject"
133
- * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
134
-
135
- EOT
136
- end
137
- end
138
- end
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # This is the base class for all Printers. It is never used directly.
5
+ class AbstractPrinter
6
+ # :stopdoc:
7
+ def self.needs_dir?
8
+ false
9
+ end
10
+ # :startdoc:
11
+
12
+ # Create a new printer.
13
+ #
14
+ # result should be the output generated from a profiling run
15
+ def initialize(result)
16
+ @result = result
17
+ @output = nil
18
+ end
19
+
20
+ attr_reader :min_percent, :max_percent, :filter_by, :sort_method
21
+
22
+ # Returns the time format used to show when a profile was run
23
+ def time_format
24
+ '%A, %B %-d at %l:%M:%S %p (%Z)'
25
+ end
26
+
27
+ # Prints a report to the provided output.
28
+ #
29
+ # output - Any IO object, including STDOUT or a file.
30
+ # The default value is STDOUT.
31
+ #
32
+ # Keyword arguments:
33
+ # min_percent - Number 0 to 100 that specifies the minimum
34
+ # %self (the methods self time divided by the
35
+ # overall total time) that a method must take
36
+ # for it to be printed out in the report.
37
+ # Default value is 0.
38
+ #
39
+ # max_percent - Number 0 to 100 that specifies the maximum
40
+ # %self for methods to include.
41
+ # Default value is 100.
42
+ #
43
+ # filter_by - Which time metric to use when applying
44
+ # min_percent and max_percent filters.
45
+ # Default value is :self_time.
46
+ #
47
+ # sort_method - Specifies method used for sorting method infos.
48
+ # Available values are :total_time, :self_time,
49
+ # :wait_time, :children_time.
50
+ # Default value depends on the printer.
51
+ def print(output = STDOUT, min_percent: 0, max_percent: 100, filter_by: :self_time, sort_method: nil, **)
52
+ @output = output
53
+ @min_percent = min_percent
54
+ @max_percent = max_percent
55
+ @filter_by = filter_by
56
+ @sort_method = sort_method
57
+ print_threads
58
+ end
59
+
60
+ def method_location(method)
61
+ if method.source_file
62
+ "#{method.source_file}:#{method.line}"
63
+ end
64
+ end
65
+
66
+ def method_href(thread, method)
67
+ h(method.full_name.gsub(/[><#\.\?=:]/,"_") + "_" + thread.fiber_id.to_s)
68
+ end
69
+
70
+ def open_asset(file)
71
+ path = File.join(File.expand_path('../../assets', __FILE__), file)
72
+ File.open(path, 'rb').read
73
+ end
74
+
75
+ def print_threads
76
+ @result.threads.each do |thread|
77
+ print_thread(thread)
78
+ end
79
+ end
80
+
81
+ def print_thread(thread)
82
+ print_header(thread)
83
+ print_methods(thread)
84
+ print_footer(thread)
85
+ end
86
+
87
+ def print_header(thread)
88
+ @output << "Measure Mode: %s\n" % @result.measure_mode_string
89
+ @output << "Thread ID: %d\n" % thread.id
90
+ @output << "Fiber ID: %d\n" % thread.fiber_id unless thread.id == thread.fiber_id
91
+ @output << "Total: %0.6f\n" % thread.total_time
92
+ @output << "Sort by: #{sort_method}\n"
93
+ @output << "\n"
94
+ print_column_headers
95
+ end
96
+
97
+ def print_column_headers
98
+ end
99
+
100
+ def print_footer(thread)
101
+ metric_data = {
102
+ 0 => { label: "time", prefix: "", suffix: "spent" },
103
+ 1 => { label: "time", prefix: "", suffix: "spent" },
104
+ 2 => { label: "allocations", prefix: "number of ", suffix: "made" },
105
+ 3 => { label: "memory", prefix: "", suffix: "used" }
106
+ }
107
+
108
+ metric = metric_data[@result.measure_mode]
109
+
110
+ metric_label = metric[:label]
111
+ metric_suffix = metric[:suffix]
112
+ metric_prefix = metric[:prefix]
113
+
114
+ metric1 = "#{metric_label} #{metric_suffix}"
115
+ metric2 = "#{metric_prefix}#{metric1}"
116
+ metric3 = metric_label
117
+
118
+ # Output the formatted text
119
+ @output << <<~EOT
120
+
121
+ * recursively called methods
122
+
123
+ Columns are:
124
+
125
+ %self - The percentage of #{metric1} by this method relative to the total #{metric3} in the entire program.
126
+ total - The total #{metric2} by this method and its children.
127
+ self - The #{metric2} by this method.
128
+ wait - The time this method spent waiting for other threads.
129
+ child - The #{metric2} by this method's children.
130
+ calls - The number of times this method was called.
131
+ name - The name of the method.
132
+ location - The location of the method.
133
+
134
+ The interpretation of method names is:
135
+
136
+ * MyObject#test - An instance method "test" of the class "MyObject"
137
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
138
+
139
+ EOT
140
+ end
141
+ end
142
+ end
@@ -1,53 +1,53 @@
1
- # encoding: utf-8
2
-
3
- module RubyProf
4
- # Prints out the call graph based on CallTree instances. This
5
- # is mainly for debugging purposes as it provides access into
6
- # into RubyProf's internals.
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)
16
- class CallInfoPrinter < AbstractPrinter
17
- TIME_WIDTH = 0
18
-
19
- private
20
-
21
- def print_header(thread)
22
- @output << "----------------------------------------------------\n"
23
- @output << "Thread ID: #{thread.id}\n"
24
- @output << "Fiber ID: #{thread.fiber_id}\n"
25
- @output << "Total Time: #{thread.total_time}\n"
26
- @output << "Sort by: #{sort_method}\n"
27
- @output << "\n"
28
- end
29
-
30
- def print_methods(thread)
31
- visitor = CallTreeVisitor.new(thread.call_tree)
32
-
33
- visitor.visit do |call_tree, event|
34
- if event == :enter
35
- @output << " " * call_tree.depth
36
- @output << call_tree.target.full_name
37
- @output << " ("
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}, "
43
- @output << ")"
44
- @output << "\n"
45
- end
46
- end
47
- end
48
-
49
- def print_footer(thread)
50
- @output << "\n" << "\n"
51
- end
52
- end
53
- end
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # Prints out the call graph based on CallTree instances. This
5
+ # is mainly for debugging purposes as it provides access into
6
+ # into RubyProf's internals.
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)
16
+ class CallInfoPrinter < AbstractPrinter
17
+ TIME_WIDTH = 0
18
+
19
+ private
20
+
21
+ def print_header(thread)
22
+ @output << "----------------------------------------------------\n"
23
+ @output << "Thread ID: #{thread.id}\n"
24
+ @output << "Fiber ID: #{thread.fiber_id}\n"
25
+ @output << "Total Time: #{thread.total_time}\n"
26
+ @output << "Sort by: #{sort_method}\n"
27
+ @output << "\n"
28
+ end
29
+
30
+ def print_methods(thread)
31
+ visitor = CallTreeVisitor.new(thread.call_tree)
32
+
33
+ visitor.visit do |call_tree, event|
34
+ if event == :enter
35
+ @output << " " * call_tree.depth
36
+ @output << call_tree.target.full_name
37
+ @output << " ("
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}, "
43
+ @output << ")"
44
+ @output << "\n"
45
+ end
46
+ end
47
+ end
48
+
49
+ def print_footer(thread)
50
+ @output << "\n" << "\n"
51
+ end
52
+ end
53
+ end