ruby-prof 0.8.1-x86-mingw32 → 0.11.0.rc1-x86-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 (119) hide show
  1. data/CHANGES +89 -13
  2. data/LICENSE +4 -3
  3. data/{README → README.rdoc} +155 -162
  4. data/Rakefile +50 -123
  5. data/bin/ruby-prof +86 -47
  6. data/examples/empty.png +0 -0
  7. data/examples/graph.dot +106 -0
  8. data/examples/graph.png +0 -0
  9. data/examples/minus.png +0 -0
  10. data/examples/multi.flat.txt +23 -0
  11. data/examples/multi.graph.html +906 -0
  12. data/examples/multi.grind.dat +194 -0
  13. data/examples/multi.stack.html +573 -0
  14. data/examples/plus.png +0 -0
  15. data/examples/stack.html +573 -0
  16. data/ext/ruby_prof/extconf.rb +53 -0
  17. data/ext/ruby_prof/rp_call_info.c +369 -0
  18. data/ext/ruby_prof/rp_call_info.h +46 -0
  19. data/ext/ruby_prof/rp_measure.c +48 -0
  20. data/ext/ruby_prof/rp_measure.h +45 -0
  21. data/ext/ruby_prof/rp_measure_allocations.c +86 -0
  22. data/ext/ruby_prof/rp_measure_cpu_time.c +112 -0
  23. data/ext/ruby_prof/rp_measure_gc_runs.c +87 -0
  24. data/ext/ruby_prof/rp_measure_gc_time.c +73 -0
  25. data/ext/ruby_prof/rp_measure_memory.c +81 -0
  26. data/ext/ruby_prof/rp_measure_process_time.c +71 -0
  27. data/ext/ruby_prof/rp_measure_wall_time.c +42 -0
  28. data/ext/ruby_prof/rp_method.c +363 -0
  29. data/ext/ruby_prof/rp_method.h +55 -0
  30. data/ext/ruby_prof/rp_stack.c +61 -0
  31. data/ext/ruby_prof/rp_stack.h +40 -0
  32. data/ext/ruby_prof/rp_thread.c +113 -0
  33. data/ext/ruby_prof/rp_thread.h +20 -0
  34. data/ext/ruby_prof/ruby_prof.c +332 -1377
  35. data/ext/ruby_prof/ruby_prof.h +54 -188
  36. data/ext/ruby_prof/version.h +6 -3
  37. data/lib/1.8/ruby_prof.so +0 -0
  38. data/lib/1.9/ruby_prof.exp +0 -0
  39. data/lib/1.9/ruby_prof.ilk +0 -0
  40. data/lib/1.9/ruby_prof.lib +0 -0
  41. data/lib/1.9/ruby_prof.pdb +0 -0
  42. data/lib/1.9/ruby_prof.so +0 -0
  43. data/lib/ruby-prof.rb +32 -18
  44. data/lib/ruby-prof/abstract_printer.rb +15 -5
  45. data/lib/ruby-prof/aggregate_call_info.rb +11 -3
  46. data/lib/ruby-prof/call_info.rb +68 -1
  47. data/lib/ruby-prof/call_stack_printer.rb +775 -0
  48. data/lib/ruby-prof/call_tree_printer.rb +17 -9
  49. data/lib/ruby-prof/compatibility.rb +134 -0
  50. data/lib/ruby-prof/dot_printer.rb +152 -0
  51. data/lib/ruby-prof/empty.png +0 -0
  52. data/lib/ruby-prof/flat_printer.rb +23 -24
  53. data/lib/ruby-prof/flat_printer_with_line_numbers.rb +17 -21
  54. data/lib/ruby-prof/graph_html_printer.rb +69 -39
  55. data/lib/ruby-prof/graph_printer.rb +35 -35
  56. data/lib/ruby-prof/method_info.rb +26 -4
  57. data/lib/ruby-prof/minus.png +0 -0
  58. data/lib/ruby-prof/multi_printer.rb +56 -0
  59. data/lib/ruby-prof/plus.png +0 -0
  60. data/lib/ruby-prof/profile.rb +72 -0
  61. data/lib/ruby-prof/rack.rb +31 -0
  62. data/lib/ruby-prof/symbol_to_proc.rb +3 -1
  63. data/lib/ruby-prof/task.rb +20 -19
  64. data/lib/ruby-prof/test.rb +5 -3
  65. data/lib/ruby_prof.exp +0 -0
  66. data/lib/ruby_prof.ilk +0 -0
  67. data/lib/ruby_prof.lib +0 -0
  68. data/lib/ruby_prof.pdb +0 -0
  69. data/lib/ruby_prof.so +0 -0
  70. data/lib/unprof.rb +2 -0
  71. data/test/aggregate_test.rb +29 -14
  72. data/test/basic_test.rb +3 -251
  73. data/test/bug_test.rb +6 -0
  74. data/test/duplicate_names_test.rb +4 -4
  75. data/test/dynamic_method_test.rb +61 -0
  76. data/test/enumerable_test.rb +4 -4
  77. data/test/exceptions_test.rb +6 -5
  78. data/test/exclude_threads_test.rb +47 -47
  79. data/test/exec_test.rb +5 -5
  80. data/test/line_number_test.rb +16 -16
  81. data/test/measure_allocations_test.rb +25 -0
  82. data/test/measure_cpu_time_test.rb +212 -0
  83. data/test/measure_gc_runs_test.rb +29 -0
  84. data/test/measure_gc_time_test.rb +29 -0
  85. data/test/measure_memory_test.rb +36 -0
  86. data/test/measure_process_time_test.rb +205 -0
  87. data/test/measure_wall_time_test.rb +209 -0
  88. data/test/method_elimination_test.rb +74 -0
  89. data/test/module_test.rb +12 -21
  90. data/test/multi_printer_test.rb +81 -0
  91. data/test/no_method_class_test.rb +5 -3
  92. data/test/prime.rb +7 -10
  93. data/test/prime_test.rb +3 -3
  94. data/test/printers_test.rb +180 -54
  95. data/test/recursive_test.rb +34 -72
  96. data/test/singleton_test.rb +5 -4
  97. data/test/stack_printer_test.rb +73 -0
  98. data/test/stack_test.rb +7 -7
  99. data/test/start_stop_test.rb +23 -6
  100. data/test/test_helper.rb +81 -0
  101. data/test/test_suite.rb +35 -21
  102. data/test/thread_test.rb +40 -39
  103. data/test/unique_call_path_test.rb +6 -6
  104. metadata +106 -51
  105. data/ext/ruby_prof/measure_allocations.h +0 -58
  106. data/ext/ruby_prof/measure_cpu_time.h +0 -152
  107. data/ext/ruby_prof/measure_gc_runs.h +0 -76
  108. data/ext/ruby_prof/measure_gc_time.h +0 -57
  109. data/ext/ruby_prof/measure_memory.h +0 -101
  110. data/ext/ruby_prof/measure_process_time.h +0 -52
  111. data/ext/ruby_prof/measure_wall_time.h +0 -53
  112. data/ext/ruby_prof/mingw/Rakefile +0 -23
  113. data/ext/ruby_prof/mingw/build.rake +0 -38
  114. data/rails/environment/profile.rb +0 -24
  115. data/rails/example/example_test.rb +0 -9
  116. data/rails/profile_test_helper.rb +0 -21
  117. data/test/current_failures_windows +0 -8
  118. data/test/measurement_test.rb +0 -121
  119. data/test/ruby-prof-bin +0 -20
