ruby-prof 0.16.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,95 +1,171 @@
1
- # encoding: utf-8
2
- require 'tmpdir'
3
-
4
- module Rack
5
- class RubyProf
6
- def initialize(app, options = {})
7
- @app = app
8
- @options = options
9
- @options[:min_percent] ||= 1
10
-
11
- @tmpdir = options[:path] || Dir.tmpdir
12
- FileUtils.mkdir_p(@tmpdir)
13
-
14
- @printer_klasses = @options[:printers] || {::RubyProf::FlatPrinter => 'flat.txt',
15
- ::RubyProf::GraphPrinter => 'graph.txt',
16
- ::RubyProf::GraphHtmlPrinter => 'graph.html',
17
- ::RubyProf::CallStackPrinter => 'call_stack.html'}
18
-
19
- @skip_paths = options[:skip_paths] || [%r{^/assets}, %r{\.(css|js|png|jpeg|jpg|gif)$}]
20
- @only_paths = options[:only_paths]
21
- end
22
-
23
- def call(env)
24
- request = Rack::Request.new(env)
25
-
26
- if should_profile?(request.path)
27
- begin
28
- result = nil
29
- data = ::RubyProf::Profile.profile(profiling_options) do
30
- result = @app.call(env)
31
- end
32
-
33
- path = request.path.gsub('/', '-')
34
- path.slice!(0)
35
-
36
- print(data, path)
37
- result
38
- end
39
- else
40
- @app.call(env)
41
- end
42
- end
43
-
44
- private
45
-
46
- def should_profile?(path)
47
- return false if paths_match?(path, @skip_paths)
48
-
49
- @only_paths ? paths_match?(path, @only_paths) : true
50
- end
51
-
52
- def paths_match?(path, paths)
53
- paths.any? { |skip_path| skip_path =~ path }
54
- end
55
-
56
- def profiling_options
57
- options = {}
58
- options[:measure_mode] = ::RubyProf.measure_mode
59
- options[:exclude_threads] =
60
- if @options[:ignore_existing_threads]
61
- Thread.list.select{|t| t != Thread.current}
62
- else
63
- ::RubyProf.exclude_threads
64
- end
65
- if @options[:request_thread_only]
66
- options[:include_threads] = [Thread.current]
67
- end
68
- if @options[:merge_fibers]
69
- options[:merge_fibers] = true
70
- end
71
- options
72
- end
73
-
74
- def print(data, path)
75
- @printer_klasses.each do |printer_klass, base_name|
76
- printer = printer_klass.new(data)
77
-
78
- if base_name.respond_to?(:call)
79
- base_name = base_name.call
80
- end
81
-
82
- if printer_klass == ::RubyProf::MultiPrinter
83
- printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
84
- elsif printer_klass == ::RubyProf::CallTreePrinter
85
- printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
86
- else
87
- file_name = ::File.join(@tmpdir, "#{path}-#{base_name}")
88
- ::File.open(file_name, 'wb') do |file|
89
- printer.print(file, @options)
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
1
+ # encoding: utf-8
2
+ require 'tmpdir'
3
+
4
+ module Rack
5
+ class RubyProf
6
+ def initialize(app, options = {})
7
+ @app = app
8
+
9
+ options[:min_percent] ||= 1
10
+
11
+ options[:path] ||= Dir.tmpdir
12
+ FileUtils.mkdir_p(options[:path])
13
+
14
+ @skip_paths = options[:skip_paths] || [%r{^/assets}, %r{\.(css|js|png|jpeg|jpg|gif)$}]
15
+ @only_paths = options[:only_paths]
16
+
17
+ @max_requests = options[:max_requests]
18
+
19
+ @options = options
20
+ end
21
+
22
+ def call(env)
23
+ request = Rack::Request.new(env)
24
+
25
+ if should_profile?(request.path)
26
+ profiler.resume
27
+ begin
28
+ result = @app.call(env)
29
+ ensure
30
+ profiler.pause
31
+ end
32
+
33
+ if profiler.max_requests_reached?
34
+ prefix = if aggregate_requests?
35
+ nil
36
+ else
37
+ request.path.gsub('/', '-')[1..-1]
38
+ end
39
+
40
+ profiler.print!(prefix)
41
+ delete_profiler!
42
+ end
43
+
44
+ result
45
+ else
46
+ @app.call(env)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ class RackProfiler
53
+ def initialize(options)
54
+ @options = options
55
+
56
+ @profile = ::RubyProf::Profile.new(profiling_options)
57
+ @profile.start
58
+ @profile.pause
59
+
60
+ @printer_klasses = options[:printers] || default_printers
61
+
62
+ @tmpdir = options[:path]
63
+
64
+ @max_requests = options[:max_requests] || 1
65
+ @requests_count = 0
66
+
67
+ @printed = false
68
+ # if running across multiple requests, we want to make sure that the
69
+ # ongoing profile is not lost if the process shuts down before the
70
+ # max request count is reached
71
+ ObjectSpace.define_finalizer(self, proc { print! })
72
+ end
73
+
74
+ def resume
75
+ @profile.resume
76
+ end
77
+
78
+ def pause
79
+ @profile.pause
80
+ @requests_count += 1
81
+ end
82
+
83
+ def max_requests_reached?
84
+ @requests_count >= @max_requests
85
+ end
86
+
87
+ def print!(prefix = nil)
88
+ return false if @printed || @requests_count == 0
89
+
90
+ data = @profile.stop
91
+
92
+ prefix ||= "multi-requests-#{@requests_count}"
93
+
94
+ @printer_klasses.each do |printer_klass, base_name|
95
+ printer = printer_klass.new(data)
96
+
97
+ if base_name.respond_to?(:call)
98
+ base_name = base_name.call
99
+ end
100
+
101
+ if printer_klass == ::RubyProf::MultiPrinter \
102
+ || printer_klass == ::RubyProf::CallTreePrinter
103
+ printer.print(@options.merge(:profile => "#{prefix}-#{base_name}"))
104
+ else
105
+ file_name = ::File.join(@tmpdir, "#{prefix}-#{base_name}")
106
+ ::File.open(file_name, 'wb') do |file|
107
+ printer.print(file, @options)
108
+ end
109
+ end
110
+ end
111
+
112
+ @printed = true
113
+ end
114
+
115
+ private
116
+
117
+ def profiling_options
118
+ options = {}
119
+ options[:measure_mode] = ::RubyProf.measure_mode
120
+ options[:exclude_threads] =
121
+ if @options[:ignore_existing_threads]
122
+ Thread.list.select{|t| t != Thread.current}
123
+ else
124
+ ::RubyProf.exclude_threads
125
+ end
126
+ if @options[:request_thread_only]
127
+ options[:include_threads] = [Thread.current]
128
+ end
129
+ options
130
+ end
131
+
132
+ def default_printers
133
+ {::RubyProf::FlatPrinter => 'flat.txt',
134
+ ::RubyProf::GraphPrinter => 'graph.txt',
135
+ ::RubyProf::GraphHtmlPrinter => 'graph.html',
136
+ ::RubyProf::CallStackPrinter => 'call_stack.html'}
137
+ end
138
+ end
139
+
140
+ def profiler
141
+ if aggregate_requests?
142
+ @@_shared_profiler ||= RackProfiler.new(@options)
143
+ else
144
+ @_profiler ||= RackProfiler.new(@options)
145
+ end
146
+ end
147
+
148
+ def delete_profiler!
149
+ if aggregate_requests?
150
+ @@_shared_profiler.print! if @@_shared_profiler
151
+ @@_shared_profiler = nil
152
+ else
153
+ @_profiler = nil
154
+ end
155
+ end
156
+
157
+ def aggregate_requests?
158
+ !@max_requests.nil?
159
+ end
160
+
161
+ def should_profile?(path)
162
+ return false if paths_match?(path, @skip_paths)
163
+
164
+ @only_paths ? paths_match?(path, @only_paths) : true
165
+ end
166
+
167
+ def paths_match?(path, paths)
168
+ paths.any? { |skip_path| skip_path =~ path }
169
+ end
170
+ end
171
+ end
@@ -1,147 +1,147 @@
1
- #!/usr/bin/env ruby
2
- # encoding: utf-8
3
-
4
- require 'rake'
5
- require 'rake/testtask'
6
- require 'fileutils'
7
-
8
- module RubyProf
9
-
10
- # Define a task library for profiling unit tests with ruby-prof.
11
- #
12
- # All of the options provided by
13
- # the Rake:TestTask are supported except the loader
14
- # which is set to ruby-prof. For detailed information
15
- # please refer to the Rake:TestTask documentation.
16
- #
17
- # ruby-prof specific options include:
18
- #
19
- # output_dir - For each file specified an output
20
- # file with profile information will be
21
- # written to the output directory.
22
- # By default, the output directory is
23
- # called "profile" and is created underneath
24
- # the current working directory.
25
- #
26
- # printer - Specifies the output printer. Valid values include
27
- # :flat, :graph, :graph_html and :call_tree.
28
- #
29
- # min_percent - Methods that take less than the specified percent
30
- # will not be written out.
31
- #
32
- # Example:
33
- #
34
- # require 'ruby-prof/task'
35
- #
36
- # RubyProf::ProfileTask.new do |t|
37
- # t.test_files = FileList['test/test*.rb']
38
- # t.output_dir = "c:/temp"
39
- # t.printer = :graph
40
- # t.min_percent = 10
41
- # end
42
- #
43
- # If rake is invoked with a "TEST=filename" command line option,
44
- # then the list of test files will be overridden to include only the
45
- # filename specified on the command line. This provides an easy way
46
- # to run just one test.
47
- #
48
- # If rake is invoked with a "TESTOPTS=options" command line option,
49
- # then the given options are passed to the test process after a
50
- # '--'. This allows Test::Unit options to be passed to the test
51
- # suite.
52
- #
53
- # Examples:
54
- #
55
- # rake profile # run tests normally
56
- # rake profile TEST=just_one_file.rb # run just one test file.
57
- # rake profile TESTOPTS="-v" # run in verbose mode
58
- # rake profile TESTOPTS="--runner=fox" # use the fox test runner
59
-
60
- class ProfileTask < Rake::TestTask
61
- attr_accessor :output_dir
62
- attr_accessor :min_percent
63
- attr_accessor :printer
64
-
65
- def initialize(name = :profile)
66
- super(name)
67
- end
68
-
69
- # Create the tasks defined by this task lib.
70
- def define
71
- lib_path = @libs.join(File::PATH_SEPARATOR)
72
- desc "Profile" + (@name==:profile ? "" : " for #{@name}")
73
-
74
- task @name do
75
- create_output_directory
76
-
77
- @ruby_opts.unshift( "-I#{lib_path}" )
78
- @ruby_opts.unshift( "-w" ) if @warning
79
- @ruby_opts.push("-S ruby-prof")
80
- @ruby_opts.push("--printer #{@printer}")
81
- @ruby_opts.push("--min_percent #{@min_percent}")
82
-
83
- file_list.each do |file_path|
84
- run_script(file_path)
85
- end
86
- end
87
- self
88
- end
89
-
90
- # Run script
91
- def run_script(script_path)
92
- run_code = ''
93
- RakeFileUtils.verbose(@verbose) do
94
- file_name = File.basename(script_path, File.extname(script_path))
95
- case @printer
96
- when :flat, :graph, :call_tree
97
- file_name += ".txt"
98
- when :graph_html
99
- file_name += ".html"
100
- else
101
- file_name += ".txt"
102
- end
103
-
104
- output_file_path = File.join(output_directory, file_name)
105
-
106
- command_line = @ruby_opts.join(" ") +
107
- " --file=" + output_file_path +
108
- " " + script_path
109
-
110
- puts "ruby " + command_line
111
- # We have to catch the exeption to continue on. However,
112
- # the error message will have been output to STDERR
113
- # already by the time we get here so we don't have to
114
- # do that again
115
- begin
116
- ruby command_line
117
- rescue => e
118
- STDOUT << e << "\n"
119
- STDOUT.flush
120
- end
121
- puts ""
122
- puts ""
123
- end
124
- end
125
-
126
- def output_directory
127
- File.expand_path(@output_dir)
128
- end
129
-
130
- def create_output_directory
131
- if not File.exist?(output_directory)
132
- Dir.mkdir(output_directory)
133
- end
134
- end
135
-
136
- def clean_output_directory
137
- if File.exist?(output_directory)
138
- files = Dir.glob(output_directory + '/*')
139
- FileUtils.rm(files)
140
- end
141
- end
142
-
143
- def option_list # :nodoc:
144
- ENV['OPTIONS'] || @options.join(" ") || ""
145
- end
146
- end
147
- end
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'rake'
5
+ require 'rake/testtask'
6
+ require 'fileutils'
7
+
8
+ module RubyProf
9
+
10
+ # Define a task library for profiling unit tests with ruby-prof.
11
+ #
12
+ # All of the options provided by
13
+ # the Rake:TestTask are supported except the loader
14
+ # which is set to ruby-prof. For detailed information
15
+ # please refer to the Rake:TestTask documentation.
16
+ #
17
+ # ruby-prof specific options include:
18
+ #
19
+ # output_dir - For each file specified an output
20
+ # file with profile information will be
21
+ # written to the output directory.
22
+ # By default, the output directory is
23
+ # called "profile" and is created underneath
24
+ # the current working directory.
25
+ #
26
+ # printer - Specifies the output printer. Valid values include
27
+ # :flat, :graph, :graph_html and :call_tree.
28
+ #
29
+ # min_percent - Methods that take less than the specified percent
30
+ # will not be written out.
31
+ #
32
+ # Example:
33
+ #
34
+ # require 'ruby-prof/task'
35
+ #
36
+ # RubyProf::ProfileTask.new do |t|
37
+ # t.test_files = FileList['test/test*.rb']
38
+ # t.output_dir = "c:/temp"
39
+ # t.printer = :graph
40
+ # t.min_percent = 10
41
+ # end
42
+ #
43
+ # If rake is invoked with a "TEST=filename" command line option,
44
+ # then the list of test files will be overridden to include only the
45
+ # filename specified on the command line. This provides an easy way
46
+ # to run just one test.
47
+ #
48
+ # If rake is invoked with a "TESTOPTS=options" command line option,
49
+ # then the given options are passed to the test process after a
50
+ # '--'. This allows Test::Unit options to be passed to the test
51
+ # suite.
52
+ #
53
+ # Examples:
54
+ #
55
+ # rake profile # run tests normally
56
+ # rake profile TEST=just_one_file.rb # run just one test file.
57
+ # rake profile TESTOPTS="-v" # run in verbose mode
58
+ # rake profile TESTOPTS="--runner=fox" # use the fox test runner
59
+
60
+ class ProfileTask < Rake::TestTask
61
+ attr_accessor :output_dir
62
+ attr_accessor :min_percent
63
+ attr_accessor :printer
64
+
65
+ def initialize(name = :profile)
66
+ super(name)
67
+ end
68
+
69
+ # Create the tasks defined by this task lib.
70
+ def define
71
+ lib_path = @libs.join(File::PATH_SEPARATOR)
72
+ desc "Profile" + (@name==:profile ? "" : " for #{@name}")
73
+
74
+ task @name do
75
+ create_output_directory
76
+
77
+ @ruby_opts.unshift( "-I#{lib_path}" )
78
+ @ruby_opts.unshift( "-w" ) if @warning
79
+ @ruby_opts.push("-S ruby-prof")
80
+ @ruby_opts.push("--printer #{@printer}")
81
+ @ruby_opts.push("--min_percent #{@min_percent}")
82
+
83
+ file_list.each do |file_path|
84
+ run_script(file_path)
85
+ end
86
+ end
87
+ self
88
+ end
89
+
90
+ # Run script
91
+ def run_script(script_path)
92
+ run_code = ''
93
+ RakeFileUtils.verbose(@verbose) do
94
+ file_name = File.basename(script_path, File.extname(script_path))
95
+ case @printer
96
+ when :flat, :graph, :call_tree
97
+ file_name += ".txt"
98
+ when :graph_html
99
+ file_name += ".html"
100
+ else
101
+ file_name += ".txt"
102
+ end
103
+
104
+ output_file_path = File.join(output_directory, file_name)
105
+
106
+ command_line = @ruby_opts.join(" ") +
107
+ " --file=" + output_file_path +
108
+ " " + script_path
109
+
110
+ puts "ruby " + command_line
111
+ # We have to catch the exeption to continue on. However,
112
+ # the error message will have been output to STDERR
113
+ # already by the time we get here so we don't have to
114
+ # do that again
115
+ begin
116
+ ruby command_line
117
+ rescue => e
118
+ STDOUT << e << "\n"
119
+ STDOUT.flush
120
+ end
121
+ puts ""
122
+ puts ""
123
+ end
124
+ end
125
+
126
+ def output_directory
127
+ File.expand_path(@output_dir)
128
+ end
129
+
130
+ def create_output_directory
131
+ if not File.exist?(output_directory)
132
+ Dir.mkdir(output_directory)
133
+ end
134
+ end
135
+
136
+ def clean_output_directory
137
+ if File.exist?(output_directory)
138
+ files = Dir.glob(output_directory + '/*')
139
+ FileUtils.rm(files)
140
+ end
141
+ end
142
+
143
+ def option_list # :nodoc:
144
+ ENV['OPTIONS'] || @options.join(" ") || ""
145
+ end
146
+ end
147
+ end