ruby-prof 0.18.0-x64-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 (108) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +500 -0
  3. data/LICENSE +25 -0
  4. data/README.rdoc +487 -0
  5. data/Rakefile +113 -0
  6. data/bin/ruby-prof +345 -0
  7. data/bin/ruby-prof-check-trace +45 -0
  8. data/examples/flat.txt +50 -0
  9. data/examples/graph.dot +84 -0
  10. data/examples/graph.html +823 -0
  11. data/examples/graph.txt +139 -0
  12. data/examples/multi.flat.txt +23 -0
  13. data/examples/multi.graph.html +760 -0
  14. data/examples/multi.grind.dat +114 -0
  15. data/examples/multi.stack.html +547 -0
  16. data/examples/stack.html +547 -0
  17. data/ext/ruby_prof/extconf.rb +68 -0
  18. data/ext/ruby_prof/rp_call_info.c +425 -0
  19. data/ext/ruby_prof/rp_call_info.h +53 -0
  20. data/ext/ruby_prof/rp_measure.c +40 -0
  21. data/ext/ruby_prof/rp_measure.h +45 -0
  22. data/ext/ruby_prof/rp_measure_allocations.c +76 -0
  23. data/ext/ruby_prof/rp_measure_cpu_time.c +136 -0
  24. data/ext/ruby_prof/rp_measure_gc_runs.c +73 -0
  25. data/ext/ruby_prof/rp_measure_gc_time.c +60 -0
  26. data/ext/ruby_prof/rp_measure_memory.c +77 -0
  27. data/ext/ruby_prof/rp_measure_process_time.c +71 -0
  28. data/ext/ruby_prof/rp_measure_wall_time.c +45 -0
  29. data/ext/ruby_prof/rp_method.c +630 -0
  30. data/ext/ruby_prof/rp_method.h +75 -0
  31. data/ext/ruby_prof/rp_stack.c +173 -0
  32. data/ext/ruby_prof/rp_stack.h +63 -0
  33. data/ext/ruby_prof/rp_thread.c +277 -0
  34. data/ext/ruby_prof/rp_thread.h +27 -0
  35. data/ext/ruby_prof/ruby_prof.c +794 -0
  36. data/ext/ruby_prof/ruby_prof.h +60 -0
  37. data/ext/ruby_prof/vc/ruby_prof.sln +31 -0
  38. data/ext/ruby_prof/vc/ruby_prof.vcxproj +141 -0
  39. data/lib/2.6.3/ruby_prof.so +0 -0
  40. data/lib/ruby-prof.rb +68 -0
  41. data/lib/ruby-prof/aggregate_call_info.rb +76 -0
  42. data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
  43. data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
  44. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  45. data/lib/ruby-prof/call_info.rb +115 -0
  46. data/lib/ruby-prof/call_info_visitor.rb +40 -0
  47. data/lib/ruby-prof/compatibility.rb +179 -0
  48. data/lib/ruby-prof/method_info.rb +121 -0
  49. data/lib/ruby-prof/printers/abstract_printer.rb +104 -0
  50. data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
  51. data/lib/ruby-prof/printers/call_stack_printer.rb +265 -0
  52. data/lib/ruby-prof/printers/call_tree_printer.rb +143 -0
  53. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  54. data/lib/ruby-prof/printers/flat_printer.rb +70 -0
  55. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +83 -0
  56. data/lib/ruby-prof/printers/graph_html_printer.rb +249 -0
  57. data/lib/ruby-prof/printers/graph_printer.rb +116 -0
  58. data/lib/ruby-prof/printers/multi_printer.rb +84 -0
  59. data/lib/ruby-prof/profile.rb +26 -0
  60. data/lib/ruby-prof/profile/exclude_common_methods.rb +207 -0
  61. data/lib/ruby-prof/profile/legacy_method_elimination.rb +50 -0
  62. data/lib/ruby-prof/rack.rb +174 -0
  63. data/lib/ruby-prof/task.rb +147 -0
  64. data/lib/ruby-prof/thread.rb +35 -0
  65. data/lib/ruby-prof/version.rb +3 -0
  66. data/lib/unprof.rb +10 -0
  67. data/ruby-prof.gemspec +58 -0
  68. data/test/abstract_printer_test.rb +53 -0
  69. data/test/aggregate_test.rb +136 -0
  70. data/test/basic_test.rb +128 -0
  71. data/test/block_test.rb +74 -0
  72. data/test/call_info_test.rb +78 -0
  73. data/test/call_info_visitor_test.rb +31 -0
  74. data/test/duplicate_names_test.rb +32 -0
  75. data/test/dynamic_method_test.rb +55 -0
  76. data/test/enumerable_test.rb +21 -0
  77. data/test/exceptions_test.rb +24 -0
  78. data/test/exclude_methods_test.rb +146 -0
  79. data/test/exclude_threads_test.rb +53 -0
  80. data/test/fiber_test.rb +79 -0
  81. data/test/issue137_test.rb +63 -0
  82. data/test/line_number_test.rb +80 -0
  83. data/test/measure_allocations_test.rb +26 -0
  84. data/test/measure_cpu_time_test.rb +212 -0
  85. data/test/measure_gc_runs_test.rb +32 -0
  86. data/test/measure_gc_time_test.rb +36 -0
  87. data/test/measure_memory_test.rb +33 -0
  88. data/test/measure_process_time_test.rb +61 -0
  89. data/test/measure_wall_time_test.rb +255 -0
  90. data/test/method_elimination_test.rb +84 -0
  91. data/test/module_test.rb +45 -0
  92. data/test/multi_printer_test.rb +104 -0
  93. data/test/no_method_class_test.rb +15 -0
  94. data/test/pause_resume_test.rb +166 -0
  95. data/test/prime.rb +54 -0
  96. data/test/printers_test.rb +275 -0
  97. data/test/printing_recursive_graph_test.rb +127 -0
  98. data/test/rack_test.rb +157 -0
  99. data/test/recursive_test.rb +215 -0
  100. data/test/singleton_test.rb +38 -0
  101. data/test/stack_printer_test.rb +77 -0
  102. data/test/stack_test.rb +138 -0
  103. data/test/start_stop_test.rb +112 -0
  104. data/test/test_helper.rb +267 -0
  105. data/test/thread_test.rb +187 -0
  106. data/test/unique_call_path_test.rb +202 -0
  107. data/test/yarv_test.rb +55 -0
  108. metadata +199 -0
