ruby-prof 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,24 @@
1
+ 0.7.1 (2008-11-28)
2
+ ========================
3
+ * Added new AggregateCallInfo class for printers to
4
+ make results easier to read. Take this call sequence
5
+ for example:
6
+
7
+ A B C
8
+ | | |
9
+ Z A A
10
+ | |
11
+ Z Z
12
+
13
+ By default, ruby-prof will show that Z was called by 3 separate
14
+ instances of A. In an IDE that is helpful but in a text report
15
+ it is not since it makes the report much harder to read.
16
+ As a result, printers now aggregate together callers (and children),
17
+ matching ruby-prof's output from versions prior to 0.7.0.
18
+
19
+ * Fixes for supporting x86_64 machines (Matt Sanford)
20
+
21
+
1
22
  0.7.0 (2008-11-04)
2
23
  ========================
3
24
 
data/README CHANGED
@@ -33,7 +33,9 @@ The easiest way to install ruby-prof is by using Ruby Gems. To install:
33
33
  <tt>gem install ruby-prof</tt>
34
34
 
35
35
  If you are running Windows, make sure to install the Win32 RubyGem which
36
- includes a pre-built binary.
36
+ includes a pre-built binary. Due to a bug in ruby-gems, you cannot
37
+ install the gem to a path that contains spaces
38
+ (see http://rubyforge.org/tracker/?func=detail&aid=23003&group_id=126&atid=577).
37
39
 
38
40
  ruby-prof is also available as a tarred gzip archive and zip archive.
39
41
 
data/Rakefile CHANGED
@@ -117,7 +117,7 @@ task :default => :package
117
117
  desc 'Run the ruby-prof test suite'
118
118
  Rake::TestTask.new do |t|
119
119
  t.libs += %w(lib ext test)
120
- t.test_files = Dir['test/*_test.rb'] - %w(test/profile_unit_test.rb)
120
+ t.test_files = Dir['test/test_suite.rb']
121
121
  t.verbose = true
122
122
  t.warning = true
123
123
  end
@@ -26,7 +26,7 @@
26
26
 
27
27
  #include <ruby.h>
28
28
 
29
- #if defined(_WIN32) || (defined(__GNUC__) && (defined(__i386__) || defined(__powerpc__) || defined(__ppc__)))
29
+ #if defined(_WIN32) || (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || defined(__ppc__)))
30
30
  #define MEASURE_CPU_TIME 2
31
31
 
32
32
  static unsigned long long cpu_frequency;
@@ -36,7 +36,7 @@ static unsigned long long cpu_frequency;
36
36
  static prof_measure_t
37
37
  measure_cpu_time()
38
38
  {
39
- #if defined(__i386__)
39
+ #if defined(__i386__) || defined(__x86_64__)
40
40
  unsigned long long x;
41
41
  __asm__ __volatile__ ("rdtsc" : "=A" (x));
42
42
  return x;
data/ext/mingw/Rakefile CHANGED
@@ -15,7 +15,7 @@ task :install do
15
15
  # RUBYLIBDIR=#{dest_path}
16
16
 
17
17
  dest_path = ENV['RUBYLIBDIR']
18
-
18
+
19
19
  # Copy the extension
20
20
  cp(EXTENSION_NAME, dest_path)
21
21
  end
data/ext/version.h CHANGED
@@ -1,4 +1,4 @@
1
- #define RUBY_PROF_VERSION "0.7.0"
1
+ #define RUBY_PROF_VERSION "0.7.1"
2
2
  #define RUBY_PROF_VERSION_MAJ 0
3
3
  #define RUBY_PROF_VERSION_MIN 7
4
- #define RUBY_PROF_VERSION_MIC 0
4
+ #define RUBY_PROF_VERSION_MIC 1
data/lib/ruby-prof.rb CHANGED
@@ -2,6 +2,7 @@ require "ruby_prof.so"
2
2
 
3
3
  require "ruby-prof/method_info"
4
4
  require "ruby-prof/call_info"
5
+ require "ruby-prof/aggregate_call_info"
5
6
  require "ruby-prof/flat_printer"
6
7
  require "ruby-prof/graph_printer"
7
8
  require "ruby-prof/graph_html_printer"
@@ -37,6 +37,5 @@ module RubyProf
37
37
  end
38
38
  name
39
39
  end
40
-
41
40
  end
42
41
  end
@@ -0,0 +1,62 @@
1
+ module RubyProf
2
+ class AggregateCallInfo
3
+ attr_reader :call_infos
4
+ def initialize(call_infos)
5
+ if call_infos.length == 0
6
+ raise(ArgumentError, "Must specify at least one call info.")
7
+ end
8
+ @call_infos = call_infos
9
+ end
10
+
11
+ def target
12
+ call_infos.first.target
13
+ end
14
+
15
+ def parent
16
+ call_infos.first.parent
17
+ end
18
+
19
+ def line
20
+ call_infos.first.line
21
+ end
22
+
23
+ def children
24
+ call_infos.inject(Array.new) do |result, call_info|
25
+ result.concat(call_info.children)
26
+ end
27
+ end
28
+
29
+ def total_time
30
+ aggregate(:total_time)
31
+ end
32
+
33
+ def self_time
34
+ aggregate(:self_time)
35
+ end
36
+
37
+ def wait_time
38
+ aggregate(:wait_time)
39
+ end
40
+
41
+ def children_time
42
+ aggregate(:children_time)
43
+ end
44
+
45
+ def called
46
+ aggregate(:called)
47
+ end
48
+
49
+ def to_s
50
+ "#{call_infos.first.full_name}"
51
+ end
52
+
53
+ private
54
+
55
+ def aggregate(method_name)
56
+ self.call_infos.inject(0) do |sum, call_info|
57
+ sum += call_info.send(method_name)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -39,7 +39,7 @@ module RubyProf
39
39
  def root?
40
40
  self.parent.nil?
41
41
  end
42
-
42
+
43
43
  def to_s
44
44
  "#{call_sequence}"
45
45
  end
@@ -198,7 +198,7 @@ module RubyProf
198
198
  self_percentage = (method.self_time/total_time) * 100 %>
199
199
 
200
200
  <!-- Parents -->
201
- <% for caller in method.call_infos
201
+ <% for caller in method.aggregate_parents
202
202
  next unless caller.parent
203
203
  next if min_time && caller.total_time < min_time %>
204
204
  <tr>
@@ -228,7 +228,7 @@ module RubyProf
228
228
  </tr>
229
229
 
230
230
  <!-- Children -->
231
- <% for callee in method.children %>
231
+ <% for callee in method.aggregate_children %>
232
232
  <% next if min_time && callee.total_time < min_time %>
233
233
  <tr>
234
234
  <td>&nbsp;</td>
@@ -127,7 +127,7 @@ module RubyProf
127
127
  end
128
128
 
129
129
  def print_parents(thread_id, method)
130
- method.call_infos.each do |caller|
130
+ method.aggregate_parents.each do |caller|
131
131
  next unless caller.parent
132
132
  @output << " " * 2 * PERCENTAGE_WIDTH
133
133
  @output << sprintf("%#{TIME_WIDTH}.2f", caller.total_time)
@@ -143,7 +143,7 @@ module RubyProf
143
143
  end
144
144
 
145
145
  def print_children(method)
146
- method.children.each do |child|
146
+ method.aggregate_children.each do |child|
147
147
  # Get children method
148
148
 
149
149
  @output << " " * 2 * PERCENTAGE_WIDTH
@@ -0,0 +1,10 @@
1
+ unless Enumerable.method_defined?(:group_by)
2
+ module Enumerable
3
+ def group_by
4
+ inject(Hash.new) do |result, element|
5
+ (result[yield(element)] ||= []) << element
6
+ result
7
+ end
8
+ end
9
+ end
10
+ end
@@ -48,14 +48,6 @@ module RubyProf
48
48
  end
49
49
  end
50
50
 
51
- def children
52
- @children ||= begin
53
- call_infos.map do |call_info|
54
- call_info.children
55
- end.flatten
56
- end
57
- end
58
-
59
51
  def children_time
60
52
  @children_time ||= begin
61
53
  call_infos.inject(0) do |sum, call_info|
@@ -78,8 +70,38 @@ module RubyProf
78
70
  end
79
71
  end
80
72
 
73
+ def children
74
+ @children ||= begin
75
+ call_infos.map do |call_info|
76
+ call_info.children
77
+ end.flatten
78
+ end
79
+ end
80
+
81
+ def aggregate_parents
82
+ aggregate_call_infos(self.call_infos)
83
+ end
84
+
85
+ def aggregate_children
86
+ aggregate_call_infos(self.children)
87
+ end
88
+
81
89
  def to_s
82
90
  full_name
83
91
  end
92
+
93
+ private
94
+
95
+ def aggregate_call_infos(call_infos)
96
+ groups = call_infos.inject(Hash.new) do |hash, call_info|
97
+ key = call_info.parent ? call_info.parent.target : self
98
+ (hash[key] ||= []) << call_info
99
+ hash
100
+ end
101
+
102
+ groups.map do |key, value|
103
+ AggregateCallInfo.new(value)
104
+ end
105
+ end
84
106
  end
85
107
  end
@@ -0,0 +1,14 @@
1
+ <!-- Generator: GNU source-highlight 2.9
2
+ by Lorenzo Bettini
3
+ http://www.lorenzobettini.it
4
+ http://www.gnu.org/software/src-highlite -->
5
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> File<span style="color: #990000">.</span>dirname<span style="color: #990000">(</span><span style="font-weight: bold"><span style="color: #0000FF">__FILE__</span></span><span style="color: #990000">)</span> <span style="color: #990000">+</span> <span style="color: #FF0000">'../profile_test_helper'</span>
6
+
7
+ <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ExampleTest <span style="color: #990000">&lt;</span> Test<span style="color: #990000">::</span>Unit<span style="color: #990000">::</span>TestCase
8
+ <span style="font-weight: bold"><span style="color: #0000FF">include</span></span> RubyProf<span style="color: #990000">::</span>Test
9
+
10
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> test_stuff
11
+ puts <span style="color: #FF0000">"Test method"</span>
12
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
13
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
14
+ </tt></pre>
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'ruby-prof'
5
+
6
+ # Test data
7
+ # A B C
8
+ # | | |
9
+ # Z A A
10
+ # | |
11
+ # Z Z
12
+
13
+ class AggClass
14
+ def z
15
+ sleep 1
16
+ end
17
+
18
+ def a
19
+ z
20
+ end
21
+
22
+ def b
23
+ a
24
+ end
25
+
26
+ def c
27
+ a
28
+ end
29
+ end
30
+
31
+ class AggregateTest < Test::Unit::TestCase
32
+ def setup
33
+ # Need to use wall time for this test due to the sleep calls
34
+ RubyProf::measure_mode = RubyProf::WALL_TIME
35
+ end
36
+
37
+ def test_call_infos
38
+ c1 = AggClass.new
39
+ result = RubyProf.profile do
40
+ c1.a
41
+ c1.b
42
+ c1.c
43
+ end
44
+
45
+ methods = result.threads.values.first.sort.reverse
46
+ method = methods.find {|method| method.full_name == 'AggClass#z'}
47
+
48
+ # Check AggClass#z
49
+ assert_equal('AggClass#z', method.full_name)
50
+ 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)
55
+ assert_equal(3, method.call_infos.length)
56
+
57
+ call_info = method.call_infos[0]
58
+ assert_equal('AggregateTest#test_call_infos->AggClass#a->AggClass#z', call_info.call_sequence)
59
+ assert_equal(1, call_info.children.length)
60
+
61
+ call_info = method.call_infos[1]
62
+ assert_equal('AggregateTest#test_call_infos->AggClass#b->AggClass#a->AggClass#z', call_info.call_sequence)
63
+ assert_equal(1, call_info.children.length)
64
+
65
+ call_info = method.call_infos[2]
66
+ assert_equal('AggregateTest#test_call_infos->AggClass#c->AggClass#a->AggClass#z', call_info.call_sequence)
67
+ assert_equal(1, call_info.children.length)
68
+ end
69
+
70
+ def test_aggregates_parents
71
+ c1 = AggClass.new
72
+ result = RubyProf.profile do
73
+ c1.a
74
+ c1.b
75
+ c1.c
76
+ end
77
+
78
+ methods = result.threads.values.first.sort.reverse
79
+ method = methods.find {|method| method.full_name == 'AggClass#z'}
80
+
81
+ # Check AggClass#z
82
+ assert_equal('AggClass#z', method.full_name)
83
+
84
+ call_infos = method.aggregate_parents
85
+ assert_equal(1, call_infos.length)
86
+
87
+ call_info = call_infos.first
88
+ assert_equal('AggClass#a', call_info.parent.target.full_name)
89
+ assert_in_delta(3, call_info.total_time, 0.01)
90
+ assert_in_delta(0, call_info.wait_time, 0.01)
91
+ assert_in_delta(0, call_info.self_time, 0.01)
92
+ assert_in_delta(3, call_info.children_time, 0.01)
93
+ assert_equal(3, call_info.called)
94
+ end
95
+
96
+ def test_aggregates_children
97
+ c1 = AggClass.new
98
+ result = RubyProf.profile do
99
+ c1.a
100
+ c1.b
101
+ c1.c
102
+ end
103
+
104
+ methods = result.threads.values.first.sort.reverse
105
+ method = methods.find {|method| method.full_name == 'AggClass#a'}
106
+
107
+ # Check AggClass#a
108
+ assert_equal('AggClass#a', method.full_name)
109
+
110
+ call_infos = method.aggregate_children
111
+ assert_equal(1, call_infos.length)
112
+
113
+ call_info = call_infos.first
114
+ assert_equal('AggClass#z', call_info.target.full_name)
115
+ assert_in_delta(3, call_info.total_time, 0.01)
116
+ assert_in_delta(0, call_info.wait_time, 0.01)
117
+ assert_in_delta(0, call_info.self_time, 0.01)
118
+ assert_in_delta(3, call_info.children_time, 0.01)
119
+ assert_equal(3, call_info.called)
120
+ end
121
+ end
data/test/stack_test.rb CHANGED
@@ -10,7 +10,7 @@ require 'ruby-prof'
10
10
  # \
11
11
  # B
12
12
 
13
- class C1
13
+ class StackClass
14
14
  def a
15
15
  sleep 1
16
16
  b
@@ -34,17 +34,17 @@ class StackTest < Test::Unit::TestCase
34
34
  end
35
35
 
36
36
  def test_call_sequence
37
- c = C1.new
37
+ c = StackClass.new
38
38
  result = RubyProf.profile do
39
39
  c.a
40
40
  end
41
41
 
42
42
  # Length should be 5:
43
43
  # StackTest#test_call_sequence
44
- # C1#a
44
+ # StackClass#a
45
45
  # Kernel#sleep
46
- # C1#c
47
- # C1#b
46
+ # StackClass#c
47
+ # StackClass#b
48
48
 
49
49
  methods = result.threads.values.first.sort.reverse
50
50
  assert_equal(5, methods.length)
@@ -63,9 +63,9 @@ class StackTest < Test::Unit::TestCase
63
63
  assert_equal('StackTest#test_call_sequence', call_info.call_sequence)
64
64
  assert_equal(1, call_info.children.length)
65
65
 
66
- # Check C1#a
66
+ # Check StackClass#a
67
67
  method = methods[1]
68
- assert_equal('C1#a', method.full_name)
68
+ assert_equal('StackClass#a', method.full_name)
69
69
  assert_equal(1, method.called)
70
70
  assert_in_delta(8, method.total_time, 0.01)
71
71
  assert_in_delta(0, method.wait_time, 0.01)
@@ -74,7 +74,7 @@ class StackTest < Test::Unit::TestCase
74
74
  assert_equal(1, method.call_infos.length)
75
75
 
76
76
  call_info = method.call_infos[0]
77
- assert_equal('StackTest#test_call_sequence->C1#a', call_info.call_sequence)
77
+ assert_equal('StackTest#test_call_sequence->StackClass#a', call_info.call_sequence)
78
78
  assert_equal(3, call_info.children.length)
79
79
 
80
80
  # Check Kernel#sleep
@@ -88,24 +88,24 @@ class StackTest < Test::Unit::TestCase
88
88
  assert_equal(4, method.call_infos.length)
89
89
 
90
90
  call_info = method.call_infos[0]
91
- assert_equal('StackTest#test_call_sequence->C1#a->Kernel#sleep', call_info.call_sequence)
91
+ assert_equal('StackTest#test_call_sequence->StackClass#a->Kernel#sleep', call_info.call_sequence)
92
92
  assert_equal(0, call_info.children.length)
93
93
 
94
94
  call_info = method.call_infos[1]
95
- assert_equal('StackTest#test_call_sequence->C1#a->C1#b->Kernel#sleep', call_info.call_sequence)
95
+ assert_equal('StackTest#test_call_sequence->StackClass#a->StackClass#b->Kernel#sleep', call_info.call_sequence)
96
96
  assert_equal(0, call_info.children.length)
97
97
 
98
98
  call_info = method.call_infos[2]
99
- assert_equal('StackTest#test_call_sequence->C1#a->C1#c->Kernel#sleep', call_info.call_sequence)
99
+ assert_equal('StackTest#test_call_sequence->StackClass#a->StackClass#c->Kernel#sleep', call_info.call_sequence)
100
100
  assert_equal(0, call_info.children.length)
101
101
 
102
102
  call_info = method.call_infos[3]
103
- assert_equal('StackTest#test_call_sequence->C1#a->C1#c->C1#b->Kernel#sleep', call_info.call_sequence)
103
+ assert_equal('StackTest#test_call_sequence->StackClass#a->StackClass#c->StackClass#b->Kernel#sleep', call_info.call_sequence)
104
104
  assert_equal(0, call_info.children.length)
105
105
 
106
- # Check C1#c
106
+ # Check StackClass#c
107
107
  method = methods[3]
108
- assert_equal('C1#c', method.full_name)
108
+ assert_equal('StackClass#c', method.full_name)
109
109
  assert_equal(1, method.called)
110
110
  assert_in_delta(5, method.total_time, 0.01)
111
111
  assert_in_delta(0, method.wait_time, 0.01)
@@ -114,12 +114,12 @@ class StackTest < Test::Unit::TestCase
114
114
  assert_equal(1, method.call_infos.length)
115
115
 
116
116
  call_info = method.call_infos[0]
117
- assert_equal('StackTest#test_call_sequence->C1#a->C1#c', call_info.call_sequence)
117
+ assert_equal('StackTest#test_call_sequence->StackClass#a->StackClass#c', call_info.call_sequence)
118
118
  assert_equal(2, call_info.children.length)
119
119
 
120
- # Check C1#b
120
+ # Check StackClass#b
121
121
  method = methods[4]
122
- assert_equal('C1#b', method.full_name)
122
+ assert_equal('StackClass#b', method.full_name)
123
123
  assert_equal(2, method.called)
124
124
  assert_in_delta(4, method.total_time, 0.01)
125
125
  assert_in_delta(0, method.wait_time, 0.01)
@@ -128,11 +128,11 @@ class StackTest < Test::Unit::TestCase
128
128
  assert_equal(2, method.call_infos.length)
129
129
 
130
130
  call_info = method.call_infos[0]
131
- assert_equal('StackTest#test_call_sequence->C1#a->C1#b', call_info.call_sequence)
131
+ assert_equal('StackTest#test_call_sequence->StackClass#a->StackClass#b', call_info.call_sequence)
132
132
  assert_equal(1, call_info.children.length)
133
133
 
134
134
  call_info = method.call_infos[1]
135
- assert_equal('StackTest#test_call_sequence->C1#a->C1#c->C1#b', call_info.call_sequence)
135
+ assert_equal('StackTest#test_call_sequence->StackClass#a->StackClass#c->StackClass#b', call_info.call_sequence)
136
136
  assert_equal(1, call_info.children.length)
137
137
  end
138
138
  end
data/test/test_suite.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'test/unit'
2
2
 
3
+ require 'aggregate_test'
3
4
  require 'basic_test'
4
5
  require 'duplicate_names_test'
5
6
  require 'exceptions_test'
@@ -9,7 +10,6 @@ require 'module_test'
9
10
  require 'no_method_class_test'
10
11
  require 'prime_test'
11
12
  require 'printers_test'
12
- require 'profile_unit_test'
13
13
  require 'recursive_test'
14
14
  require 'singleton_test'
15
15
  require 'stack_test'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-prof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda and Charlie Savage
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-11 00:00:00 -07:00
12
+ date: 2008-11-30 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -49,11 +49,13 @@ files:
49
49
  - ext/vc/ruby_prof.vcproj
50
50
  - lib/ruby-prof
51
51
  - lib/ruby-prof/abstract_printer.rb
52
+ - lib/ruby-prof/aggregate_call_info.rb
52
53
  - lib/ruby-prof/call_info.rb
53
54
  - lib/ruby-prof/call_tree_printer.rb
54
55
  - lib/ruby-prof/flat_printer.rb
55
56
  - lib/ruby-prof/graph_html_printer.rb
56
57
  - lib/ruby-prof/graph_printer.rb
58
+ - lib/ruby-prof/group_by.rb
57
59
  - lib/ruby-prof/method_info.rb
58
60
  - lib/ruby-prof/task.rb
59
61
  - lib/ruby-prof/test.rb
@@ -63,7 +65,9 @@ files:
63
65
  - rails/environment/profile.rb
64
66
  - rails/example
65
67
  - rails/example/example_test.rb
68
+ - rails/example/example_test.rb.html
66
69
  - rails/profile_test_helper.rb
70
+ - test/aggregate_test.rb
67
71
  - test/basic_test.rb
68
72
  - test/duplicate_names_test.rb
69
73
  - test/exceptions_test.rb
@@ -75,7 +79,6 @@ files:
75
79
  - test/prime.rb
76
80
  - test/prime_test.rb
77
81
  - test/printers_test.rb
78
- - test/profile_unit_test.rb
79
82
  - test/recursive_test.rb
80
83
  - test/singleton_test.rb
81
84
  - test/stack_test.rb
@@ -105,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
108
  requirements: []
106
109
 
107
110
  rubyforge_project: ruby-prof
108
- rubygems_version: 1.2.0
111
+ rubygems_version: 1.3.1
109
112
  signing_key:
110
113
  specification_version: 2
111
114
  summary: Fast Ruby profiler
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'test/unit'
3
- require 'ruby-prof'
4
-
5
- # Need to use wall time for this test due to the sleep calls
6
- RubyProf::measure_mode = RubyProf::WALL_TIME
7
-
8
- # -- Tests ----
9
- class ProfileTest < Test::Unit::TestCase
10
- include RubyProf::Test
11
-
12
- def teardown
13
- profile_dir = output_dir
14
-
15
- #file_path = File.join(profile_dir, 'test_profile_profile_test.html')
16
- #assert(File.exists?(file_path))
17
- end
18
-
19
- def test_profile
20
- sleep(1)
21
- end
22
- end