ruby-prof 1.8.0-x64-mswin64-140
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.
- checksums.yaml +7 -0
- data/CHANGES +665 -0
- data/LICENSE +25 -0
- data/README.md +5 -0
- data/Rakefile +98 -0
- data/bin/ruby-prof +341 -0
- data/bin/ruby-prof-check-trace +45 -0
- data/ext/ruby_prof/extconf.rb +23 -0
- data/ext/ruby_prof/rp_allocation.c +327 -0
- data/ext/ruby_prof/rp_allocation.h +32 -0
- data/ext/ruby_prof/rp_call_tree.c +502 -0
- data/ext/ruby_prof/rp_call_tree.h +47 -0
- data/ext/ruby_prof/rp_call_trees.c +296 -0
- data/ext/ruby_prof/rp_call_trees.h +28 -0
- data/ext/ruby_prof/rp_measure_allocations.c +47 -0
- data/ext/ruby_prof/rp_measure_memory.c +46 -0
- data/ext/ruby_prof/rp_measure_process_time.c +64 -0
- data/ext/ruby_prof/rp_measure_wall_time.c +52 -0
- data/ext/ruby_prof/rp_measurement.c +359 -0
- data/ext/ruby_prof/rp_measurement.h +52 -0
- data/ext/ruby_prof/rp_method.c +551 -0
- data/ext/ruby_prof/rp_method.h +66 -0
- data/ext/ruby_prof/rp_profile.c +933 -0
- data/ext/ruby_prof/rp_profile.h +36 -0
- data/ext/ruby_prof/rp_stack.c +212 -0
- data/ext/ruby_prof/rp_stack.h +53 -0
- data/ext/ruby_prof/rp_thread.c +433 -0
- data/ext/ruby_prof/rp_thread.h +39 -0
- data/ext/ruby_prof/ruby_prof.c +50 -0
- data/ext/ruby_prof/ruby_prof.h +35 -0
- data/ext/ruby_prof/vc/ruby_prof.sln +39 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +158 -0
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +711 -0
- data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
- data/lib/ruby-prof/assets/graph_printer.html.erb +355 -0
- data/lib/ruby-prof/call_tree.rb +57 -0
- data/lib/ruby-prof/call_tree_visitor.rb +36 -0
- data/lib/ruby-prof/compatibility.rb +113 -0
- data/lib/ruby-prof/exclude_common_methods.rb +204 -0
- data/lib/ruby-prof/measurement.rb +17 -0
- data/lib/ruby-prof/method_info.rb +87 -0
- data/lib/ruby-prof/printers/abstract_printer.rb +156 -0
- data/lib/ruby-prof/printers/call_info_printer.rb +53 -0
- data/lib/ruby-prof/printers/call_stack_printer.rb +180 -0
- data/lib/ruby-prof/printers/call_tree_printer.rb +145 -0
- data/lib/ruby-prof/printers/dot_printer.rb +132 -0
- data/lib/ruby-prof/printers/flat_printer.rb +53 -0
- data/lib/ruby-prof/printers/graph_html_printer.rb +63 -0
- data/lib/ruby-prof/printers/graph_printer.rb +113 -0
- data/lib/ruby-prof/printers/multi_printer.rb +127 -0
- data/lib/ruby-prof/profile.rb +70 -0
- data/lib/ruby-prof/rack.rb +105 -0
- data/lib/ruby-prof/task.rb +147 -0
- data/lib/ruby-prof/thread.rb +20 -0
- data/lib/ruby-prof/version.rb +3 -0
- data/lib/ruby-prof.rb +52 -0
- data/lib/unprof.rb +10 -0
- data/ruby-prof.gemspec +67 -0
- data/test/abstract_printer_test.rb +27 -0
- data/test/alias_test.rb +117 -0
- data/test/call_tree_builder.rb +126 -0
- data/test/call_tree_test.rb +94 -0
- data/test/call_tree_visitor_test.rb +27 -0
- data/test/call_trees_test.rb +66 -0
- data/test/compatibility_test.rb +49 -0
- data/test/duplicate_names_test.rb +32 -0
- data/test/dynamic_method_test.rb +50 -0
- data/test/enumerable_test.rb +23 -0
- data/test/exceptions_test.rb +24 -0
- data/test/exclude_methods_test.rb +363 -0
- data/test/exclude_threads_test.rb +48 -0
- data/test/fiber_test.rb +195 -0
- data/test/gc_test.rb +104 -0
- data/test/inverse_call_tree_test.rb +174 -0
- data/test/line_number_test.rb +426 -0
- data/test/marshal_test.rb +145 -0
- data/test/measure_allocations.rb +26 -0
- data/test/measure_allocations_test.rb +1172 -0
- data/test/measure_process_time_test.rb +3330 -0
- data/test/measure_times.rb +56 -0
- data/test/measure_wall_time_test.rb +635 -0
- data/test/measurement_test.rb +82 -0
- data/test/merge_test.rb +146 -0
- data/test/method_info_test.rb +100 -0
- data/test/multi_printer_test.rb +66 -0
- data/test/no_method_class_test.rb +15 -0
- data/test/pause_resume_test.rb +171 -0
- data/test/prime.rb +54 -0
- data/test/prime_script.rb +6 -0
- data/test/printer_call_stack_test.rb +27 -0
- data/test/printer_call_tree_test.rb +30 -0
- data/test/printer_flat_test.rb +99 -0
- data/test/printer_graph_html_test.rb +59 -0
- data/test/printer_graph_test.rb +40 -0
- data/test/printers_test.rb +178 -0
- data/test/printing_recursive_graph_test.rb +81 -0
- data/test/profile_test.rb +101 -0
- data/test/rack_test.rb +93 -0
- data/test/recursive_test.rb +796 -0
- data/test/scheduler.rb +363 -0
- data/test/singleton_test.rb +38 -0
- data/test/stack_printer_test.rb +61 -0
- data/test/start_stop_test.rb +106 -0
- data/test/test_helper.rb +21 -0
- data/test/thread_test.rb +229 -0
- data/test/unique_call_path_test.rb +123 -0
- data/test/yarv_test.rb +56 -0
- metadata +228 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
require 'tmpdir'
|
|
8
|
+
require_relative 'prime'
|
|
9
|
+
|
|
10
|
+
# -- Tests ----
|
|
11
|
+
class PrinterFlatTest < TestCase
|
|
12
|
+
def run_profile
|
|
13
|
+
RubyProf::Profile.profile(:measure_mode => RubyProf::WALL_TIME) do
|
|
14
|
+
run_primes(1000, 5000)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def flat_output_nth_column_values(output, n)
|
|
19
|
+
only_method_calls = output.split("\n").select { |line| line =~ /^\s+\d+/ }
|
|
20
|
+
only_method_calls.collect { |line| line.split(/\s+/)[n] }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def helper_test_flat_string(klass)
|
|
24
|
+
output = StringIO.new
|
|
25
|
+
|
|
26
|
+
printer = klass.new(self.run_profile)
|
|
27
|
+
printer.print(output)
|
|
28
|
+
|
|
29
|
+
assert_match(/Thread ID: -?\d+/i, output.string)
|
|
30
|
+
assert_match(/Fiber ID: -?\d+/i, output.string)
|
|
31
|
+
assert_match(/Total: \d+\.\d+/i, output.string)
|
|
32
|
+
assert_match(/Object#run_primes/i, output.string)
|
|
33
|
+
output.string
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def assert_sorted(array)
|
|
37
|
+
array = array.map(&:to_f) # allow for > 10s times to sort right, since lexographically 4.0 > 10.0
|
|
38
|
+
assert_equal(array, array.sort.reverse)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_flat_string
|
|
42
|
+
output = helper_test_flat_string(RubyProf::FlatPrinter)
|
|
43
|
+
assert_match(/prime.rb/, output)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_flat_result_sorting_by_self_time_is_default
|
|
47
|
+
printer = RubyProf::FlatPrinter.new(self.run_profile)
|
|
48
|
+
|
|
49
|
+
output = StringIO.new
|
|
50
|
+
printer.print(output)
|
|
51
|
+
self_times = flat_output_nth_column_values(output.string, 3)
|
|
52
|
+
|
|
53
|
+
assert_sorted self_times
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_flat_result_sorting
|
|
57
|
+
printer = RubyProf::FlatPrinter.new(self.run_profile)
|
|
58
|
+
|
|
59
|
+
sort_method_with_column_number = {:total_time => 2, :self_time => 3, :wait_time => 4, :children_time => 5}
|
|
60
|
+
|
|
61
|
+
sort_method_with_column_number.each_pair do |sort_method, n|
|
|
62
|
+
output = StringIO.new
|
|
63
|
+
printer.print(output, :sort_method => sort_method)
|
|
64
|
+
|
|
65
|
+
times = flat_output_nth_column_values(output.string, n)
|
|
66
|
+
assert_sorted(times)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_flat_result_max_percent
|
|
71
|
+
printer = RubyProf::FlatPrinter.new(self.run_profile)
|
|
72
|
+
|
|
73
|
+
output = StringIO.new
|
|
74
|
+
printer.print(output, max_percent: 1)
|
|
75
|
+
self_percents = flat_output_nth_column_values(output.string, 1).map(&:to_f)
|
|
76
|
+
|
|
77
|
+
assert self_percents.max < 1
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_flat_result_filter_by_total_time
|
|
81
|
+
printer = RubyProf::FlatPrinter.new(self.run_profile)
|
|
82
|
+
|
|
83
|
+
output = StringIO.new
|
|
84
|
+
printer.print(output, filter_by: :total_time, min_percent: 50)
|
|
85
|
+
total_times = flat_output_nth_column_values(output.string, 2).map(&:to_f)
|
|
86
|
+
|
|
87
|
+
assert (total_times.min / total_times.max) >= 0.5
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_flat_result_filter_by_self_time
|
|
91
|
+
printer = RubyProf::FlatPrinter.new(self.run_profile)
|
|
92
|
+
|
|
93
|
+
output = StringIO.new
|
|
94
|
+
printer.print(output, filter_by: :self_time, min_percent: 0.1)
|
|
95
|
+
self_percents = flat_output_nth_column_values(output.string, 1).map(&:to_f)
|
|
96
|
+
|
|
97
|
+
assert self_percents.min >= 0.1
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'tmpdir'
|
|
7
|
+
require_relative 'prime'
|
|
8
|
+
|
|
9
|
+
# -- Tests ----
|
|
10
|
+
class PrinterGraphHtmlTest < TestCase
|
|
11
|
+
def setup
|
|
12
|
+
super
|
|
13
|
+
# WALL_TIME so we can use sleep in our test and get same measurements on linux and windows
|
|
14
|
+
@result = RubyProf::Profile.profile(measure_mode: RubyProf::WALL_TIME) do
|
|
15
|
+
run_primes(1000, 5000)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def graph_html_output_nth_column_values(output, n)
|
|
20
|
+
only_root_calls = output.split('<tr class="method">')
|
|
21
|
+
only_root_calls.delete_at(0)
|
|
22
|
+
only_root_calls.collect {|line| line.scan(/[\d\.]+/)[n - 1] }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def assert_sorted array
|
|
26
|
+
array = array.map{|n| n.to_f} # allow for > 10s times to sort right, since lexographically 4.0 > 10.0
|
|
27
|
+
assert_equal array, array.sort.reverse, "Array #{array.inspect} is not sorted"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_graph_html_string
|
|
31
|
+
output = ''
|
|
32
|
+
printer = RubyProf::GraphHtmlPrinter.new(@result)
|
|
33
|
+
printer.print(output)
|
|
34
|
+
|
|
35
|
+
assert_match(/<!DOCTYPE html>/i, output)
|
|
36
|
+
assert_match( %r{<th>Total</th>}i, output)
|
|
37
|
+
assert_match(/Object#run_primes/i, output)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_graph_html_result_sorting_by_total_time_is_default
|
|
41
|
+
printer = RubyProf::GraphHtmlPrinter.new(@result)
|
|
42
|
+
printer.print(output = '')
|
|
43
|
+
total_times = graph_html_output_nth_column_values(output, 3)
|
|
44
|
+
|
|
45
|
+
assert_sorted total_times
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_graph_html_result_sorting
|
|
49
|
+
printer = RubyProf::GraphHtmlPrinter.new(@result)
|
|
50
|
+
|
|
51
|
+
sort_method_with_column_number = {:total_time => 3, :self_time => 4, :wait_time => 5, :children_time => 6}
|
|
52
|
+
|
|
53
|
+
sort_method_with_column_number.each_pair do |sort_method, n|
|
|
54
|
+
printer.print(output = '', :sort_method => sort_method)
|
|
55
|
+
times = graph_html_output_nth_column_values(output, n)
|
|
56
|
+
assert_sorted times
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'tmpdir'
|
|
7
|
+
require_relative 'prime'
|
|
8
|
+
|
|
9
|
+
# -- Tests ----
|
|
10
|
+
class PrinterGraphTest < TestCase
|
|
11
|
+
def setup
|
|
12
|
+
super
|
|
13
|
+
# WALL_TIME so we can use sleep in our test and get same measurements on linux and windows
|
|
14
|
+
@result = RubyProf::Profile.profile(measure_mode: RubyProf::WALL_TIME) do
|
|
15
|
+
run_primes(1000, 5000)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def graph_output_nth_column_values(output, n)
|
|
20
|
+
only_root_calls = output.split("\n").select { |line| line =~ /^ +[\d\.]+%/ }
|
|
21
|
+
only_root_calls.collect { |line| line.split(/ +/)[n] }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def assert_sorted(array)
|
|
25
|
+
array = array.map {|n| n.to_f} # allow for > 10s times to sort right, since lexographically 4.0 > 10.0
|
|
26
|
+
assert_equal(array, array.sort.reverse, "Array #{array.inspect} is not sorted")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_graph_results_sorting
|
|
30
|
+
printer = RubyProf::GraphPrinter.new(@result)
|
|
31
|
+
|
|
32
|
+
sort_method_with_column_number = {:total_time => 3, :self_time => 4, :wait_time => 5, :children_time => 6}
|
|
33
|
+
|
|
34
|
+
sort_method_with_column_number.each_pair do |sort_method, n|
|
|
35
|
+
printer.print(output = '', :sort_method => sort_method)
|
|
36
|
+
times = graph_output_nth_column_values(output, n)
|
|
37
|
+
assert_sorted times
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
require 'tmpdir'
|
|
8
|
+
require_relative 'prime'
|
|
9
|
+
|
|
10
|
+
# -- Tests ----
|
|
11
|
+
class PrintersTest < TestCase
|
|
12
|
+
def setup
|
|
13
|
+
super
|
|
14
|
+
# WALL_TIME, PROCESS_TIME, ALLOCATIONS and MEMORY as types of measuremen
|
|
15
|
+
measure_modes = {wall_time: RubyProf::WALL_TIME, process_time: RubyProf::PROCESS_TIME, allocations: RubyProf::ALLOCATIONS, memory: RubyProf::MEMORY}
|
|
16
|
+
|
|
17
|
+
@results = {}
|
|
18
|
+
|
|
19
|
+
measure_modes.each do |key, value|
|
|
20
|
+
@results[key] = RubyProf::Profile.profile(measure_mode: value) do
|
|
21
|
+
run_primes(1000, 5000)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_printers
|
|
27
|
+
output = ENV['SHOW_RUBY_PROF_PRINTER_OUTPUT'] == "1" ? STDOUT : StringIO.new('')
|
|
28
|
+
|
|
29
|
+
printer = RubyProf::CallStackPrinter.new(@results[:wall_time])
|
|
30
|
+
printer.print(output)
|
|
31
|
+
|
|
32
|
+
printer = RubyProf::CallTreePrinter.new(@results[:wall_time])
|
|
33
|
+
printer.print(:path => Dir.tmpdir)
|
|
34
|
+
|
|
35
|
+
printer = RubyProf::FlatPrinter.new(@results[:wall_time])
|
|
36
|
+
printer.print(output)
|
|
37
|
+
|
|
38
|
+
printer = RubyProf::GraphHtmlPrinter.new(@results[:wall_time])
|
|
39
|
+
printer.print(output)
|
|
40
|
+
|
|
41
|
+
printer = RubyProf::GraphPrinter.new(@results[:wall_time])
|
|
42
|
+
printer.print(output)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_print_to_files
|
|
46
|
+
printer = RubyProf::DotPrinter.new(@results[:wall_time])
|
|
47
|
+
File.open("#{Dir.tmpdir}/graph.dot", "w") {|f| printer.print(f)}
|
|
48
|
+
|
|
49
|
+
printer = RubyProf::CallStackPrinter.new(@results[:wall_time])
|
|
50
|
+
File.open("#{Dir.tmpdir}/stack.html", "w") {|f| printer.print(f, :application => "primes")}
|
|
51
|
+
|
|
52
|
+
printer = RubyProf::MultiPrinter.new(@results[:wall_time])
|
|
53
|
+
printer.print(:path => Dir.tmpdir, :profile => "multi", :application => "primes")
|
|
54
|
+
|
|
55
|
+
['graph.dot', 'multi.flat.txt', 'multi.graph.html', "multi.callgrind.out.#{$$}", 'multi.stack.html', 'stack.html'].each do |file_name|
|
|
56
|
+
file_path = File.join(Dir.tmpdir, file_name)
|
|
57
|
+
refute(File.empty?(file_path))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_refuses_io_objects
|
|
62
|
+
p = RubyProf::MultiPrinter.new(@results[:wall_time])
|
|
63
|
+
begin
|
|
64
|
+
p.print(STDOUT)
|
|
65
|
+
flunk "should have raised an ArgumentError"
|
|
66
|
+
rescue ArgumentError => e
|
|
67
|
+
assert_match(/IO/, e.to_s)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_refuses_non_hashes
|
|
72
|
+
p = RubyProf::MultiPrinter.new (@results[:wall_time])
|
|
73
|
+
begin
|
|
74
|
+
p.print([])
|
|
75
|
+
flunk "should have raised an ArgumentError"
|
|
76
|
+
rescue ArgumentError => e
|
|
77
|
+
assert_match(/hash/, e.to_s)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_flat_string
|
|
82
|
+
output = helper_test_flat_string(RubyProf::FlatPrinter)
|
|
83
|
+
assert_match(/prime.rb/, output)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def helper_test_flat_string(klass)
|
|
87
|
+
output = ''
|
|
88
|
+
|
|
89
|
+
printer = klass.new(@results[:wall_time])
|
|
90
|
+
printer.print(output)
|
|
91
|
+
|
|
92
|
+
assert_match(/Thread ID: -?\d+/i, output)
|
|
93
|
+
assert_match(/Fiber ID: -?\d+/i, output)
|
|
94
|
+
assert_match(/Total: \d+\.\d+/i, output)
|
|
95
|
+
assert_match(/Object#run_primes/i, output)
|
|
96
|
+
output
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_graph_html_string
|
|
100
|
+
output = ''
|
|
101
|
+
printer = RubyProf::GraphHtmlPrinter.new(@results[:wall_time])
|
|
102
|
+
printer.print(output)
|
|
103
|
+
|
|
104
|
+
assert_match(/<!DOCTYPE html>/i, output)
|
|
105
|
+
assert_match( %r{<th>Total</th>}i, output)
|
|
106
|
+
assert_match(/Object#run_primes/i, output)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_graph_string
|
|
110
|
+
output = ''
|
|
111
|
+
printer = RubyProf::GraphPrinter.new(@results[:wall_time])
|
|
112
|
+
printer.print(output)
|
|
113
|
+
|
|
114
|
+
assert_match(/Thread ID: -?\d+/i, output)
|
|
115
|
+
assert_match(/Fiber ID: -?\d+/i, output)
|
|
116
|
+
assert_match(/Total Time: \d+\.\d+/i, output)
|
|
117
|
+
assert_match(/Object#run_primes/i, output)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def do_nothing
|
|
121
|
+
start = Time.now
|
|
122
|
+
while(Time.now == start)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_all_with_small_percentiles
|
|
127
|
+
result = RubyProf::Profile.profile do
|
|
128
|
+
sleep 2
|
|
129
|
+
do_nothing
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# RubyProf::CallTreePrinter doesn't "do" a min_percent
|
|
133
|
+
# RubyProf::FlatPrinter only outputs if self time > percent...
|
|
134
|
+
for klass in [RubyProf::GraphPrinter, RubyProf::GraphHtmlPrinter]
|
|
135
|
+
printer = klass.new(result)
|
|
136
|
+
out = ''
|
|
137
|
+
printer.print(out, :min_percent => 0.00000001)
|
|
138
|
+
assert_match(/do_nothing/, out)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def test_print_footer
|
|
143
|
+
results_keys = [:wall_time, :process_time, :allocations, :memory]
|
|
144
|
+
expected_matches = [
|
|
145
|
+
"The percentage of time spent by this method relative to the total time in the entire program.",
|
|
146
|
+
"The total time spent by this method and its children.",
|
|
147
|
+
"The time spent by this method.",
|
|
148
|
+
"The time spent by this method's children.",
|
|
149
|
+
"The percentage of allocations made by this method relative to the total allocations in the entire program.",
|
|
150
|
+
"The total number of allocations made by this method and its children.",
|
|
151
|
+
"The number of allocations made by this method.",
|
|
152
|
+
"The number of allocations made by this method's children.",
|
|
153
|
+
"The percentage of memory used by this method relative to the total memory in the entire program.",
|
|
154
|
+
"The total memory used by this method and its children.",
|
|
155
|
+
"The memory used by this method.",
|
|
156
|
+
"The memory used by this method's children."
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
results_keys.each do |key|
|
|
160
|
+
output = ''
|
|
161
|
+
printer = RubyProf::GraphPrinter.new(@results[key])
|
|
162
|
+
printer.print(output)
|
|
163
|
+
|
|
164
|
+
case key
|
|
165
|
+
when :wall_time, :process_time
|
|
166
|
+
matches = expected_matches[0..3]
|
|
167
|
+
when :allocations
|
|
168
|
+
matches = expected_matches[4..7]
|
|
169
|
+
when :memory
|
|
170
|
+
matches = expected_matches[8..11]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
matches.each do |pattern|
|
|
174
|
+
assert_match(pattern, output)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'stringio'
|
|
7
|
+
|
|
8
|
+
# --- code to be tested ---
|
|
9
|
+
module PRGT
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
def f(n)
|
|
13
|
+
n.times { sleep 0.1 }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def g(n)
|
|
17
|
+
n.times { sleep 0.2 }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def run
|
|
21
|
+
2.times { f(2); g(4) }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# --- expected test output ---
|
|
26
|
+
=begin
|
|
27
|
+
Measure Mode: wall_time
|
|
28
|
+
Thread ID: 1307675084040
|
|
29
|
+
Fiber ID: 1307708787440
|
|
30
|
+
Total Time: 2.0939999999973224
|
|
31
|
+
Sort by:
|
|
32
|
+
|
|
33
|
+
%total %self total self wait child calls name
|
|
34
|
+
--------------------------------------------------------------------------------
|
|
35
|
+
1.657 0.000 0.000 1.657 2/2 Integer#times
|
|
36
|
+
79.13% 0.00% 1.657 0.000 0.000 1.657 2 PRGT#g
|
|
37
|
+
1.657 0.000 0.000 1.657 2/5 Integer#times
|
|
38
|
+
--------------------------------------------------------------------------------
|
|
39
|
+
2.094 2.094 0.000 0.000 12/12 Integer#times
|
|
40
|
+
100.00% 100.00% 2.094 2.094 0.000 0.000 12 Kernel#sleep
|
|
41
|
+
--------------------------------------------------------------------------------
|
|
42
|
+
0.437 0.000 0.000 0.437 2/2 Integer#times
|
|
43
|
+
20.87% 0.00% 0.437 0.000 0.000 0.437 2 PRGT#f
|
|
44
|
+
0.437 0.000 0.000 0.437 2/5 Integer#times
|
|
45
|
+
--------------------------------------------------------------------------------
|
|
46
|
+
0.437 0.000 0.000 0.437 2/5 PRGT#f
|
|
47
|
+
1.657 0.000 0.000 1.657 2/5 PRGT#g
|
|
48
|
+
2.094 0.000 0.000 2.094 1/5 PRGT#run
|
|
49
|
+
100.00% 0.00% 2.094 0.000 0.000 2.094 5 *Integer#times
|
|
50
|
+
2.094 2.094 0.000 0.000 12/12 Kernel#sleep
|
|
51
|
+
1.657 0.000 0.000 1.657 2/2 PRGT#g
|
|
52
|
+
0.437 0.000 0.000 0.437 2/2 PRGT#f
|
|
53
|
+
--------------------------------------------------------------------------------
|
|
54
|
+
2.094 0.000 0.000 2.094 1/1 PrintingRecursiveGraphTest#setup
|
|
55
|
+
100.00% 0.00% 2.094 0.000 0.000 2.094 1 PRGT#run
|
|
56
|
+
2.094 0.000 0.000 2.094 1/5 Integer#times
|
|
57
|
+
--------------------------------------------------------------------------------
|
|
58
|
+
100.00% 0.00% 2.094 0.000 0.000 2.094 1 PrintingRecursiveGraphTest#setup
|
|
59
|
+
2.094 0.000 0.000 2.094 1/1 PRGT#run
|
|
60
|
+
|
|
61
|
+
* indicates recursively called methods
|
|
62
|
+
=end
|
|
63
|
+
|
|
64
|
+
class PrintingRecursiveGraphTest < TestCase
|
|
65
|
+
def setup
|
|
66
|
+
super
|
|
67
|
+
# WALL_TIME so we can use sleep in our test and get same measurements on linux and windows
|
|
68
|
+
@result = RubyProf::Profile.profile(measure_mode: RubyProf::WALL_TIME) do
|
|
69
|
+
PRGT.run
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_printing_rescursive_graph
|
|
74
|
+
printer = RubyProf::GraphPrinter.new(@result)
|
|
75
|
+
buffer = ''
|
|
76
|
+
printer.print(StringIO.new(buffer))
|
|
77
|
+
puts buffer if ENV['SHOW_RUBY_PROF_PRINTER_OUTPUT'] == "1"
|
|
78
|
+
|
|
79
|
+
refute_nil(buffer)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
require_relative './call_tree_builder'
|
|
6
|
+
|
|
7
|
+
class ProfileTest < TestCase
|
|
8
|
+
def test_measure_mode
|
|
9
|
+
profile = RubyProf::Profile.new(:measure_mode => RubyProf::PROCESS_TIME)
|
|
10
|
+
assert_equal(RubyProf::PROCESS_TIME, profile.measure_mode)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_measure_mode_string
|
|
14
|
+
profile = RubyProf::Profile.new(:measure_mode => RubyProf::PROCESS_TIME)
|
|
15
|
+
assert_equal("process_time", profile.measure_mode_string)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_add_thread
|
|
19
|
+
profile = RubyProf::Profile.new
|
|
20
|
+
assert_empty(profile.threads)
|
|
21
|
+
|
|
22
|
+
method_info = RubyProf::MethodInfo.new(Array, :size)
|
|
23
|
+
call_tree = RubyProf::CallTree.new(method_info)
|
|
24
|
+
thread = RubyProf::Thread.new(call_tree, Thread.current, Fiber.current)
|
|
25
|
+
|
|
26
|
+
profile.add_thread(thread)
|
|
27
|
+
assert_equal(1, profile.threads.size)
|
|
28
|
+
assert(thread.equal?(profile.threads.first))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_add_threads
|
|
32
|
+
call_tree_1 = create_call_tree_1
|
|
33
|
+
ruby_thread_1 = Thread.new { }
|
|
34
|
+
thread_1 = RubyProf::Thread.new(call_tree_1, ruby_thread_1, Fiber.current)
|
|
35
|
+
|
|
36
|
+
call_tree_2 = create_call_tree_2
|
|
37
|
+
ruby_thread_2 = Thread.new { }
|
|
38
|
+
thread_2 = RubyProf::Thread.new(call_tree_2, ruby_thread_2, Fiber.current)
|
|
39
|
+
|
|
40
|
+
profile = RubyProf::Profile.new
|
|
41
|
+
profile.add_thread(thread_1)
|
|
42
|
+
profile.add_thread(thread_2)
|
|
43
|
+
assert_equal(1, profile.threads.count)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_add_fibers
|
|
47
|
+
call_tree_1 = create_call_tree_1
|
|
48
|
+
fiber_1 = Fiber.new { }
|
|
49
|
+
thread_1 = RubyProf::Thread.new(call_tree_1, Thread.current, fiber_1)
|
|
50
|
+
|
|
51
|
+
call_tree_2 = create_call_tree_2
|
|
52
|
+
fiber_2 = Fiber.new { }
|
|
53
|
+
thread_2 = RubyProf::Thread.new(call_tree_2, Thread.current, fiber_2)
|
|
54
|
+
|
|
55
|
+
profile = RubyProf::Profile.new
|
|
56
|
+
profile.add_thread(thread_1)
|
|
57
|
+
profile.add_thread(thread_2)
|
|
58
|
+
assert_equal(2, profile.threads.count)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_remove_thread
|
|
62
|
+
profile = RubyProf::Profile.new
|
|
63
|
+
assert_empty(profile.threads)
|
|
64
|
+
|
|
65
|
+
method_info = RubyProf::MethodInfo.new(Array, :size)
|
|
66
|
+
call_tree = RubyProf::CallTree.new(method_info)
|
|
67
|
+
thread = RubyProf::Thread.new(call_tree, Thread.current, Fiber.current)
|
|
68
|
+
|
|
69
|
+
profile.add_thread(thread)
|
|
70
|
+
assert_equal(1, profile.threads.size)
|
|
71
|
+
assert(thread.equal?(profile.threads.first))
|
|
72
|
+
|
|
73
|
+
removed = profile.remove_thread(thread)
|
|
74
|
+
assert_equal(0, profile.threads.size)
|
|
75
|
+
assert(removed.equal?(thread))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_merge
|
|
79
|
+
call_tree_1 = create_call_tree_1
|
|
80
|
+
fiber_1 = Thread.new { }
|
|
81
|
+
thread_1 = RubyProf::Thread.new(call_tree_1, Thread.current, fiber_1)
|
|
82
|
+
|
|
83
|
+
call_tree_2 = create_call_tree_2
|
|
84
|
+
fiber_2 = Thread.new { }
|
|
85
|
+
thread_2 = RubyProf::Thread.new(call_tree_2, Thread.current, fiber_2)
|
|
86
|
+
|
|
87
|
+
profile = RubyProf::Profile.new
|
|
88
|
+
profile.add_thread(thread_1)
|
|
89
|
+
profile.add_thread(thread_2)
|
|
90
|
+
|
|
91
|
+
profile.merge!
|
|
92
|
+
assert_equal(1, profile.threads.count)
|
|
93
|
+
|
|
94
|
+
assert_equal(thread_1, profile.threads.first)
|
|
95
|
+
|
|
96
|
+
assert_in_delta(11.6, thread_1.call_tree.total_time, 0.00001)
|
|
97
|
+
assert_in_delta(0, thread_1.call_tree.self_time, 0.00001)
|
|
98
|
+
assert_in_delta(0.0, thread_1.call_tree.wait_time, 0.00001)
|
|
99
|
+
assert_in_delta(11.6, thread_1.call_tree.children_time, 0.00001)
|
|
100
|
+
end
|
|
101
|
+
end
|
data/test/rack_test.rb
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
|
5
|
+
|
|
6
|
+
class FakeRackApp
|
|
7
|
+
def call(env)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Rack
|
|
12
|
+
class Request
|
|
13
|
+
def initialize(env)
|
|
14
|
+
if env == :fake_env
|
|
15
|
+
@env = {}
|
|
16
|
+
else
|
|
17
|
+
@env = env
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def path
|
|
22
|
+
@env[:path] || '/path/to/resource.json'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class RackTest < TestCase
|
|
28
|
+
def test_create_print_path
|
|
29
|
+
path = Dir.mktmpdir
|
|
30
|
+
Dir.delete(path)
|
|
31
|
+
|
|
32
|
+
Rack::RubyProf.new(FakeRackApp.new, :path => path)
|
|
33
|
+
|
|
34
|
+
assert(Dir.exist?(path))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_create_profile_reports
|
|
38
|
+
path = Dir.mktmpdir
|
|
39
|
+
|
|
40
|
+
adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path)
|
|
41
|
+
|
|
42
|
+
adapter.call(:fake_env)
|
|
43
|
+
|
|
44
|
+
%w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
|
|
45
|
+
file_path = ::File.join(path, "path-to-resource.json-#{base_name}")
|
|
46
|
+
assert(File.exist?(file_path))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_skip_paths
|
|
51
|
+
path = Dir.mktmpdir
|
|
52
|
+
|
|
53
|
+
adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :skip_paths => [%r{\.json$}])
|
|
54
|
+
|
|
55
|
+
adapter.call(:fake_env)
|
|
56
|
+
|
|
57
|
+
%w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
|
|
58
|
+
file_path = ::File.join(path, "path-to-resource.json-#{base_name}")
|
|
59
|
+
assert(!File.exist?(file_path))
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_only_paths
|
|
64
|
+
path = Dir.mktmpdir
|
|
65
|
+
|
|
66
|
+
adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :only_paths => [%r{\.json$}])
|
|
67
|
+
|
|
68
|
+
adapter.call({path: '/path/to/resource.json'})
|
|
69
|
+
|
|
70
|
+
%w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
|
|
71
|
+
file_path = ::File.join(path, "path-to-resource.json-#{base_name}")
|
|
72
|
+
assert(File.exist?(file_path))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
adapter.call({path: '/path/to/resource.html'})
|
|
76
|
+
%w(flat.txt graph.txt graph.html call_stack.html).each do |base_name|
|
|
77
|
+
file_path = ::File.join(path, "path-to-resource.html-#{base_name}")
|
|
78
|
+
assert(!File.exist?(file_path))
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_allows_lazy_filename_setting
|
|
83
|
+
path = Dir.mktmpdir
|
|
84
|
+
|
|
85
|
+
printer = {::RubyProf::FlatPrinter => lambda { 'dynamic.txt' }}
|
|
86
|
+
adapter = Rack::RubyProf.new(FakeRackApp.new, :path => path, :printers => printer)
|
|
87
|
+
|
|
88
|
+
adapter.call(:fake_env)
|
|
89
|
+
|
|
90
|
+
file_path = ::File.join(path, 'path-to-resource.json-dynamic.txt')
|
|
91
|
+
assert(File.exist?(file_path))
|
|
92
|
+
end
|
|
93
|
+
end
|