Binary file
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ module RubyProf
4
+ # Helper class to simplify printing profiles of several types from
5
+ # one profiling run. Currently prints a flat profile, a callgrind
6
+ # profile, a call stack profile and a graph profile.
7
+ class MultiPrinter
8
+ def initialize(result)
9
+ @stack_printer = CallStackPrinter.new(result)
10
+ @graph_printer = GraphHtmlPrinter.new(result)
11
+ @tree_printer = CallTreePrinter.new(result)
12
+ @flat_printer = FlatPrinter.new(result)
13
+ end
14
+
15
+ # create profile files under options[:path] or the current
16
+ # directory. options[:profile] is used as the base name for the
17
+ # pofile file, defaults to "profile".
18
+ def print(options)
19
+ @profile = options.delete(:profile) || "profile"
20
+ @directory = options.delete(:path) || File.expand_path(".")
21
+ File.open(stack_profile, "w") do |f|
22
+ @stack_printer.print(f, options.merge(:graph => "#{@profile}.graph.html"))
23
+ end
24
+ File.open(graph_profile, "w") do |f|
25
+ @graph_printer.print(f, options)
26
+ end
27
+ File.open(tree_profile, "w") do |f|
28
+ @tree_printer.print(f, options)
29
+ end
30
+ File.open(flat_profile, "w") do |f|
31
+ @flat_printer.print(f, options)
32
+ end
33
+ end
34
+
35
+ # the name of the call stack profile file
36
+ def stack_profile
37
+ "#{@directory}/#{@profile}.stack.html"
38
+ end
39
+
40
+ # the name of the graph profile file
41
+ def graph_profile
42
+ "#{@directory}/#{@profile}.graph.html"
43
+ end
44
+
45
+ # the name of the callgrind profile file
46
+ def tree_profile
47
+ "#{@directory}/#{@profile}.grind.dat"
48
+ end
49
+
50
+ # the name of the flat profile file
51
+ def flat_profile
52
+ "#{@directory}/#{@profile}.flat.txt"
53
+ end
54
+
55
+ end
56
+ end
Binary file
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+
3
+ require 'set'
4
+ module RubyProf
5
+ class Profile
6
+ # this method gets called internally when profiling is stopped.
7
+ # it determines for each call_info whether it is minimal: a
8
+ # call_info is minimal in a call tree if the call_info is not a
9
+ # descendant of a call_info of the same method
10
+ def compute_minimality
11
+ threads.each do |threadid, method_infos|
12
+ root_methods = method_infos.select{|mi| mi.root?}
13
+ root_methods.each do |mi|
14
+ mi.call_infos.select{|ci| ci.root?}.each do |call_info_root|
15
+ call_info_root.compute_minimality(Set.new)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # eliminate some calls from the graph by merging the information into callers.
22
+ # matchers can be a list of strings or regular expressions or the name of a file containing regexps.
23
+ def eliminate_methods!(matchers)
24
+ matchers = read_regexps_from_file(matchers) if matchers.is_a?(String)
25
+ eliminated = []
26
+ threads.each do |thread_id, methods|
27
+ matchers.each{ |matcher| eliminated.concat(eliminate_methods(methods, matcher)) }
28
+ end
29
+ compute_minimality # is this really necessary?
30
+ eliminated
31
+ end
32
+
33
+ def dump
34
+ threads.each do |thread_id, methods|
35
+ $stderr.puts "Call Info Dump for thread id #{thread_id}"
36
+ methods.each do |method_info|
37
+ $stderr.puts method_info.dump
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # read regexps from file
45
+ def read_regexps_from_file(file_name)
46
+ matchers = []
47
+ File.open(matchers).each_line do |l|
48
+ next if (l =~ /^(#.*|\s*)$/) # emtpy lines and lines starting with #
49
+ matchers << Regexp.new(l.strip)
50
+ end
51
+ end
52
+
53
+ # eliminate methods matching matcher
54
+ def eliminate_methods(methods, matcher)
55
+ eliminated = []
56
+ i = 0
57
+ while i < methods.size
58
+ method_info = methods[i]
59
+ method_name = method_info.full_name
60
+ if matcher === method_name
61
+ raise "can't eliminate root method" if method_info.root?
62
+ eliminated << methods.delete_at(i)
63
+ method_info.eliminate!
64
+ else
65
+ i += 1
66
+ end
67
+ end
68
+ eliminated
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module Rack
4
+ class RubyProf
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ ::RubyProf.start
11
+ result = @app.call(env)
12
+ data = ::RubyProf.stop
13
+
14
+ print(data)
15
+ result
16
+ end
17
+
18
+ def print(data)
19
+ require 'tmpdir' # late require so we load on demand only
20
+ printers = {::RubyProf::FlatPrinter => ::File.join(Dir.tmpdir, 'profile.txt'),
21
+ ::RubyProf::GraphHtmlPrinter => ::File.join(Dir.tmpdir, 'profile.html')}
22
+
23
+ printers.each do |printer_klass, file_name|
24
+ printer = printer_klass.new(data)
25
+ ::File.open(file_name, 'wb') do |file|
26
+ printer.print(file, :min_percent => 0.00000001 )
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  unless (:a.respond_to?(:to_proc))
2
4
  class Symbol
3
5
  def to_proc
@@ -5,4 +7,4 @@ unless (:a.respond_to?(:to_proc))
5
7
  end
6
8
  end
7
9
  end
8
-
10
+
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: utf-8
2
3
 
3
4
  require 'rake'
4
5
  require 'rake/testtask'
@@ -15,7 +16,7 @@ module RubyProf
15
16
  #
16
17
  # ruby-prof specific options include:
17
18
  #
18
- # output_dir - For each file specified an output
19
+ # output_dir - For each file specified an output
19
20
  # file with profile information will be
20
21
  # written to the output directory.
21
22
  # By default, the output directory is
@@ -29,9 +30,9 @@ module RubyProf
29
30
  # will not be written out.
30
31
  #
31
32
  # Example:
32
- #
33
+ #
33
34
  # require 'ruby-prof/task'
34
- #
35
+ #
35
36
  # RubyProf::ProfileTask.new do |t|
36
37
  # t.test_files = FileList['test/test*.rb']
37
38
  # t.output_dir = "c:/temp"
@@ -55,37 +56,37 @@ module RubyProf
55
56
  # rake profile TEST=just_one_file.rb # run just one test file.
56
57
  # rake profile TESTOPTS="-v" # run in verbose mode
57
58
  # rake profile TESTOPTS="--runner=fox" # use the fox test runner
58
-
59
+
59
60
  class ProfileTask < Rake::TestTask
60
- attr_accessor :output_dir
61
- attr_accessor :min_percent
61
+ attr_accessor :output_dir
62
+ attr_accessor :min_percent
62
63
  attr_accessor :printer
63
-
64
+
64
65
  def initialize(name = :profile)
65
66
  super(name)
66
67
  end
67
-
68
+
68
69
  # Create the tasks defined by this task lib.
69
70
  def define
70
71
  lib_path = @libs.join(File::PATH_SEPARATOR)
71
72
  desc "Profile" + (@name==:profile ? "" : " for #{@name}")
72
-
73
+
73
74
  task @name do
74
75
  create_output_directory
75
-
76
+
76
77
  @ruby_opts.unshift( "-I#{lib_path}" )
77
78
  @ruby_opts.unshift( "-w" ) if @warning
78
79
  @ruby_opts.push("-S ruby-prof")
79
80
  @ruby_opts.push("--printer #{@printer}")
80
81
  @ruby_opts.push("--min_percent #{@min_percent}")
81
82
 
82
- file_list.each do |file_path|
83
+ file_list.each do |file_path|
83
84
  run_script(file_path)
84
85
  end
85
86
  end
86
87
  self
87
88
  end
88
-
89
+
89
90
  # Run script
90
91
  def run_script(script_path)
91
92
  run_code = ''
@@ -99,14 +100,14 @@ module RubyProf
99
100
  else
100
101
  file_name += ".txt"
101
102
  end
102
-
103
+
103
104
  output_file_path = File.join(output_directory, file_name)
104
-
105
- command_line = @ruby_opts.join(" ") +
105
+
106
+ command_line = @ruby_opts.join(" ") +
106
107
  " --file=" + output_file_path +
107
108
  " " + script_path
108
109
 
109
- puts "ruby " + command_line
110
+ puts "ruby " + command_line
110
111
  # We have to catch the exeption to continue on. However,
111
112
  # the error message will have been output to STDERR
112
113
  # already by the time we get here so we don't have to
@@ -125,7 +126,7 @@ module RubyProf
125
126
  def output_directory
126
127
  File.expand_path(@output_dir)
127
128
  end
128
-
129
+
129
130
  def create_output_directory
130
131
  if not File.exist?(output_directory)
131
132
  Dir.mkdir(output_directory)
@@ -138,9 +139,9 @@ module RubyProf
138
139
  FileUtils.rm(files)
139
140
  end
140
141
  end
141
-
142
+
142
143
  def option_list # :nodoc:
143
144
  ENV['OPTIONS'] || @options.join(" ") || ""
144
145
  end
145
146
  end
146
- end
147
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  # Now load ruby-prof and away we go
2
4
  require 'fileutils'
3
5
  require 'ruby-prof'
@@ -15,7 +17,7 @@ module RubyProf
15
17
  def output_dir
16
18
  PROFILE_OPTIONS[:output_dir]
17
19
  end
18
-
20
+
19
21
  def run(result)
20
22
  return if @method_name.to_s == "default_test"
21
23
 
@@ -108,7 +110,7 @@ module RubyProf
108
110
  def report_profile(data, measure_mode)
109
111
  PROFILE_OPTIONS[:printers].each do |printer_klass|
110
112
  printer = printer_klass.new(data)
111
-
113
+
112
114
  # Makes sure the output directory exits
113
115
  FileUtils.mkdir_p(output_dir)
114
116
 
@@ -145,4 +147,4 @@ module RubyProf
145
147
  end
146
148
  end
147
149
  end
148
- end
150
+ end
data/lib/ruby_prof.exp ADDED
Binary file
data/lib/ruby_prof.ilk ADDED
Binary file
data/lib/ruby_prof.lib ADDED
Binary file
data/lib/ruby_prof.pdb ADDED
Binary file
data/lib/ruby_prof.so ADDED
Binary file
data/lib/unprof.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require "ruby-prof"
2
4
 
3
5
  at_exit {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: UTF-8
2
3
 
3
- require 'test/unit'
4
- require 'ruby-prof'
4
+ require File.expand_path('../test_helper', __FILE__)
5
5
 
6
6
  # Test data
7
7
  # A B C
@@ -14,7 +14,7 @@ class AggClass
14
14
  def z
15
15
  sleep 1
16
16
  end
17
-
17
+
18
18
  def a
19
19
  z
20
20
  end
@@ -24,7 +24,7 @@ class AggClass
24
24
  end
25
25
 
26
26
  def c
27
- a
27
+ a
28
28
  end
29
29
  end
30
30
 
@@ -34,6 +34,21 @@ class AggregateTest < Test::Unit::TestCase
34
34
  RubyProf::measure_mode = RubyProf::WALL_TIME
35
35
  end
36
36
 
37
+ def test_all_call_infos_are_minimal_as_there_is_no_recursion
38
+ c1 = AggClass.new
39
+ result = RubyProf.profile do
40
+ c1.a
41
+ c1.b
42
+ c1.c
43
+ end
44
+ methods = result.threads.values.first.sort.reverse
45
+ methods.each do |m|
46
+ m.call_infos.each do |ci|
47
+ assert ci.minimal?, "#{ci.call_sequence} should be minimal in the call tree"
48
+ end
49
+ end
50
+ end
51
+
37
52
  def test_call_infos
38
53
  c1 = AggClass.new
39
54
  result = RubyProf.profile do
@@ -43,15 +58,15 @@ class AggregateTest < Test::Unit::TestCase
43
58
  end
44
59
 
45
60
  methods = result.threads.values.first.sort.reverse
46
- method = methods.find {|method| method.full_name == 'AggClass#z'}
61
+ method = methods.find {|meth| meth.full_name == 'AggClass#z'}
47
62
 
48
63
  # Check AggClass#z
49
64
  assert_equal('AggClass#z', method.full_name)
50
65
  assert_equal(3, method.called)
51
- assert_in_delta(3, method.total_time, 0.01)
52
- assert_in_delta(0, method.wait_time, 0.01)
53
- assert_in_delta(0, method.self_time, 0.01)
54
- assert_in_delta(3, method.children_time, 0.01)
66
+ assert_in_delta(3, method.total_time, 0.05)
67
+ assert_in_delta(0, method.wait_time, 0.05)
68
+ assert_in_delta(0, method.self_time, 0.05)
69
+ assert_in_delta(3, method.children_time, 0.05)
55
70
  assert_equal(3, method.call_infos.length)
56
71
 
57
72
  call_info = method.call_infos[0]
@@ -76,7 +91,7 @@ class AggregateTest < Test::Unit::TestCase
76
91
  end
77
92
 
78
93
  methods = result.threads.values.first.sort.reverse
79
- method = methods.find {|method| method.full_name == 'AggClass#z'}
94
+ method = methods.find {|meth| meth.full_name == 'AggClass#z'}
80
95
 
81
96
  # Check AggClass#z
82
97
  assert_equal('AggClass#z', method.full_name)
@@ -87,7 +102,7 @@ class AggregateTest < Test::Unit::TestCase
87
102
  call_info = call_infos.first
88
103
  assert_equal('AggClass#a', call_info.parent.target.full_name)
89
104
  assert_in_delta(3, call_info.total_time, 0.05)
90
- assert_in_delta(0, call_info.wait_time, 0.01)
105
+ assert_in_delta(0, call_info.wait_time, 0.05)
91
106
  assert_in_delta(0, call_info.self_time, 0.05)
92
107
  assert_in_delta(3, call_info.children_time, 0.05)
93
108
  assert_equal(3, call_info.called)
@@ -102,7 +117,7 @@ class AggregateTest < Test::Unit::TestCase
102
117
  end
103
118
 
104
119
  methods = result.threads.values.first.sort.reverse
105
- method = methods.find {|method| method.full_name == 'AggClass#a'}
120
+ method = methods.find {|meth| meth.full_name == 'AggClass#a'}
106
121
 
107
122
  # Check AggClass#a
108
123
  assert_equal('AggClass#a', method.full_name)
@@ -113,9 +128,9 @@ class AggregateTest < Test::Unit::TestCase
113
128
  call_info = call_infos.first
114
129
  assert_equal('AggClass#z', call_info.target.full_name)
115
130
  assert_in_delta(3, call_info.total_time, 0.05)
116
- assert_in_delta(0, call_info.wait_time, 0.01)
131
+ assert_in_delta(0, call_info.wait_time, 0.05)
117
132
  assert_in_delta(0, call_info.self_time, 0.05)
118
133
  assert_in_delta(3, call_info.children_time, 0.05)
119
134
  assert_equal(3, call_info.called)
120
135
  end
121
- end
136
+ end