@@ -0,0 +1,40 @@
1
+ # The call info visitor class does a depth-first traversal across a
2
+ # list of method infos. At each call_info node, the visitor executes
3
+ # the block provided in the #visit method. The block is passed two
4
+ # parameters, the event and the call_info instance. Event will be
5
+ # either :enter or :exit.
6
+ #
7
+ # visitor = RubyProf::CallInfoVisitor.new(result.threads.first.top_call_infos)
8
+ #
9
+ # method_names = Array.new
10
+ #
11
+ # visitor.visit do |call_info, event|
12
+ # method_names << call_info.target.full_name if event == :enter
13
+ # end
14
+ #
15
+ # puts method_names
16
+
17
+ module RubyProf
18
+ class CallInfoVisitor
19
+
20
+ def initialize(call_infos)
21
+ @call_infos = CallInfo.roots_of(call_infos)
22
+ end
23
+
24
+ def visit(&block)
25
+ @call_infos.each do |call_info|
26
+ visit_call_info(call_info, &block)
27
+ end
28
+ end
29
+
30
+ private
31
+ def visit_call_info(call_info, &block)
32
+ yield call_info, :enter
33
+ call_info.children.each do |child|
34
+ visit_call_info(child, &block)
35
+ end
36
+ yield call_info, :exit
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,179 @@
1
+ # encoding: utf-8
2
+
3
+ # These methods are here for backwards compatability with previous RubyProf releases
4
+ module RubyProf
5
+ # Measurements
6
+ def self.cpu_frequency
7
+ Measure::CpuTime.frequency
8
+ end
9
+
10
+ def self.measure_allocations
11
+ Measure::Allocations.measure
12
+ end
13
+
14
+ def self.measure_cpu_time
15
+ Measure::CpuTime.measure
16
+ end
17
+
18
+ def self.measure_gc_runs
19
+ Measure::GcRuns.measure
20
+ end
21
+
22
+ def self.measure_gc_time
23
+ Measure::GcTime.measure
24
+ end
25
+
26
+ def self.measure_memory
27
+ Measure::Memory.measure
28
+ end
29
+
30
+ def self.measure_process_time
31
+ Measure::ProcessTime.measure
32
+ end
33
+
34
+ def self.measure_wall_time
35
+ Measure::WallTime.measure
36
+ end
37
+
38
+ # call-seq:
39
+ # measure_mode -> measure_mode
40
+ #
41
+ # Returns what ruby-prof is measuring. Valid values include:
42
+ #
43
+ # *RubyProf::WALL_TIME - Measure wall time using gettimeofday on Linx and GetLocalTime on Windows. This is default.
44
+ # *RubyProf::PROCESS_TIME - Measure process time. It is implemented using the clock functions in the C Runtime library.
45
+ # *RubyProf::CPU_TIME - Measure time using the CPU clock counter. This mode is only supported on Pentium or PowerPC platforms.
46
+ # *RubyProf::ALLOCATIONS - Measure object allocations. This requires a patched Ruby interpreter.
47
+ # *RubyProf::MEMORY - Measure memory size. This requires a patched Ruby interpreter.
48
+ # *RubyProf::GC_RUNS - Measure number of garbage collections. This requires a patched Ruby interpreter.
49
+ # *RubyProf::GC_TIME - Measure time spent doing garbage collection. This requires a patched Ruby interpreter.*/
50
+
51
+ def self.measure_mode
52
+ @measure_mode ||= RubyProf::WALL_TIME
53
+ end
54
+
55
+ # call-seq:
56
+ # measure_mode=value -> void
57
+ #
58
+ # Specifies what ruby-prof should measure. Valid values include:
59
+ #
60
+ # *RubyProf::WALL_TIME - Measure wall time using gettimeofday on Linx and GetLocalTime on Windows. This is default.
61
+ # *RubyProf::PROCESS_TIME - Measure process time. It is implemented using the clock functions in the C Runtime library.
62
+ # *RubyProf::CPU_TIME - Measure time using the CPU clock counter. This mode is only supported on Pentium or PowerPC platforms.
63
+ # *RubyProf::ALLOCATIONS - Measure object allocations. This requires a patched Ruby interpreter.
64
+ # *RubyProf::MEMORY - Measure memory size. This requires a patched Ruby interpreter.
65
+ # *RubyProf::GC_RUNS - Measure number of garbage collections. This requires a patched Ruby interpreter.
66
+ # *RubyProf::GC_TIME - Measure time spent doing garbage collection. This requires a patched Ruby interpreter.*/
67
+ def self.measure_mode=(value)
68
+ @measure_mode = value
69
+ end
70
+
71
+ def self.measure_mode_string
72
+ case measure_mode
73
+ when WALL_TIME then "wall_time"
74
+ when CPU_TIME then "cpu_time"
75
+ when PROCESS_TIME then "process_time_time"
76
+ when ALLOCATIONS then "allocations"
77
+ when MEMORY then "memory"
78
+ when GC_TIME then "gc_time"
79
+ when GC_RUNS then "gc_runs"
80
+ end
81
+ end
82
+
83
+ # call-seq:
84
+ # exclude_threads -> exclude_threads
85
+ #
86
+ # Returns threads ruby-prof should exclude from profiling
87
+
88
+ def self.exclude_threads
89
+ @exclude_threads ||= Array.new
90
+ end
91
+
92
+ # call-seq:
93
+ # exclude_threads= -> void
94
+ #
95
+ # Specifies what threads ruby-prof should exclude from profiling
96
+
97
+ def self.exclude_threads=(value)
98
+ @exclude_threads = value
99
+ end
100
+
101
+ # Profiling
102
+ def self.start_script(script)
103
+ start
104
+ load script
105
+ end
106
+
107
+ def self.start
108
+ ensure_not_running!
109
+ @profile = Profile.new(measure_mode: measure_mode, exclude_threads: exclude_threads)
110
+ enable_gc_stats_if_needed
111
+ @profile.start
112
+ end
113
+
114
+ def self.pause
115
+ ensure_running!
116
+ disable_gc_stats_if_needed
117
+ @profile.pause
118
+ end
119
+
120
+ def self.running?
121
+ if defined?(@profile) and @profile
122
+ @profile.running?
123
+ else
124
+ false
125
+ end
126
+ end
127
+
128
+ def self.resume
129
+ ensure_running!
130
+ enable_gc_stats_if_needed
131
+ @profile.resume
132
+ end
133
+
134
+ def self.stop
135
+ ensure_running!
136
+ result = @profile.stop
137
+ disable_gc_stats_if_needed
138
+ @profile = nil
139
+ result
140
+ end
141
+
142
+ # Profile a block
143
+ def self.profile(options = {}, &block)
144
+ ensure_not_running!
145
+ gc_stat_was_enabled = enable_gc_stats_if_needed
146
+ options = { measure_mode: measure_mode, exclude_threads: exclude_threads }.merge!(options)
147
+ result = Profile.profile(options, &block)
148
+ ensure
149
+ disable_gc_stats_if_needed(gc_stat_was_enabled)
150
+ result
151
+ end
152
+
153
+
154
+ private
155
+ def self.ensure_running!
156
+ raise(RuntimeError, "RubyProf.start was not yet called") unless running?
157
+ end
158
+
159
+ def self.ensure_not_running!
160
+ raise(RuntimeError, "RubyProf is already running") if running?
161
+ end
162
+
163
+ # for GC.allocated_size to work GC statistics should be enabled
164
+ def self.enable_gc_stats_if_needed
165
+ if measure_mode_requires_gc_stats_enabled?
166
+ @gc_stat_was_enabled = GC.enable_stats
167
+ end
168
+ end
169
+
170
+ def self.disable_gc_stats_if_needed(was_enabled=nil)
171
+ was_enabled ||= defined?(@gc_stat_was_enabled) && @gc_stat_was_enabled
172
+ GC.disable_stats if measure_mode_requires_gc_stats_enabled? && !was_enabled
173
+ end
174
+
175
+ def self.measure_mode_requires_gc_stats_enabled?
176
+ GC.respond_to?(:enable_stats) &&
177
+ [RubyProf::MEMORY, RubyProf::GC_TIME, RubyProf::GC_RUNS].include?(measure_mode)
178
+ end
179
+ end
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ class MethodInfo
5
+ include Comparable
6
+
7
+ def <=>(other)
8
+ if self.total_time < other.total_time
9
+ -1
10
+ elsif self.total_time > other.total_time
11
+ 1
12
+ elsif self.min_depth < other.min_depth
13
+ 1
14
+ elsif self.min_depth > other.min_depth
15
+ -1
16
+ else
17
+ self.full_name <=> other.full_name
18
+ end
19
+ end
20
+
21
+ def called
22
+ @called ||= begin
23
+ call_infos.inject(0) do |sum, call_info|
24
+ sum + call_info.called
25
+ end
26
+ end
27
+ end
28
+
29
+ def total_time
30
+ @total_time ||= begin
31
+ call_infos.inject(0) do |sum, call_info|
32
+ sum += call_info.total_time if !call_info.recursive?
33
+ sum
34
+ end
35
+ end
36
+ end
37
+
38
+ def self_time
39
+ @self_time ||= begin
40
+ call_infos.inject(0) do |sum, call_info|
41
+ sum += call_info.self_time if !call_info.recursive?
42
+ sum
43
+ end
44
+ end
45
+ end
46
+
47
+ def wait_time
48
+ @wait_time ||= begin
49
+ call_infos.inject(0) do |sum, call_info|
50
+ sum += call_info.wait_time if !call_info.recursive?
51
+ sum
52
+ end
53
+ end
54
+ end
55
+
56
+ def children_time
57
+ @children_time ||= begin
58
+ call_infos.inject(0) do |sum, call_info|
59
+ sum += call_info.children_time if !call_info.recursive?
60
+ sum
61
+ end
62
+ end
63
+ end
64
+
65
+ def min_depth
66
+ @min_depth ||= call_infos.map(&:depth).min
67
+ end
68
+
69
+ def root?
70
+ @root ||= begin
71
+ call_infos.find do |call_info|
72
+ not call_info.root?
73
+ end.nil?
74
+ end
75
+ end
76
+
77
+ def children
78
+ @children ||= call_infos.map(&:children).flatten
79
+ end
80
+
81
+ def parents
82
+ @parents ||= call_infos.map(&:parent)
83
+ end
84
+
85
+ def aggregate_parents
86
+ # group call infos based on their parents
87
+ groups = self.call_infos.each_with_object({}) do |call_info, hash|
88
+ key = call_info.parent ? call_info.parent.target : self
89
+ (hash[key] ||= []) << call_info
90
+ end
91
+
92
+ groups.map do |key, value|
93
+ AggregateCallInfo.new(value, self)
94
+ end
95
+ end
96
+
97
+ def aggregate_children
98
+ # group call infos based on their targets
99
+ groups = self.children.each_with_object({}) do |call_info, hash|
100
+ key = call_info.target
101
+ (hash[key] ||= []) << call_info
102
+ end
103
+
104
+ groups.map do |key, value|
105
+ AggregateCallInfo.new(value, self)
106
+ end
107
+ end
108
+
109
+ def to_s
110
+ "#{self.full_name} (c: #{self.called}, tt: #{self.total_time}, st: #{self.self_time}, wt: #{wait_time}, ct: #{self.children_time})"
111
+ end
112
+
113
+ # remove method from the call graph. should not be called directly.
114
+ def eliminate!
115
+ # $stderr.puts "eliminating #{self}"
116
+ call_infos.each{ |call_info| call_info.eliminate! }
117
+ call_infos.clear
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ class AbstractPrinter
5
+ # Create a new printer.
6
+ #
7
+ # result should be the output generated from a profiling run
8
+ def initialize(result)
9
+ @result = result
10
+ @output = nil
11
+ end
12
+
13
+ # Specify print options.
14
+ #
15
+ # options - Hash table
16
+ # :min_percent - Number 0 to 100 that specifes the minimum
17
+ # %self (the methods self time divided by the
18
+ # overall total time) that a method must take
19
+ # for it to be printed out in the report.
20
+ # Default value is 0.
21
+ #
22
+ # :print_file - True or false. Specifies if a method's source
23
+ # file should be printed. Default value if false.
24
+ #
25
+ # :sort_method - Specifies method used for sorting method infos.
26
+ # Available values are :total_time, :self_time,
27
+ # :wait_time, :children_time
28
+ # 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
43
+ end
44
+
45
+ def sort_method
46
+ @options[:sort_method] || :total_time
47
+ end
48
+
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
56
+ end
57
+ end
58
+
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
65
+ end
66
+
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
79
+ end
80
+
81
+ def print_threads
82
+ @result.threads.each do |thread|
83
+ print_thread(thread)
84
+ end
85
+ end
86
+
87
+ def print_thread(thread)
88
+ print_header(thread)
89
+ print_methods(thread)
90
+ print_footer(thread)
91
+ end
92
+
93
+ def print_header(thread)
94
+ end
95
+
96
+ def print_footer(thread)
97
+ end
98
+
99
+ # whether this printer need a :path option pointing to a directory
100
+ def self.needs_dir?
101
+ false
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,41 @@
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 << "Fiber ID: #{thread.fiber_id}\n"
16
+ @output << "Total Time: #{thread.total_time}\n"
17
+ @output << "Sort by: #{sort_method}\n"
18
+ @output << "\n"
19
+ end
20
+
21
+ def print_methods(thread)
22
+ visitor = CallInfoVisitor.new(thread.top_call_infos)
23
+
24
+ visitor.visit do |call_info, event|
25
+ if event == :enter
26
+ @output << " " * call_info.depth
27
+ @output << call_info.target.full_name
28
+ @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?}"
35
+ @output << ")"
36
+ @output << "\n"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end