ruby-prof 0.18.0 → 1.0.0

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +23 -0
  3. data/LICENSE +2 -2
  4. data/README.rdoc +1 -483
  5. data/Rakefile +3 -6
  6. data/bin/ruby-prof +65 -30
  7. data/ext/ruby_prof/extconf.rb +6 -38
  8. data/ext/ruby_prof/rp_allocation.c +292 -0
  9. data/ext/ruby_prof/rp_allocation.h +31 -0
  10. data/ext/ruby_prof/rp_call_info.c +137 -279
  11. data/ext/ruby_prof/rp_call_info.h +16 -34
  12. data/ext/ruby_prof/rp_measure_allocations.c +25 -49
  13. data/ext/ruby_prof/rp_measure_memory.c +21 -56
  14. data/ext/ruby_prof/rp_measure_process_time.c +28 -36
  15. data/ext/ruby_prof/rp_measure_wall_time.c +36 -19
  16. data/ext/ruby_prof/rp_measurement.c +236 -0
  17. data/ext/ruby_prof/rp_measurement.h +49 -0
  18. data/ext/ruby_prof/rp_method.c +395 -383
  19. data/ext/ruby_prof/rp_method.h +34 -39
  20. data/ext/ruby_prof/rp_profile.c +881 -0
  21. data/ext/ruby_prof/rp_profile.h +36 -0
  22. data/ext/ruby_prof/rp_stack.c +103 -80
  23. data/ext/ruby_prof/rp_stack.h +5 -12
  24. data/ext/ruby_prof/rp_thread.c +149 -88
  25. data/ext/ruby_prof/rp_thread.h +15 -6
  26. data/ext/ruby_prof/ruby_prof.c +11 -757
  27. data/ext/ruby_prof/ruby_prof.h +4 -47
  28. data/ext/ruby_prof/vc/ruby_prof.vcxproj +10 -8
  29. data/lib/ruby-prof.rb +2 -17
  30. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  31. data/lib/ruby-prof/call_info.rb +35 -93
  32. data/lib/ruby-prof/call_info_visitor.rb +19 -21
  33. data/lib/ruby-prof/compatibility.rb +37 -107
  34. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  35. data/lib/ruby-prof/measurement.rb +14 -0
  36. data/lib/ruby-prof/method_info.rb +52 -83
  37. data/lib/ruby-prof/printers/abstract_printer.rb +66 -52
  38. data/lib/ruby-prof/printers/call_info_printer.rb +13 -3
  39. data/lib/ruby-prof/printers/call_stack_printer.rb +32 -28
  40. data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
  41. data/lib/ruby-prof/printers/dot_printer.rb +5 -5
  42. data/lib/ruby-prof/printers/flat_printer.rb +6 -24
  43. data/lib/ruby-prof/printers/graph_html_printer.rb +7 -192
  44. data/lib/ruby-prof/printers/graph_printer.rb +13 -15
  45. data/lib/ruby-prof/printers/multi_printer.rb +66 -23
  46. data/lib/ruby-prof/profile.rb +10 -3
  47. data/lib/ruby-prof/rack.rb +0 -3
  48. data/lib/ruby-prof/thread.rb +12 -12
  49. data/lib/ruby-prof/version.rb +1 -1
  50. data/ruby-prof.gemspec +2 -2
  51. data/test/abstract_printer_test.rb +0 -27
  52. data/test/alias_test.rb +129 -0
  53. data/test/basic_test.rb +41 -40
  54. data/test/call_info_visitor_test.rb +3 -3
  55. data/test/dynamic_method_test.rb +0 -2
  56. data/test/line_number_test.rb +120 -39
  57. data/test/marshal_test.rb +119 -0
  58. data/test/measure_allocations.rb +30 -0
  59. data/test/measure_allocations_test.rb +371 -12
  60. data/test/measure_allocations_trace_test.rb +385 -0
  61. data/test/measure_memory_trace_test.rb +756 -0
  62. data/test/measure_process_time_test.rb +821 -33
  63. data/test/measure_times.rb +54 -0
  64. data/test/measure_wall_time_test.rb +349 -145
  65. data/test/multi_printer_test.rb +1 -34
  66. data/test/parser_timings.rb +24 -0
  67. data/test/pause_resume_test.rb +5 -5
  68. data/test/prime.rb +2 -0
  69. data/test/printer_call_tree_test.rb +31 -0
  70. data/test/printer_flat_test.rb +68 -0
  71. data/test/printer_graph_html_test.rb +60 -0
  72. data/test/printer_graph_test.rb +41 -0
  73. data/test/printers_test.rb +32 -166
  74. data/test/printing_recursive_graph_test.rb +26 -72
  75. data/test/recursive_test.rb +72 -77
  76. data/test/stack_printer_test.rb +2 -15
  77. data/test/start_stop_test.rb +22 -25
  78. data/test/test_helper.rb +5 -248
  79. data/test/thread_test.rb +11 -54
  80. data/test/unique_call_path_test.rb +16 -28
  81. data/test/yarv_test.rb +1 -0
  82. metadata +24 -34
  83. data/examples/flat.txt +0 -50
  84. data/examples/graph.dot +0 -84
  85. data/examples/graph.html +0 -823
  86. data/examples/graph.txt +0 -139
  87. data/examples/multi.flat.txt +0 -23
  88. data/examples/multi.graph.html +0 -760
  89. data/examples/multi.grind.dat +0 -114
  90. data/examples/multi.stack.html +0 -547
  91. data/examples/stack.html +0 -547
  92. data/ext/ruby_prof/rp_measure.c +0 -40
  93. data/ext/ruby_prof/rp_measure.h +0 -45
  94. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
  95. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
  96. data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
  97. data/lib/ruby-prof/aggregate_call_info.rb +0 -76
  98. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
  99. data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
  100. data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
  101. data/test/aggregate_test.rb +0 -136
  102. data/test/block_test.rb +0 -74
  103. data/test/call_info_test.rb +0 -78
  104. data/test/fiber_test.rb +0 -79
  105. data/test/issue137_test.rb +0 -63
  106. data/test/measure_cpu_time_test.rb +0 -212
  107. data/test/measure_gc_runs_test.rb +0 -32
  108. data/test/measure_gc_time_test.rb +0 -36
  109. data/test/measure_memory_test.rb +0 -33
  110. data/test/method_elimination_test.rb +0 -84
  111. data/test/module_test.rb +0 -45
  112. data/test/stack_test.rb +0 -138
@@ -0,0 +1,14 @@
1
+ module RubyProf
2
+ # The Measurement class is a helper class used by RubyProf::MethodInfo to store information about the method.
3
+ # You cannot create a CallInfo object directly, they are generated while running a profile.
4
+ class Measurement
5
+ # :nodoc:
6
+ def to_s
7
+ "c: #{called}, tt: #{total_time}, st: #{self_time}"
8
+ end
9
+
10
+ def inspect
11
+ super + "(#{self.to_s})"
12
+ end
13
+ end
14
+ end
@@ -1,108 +1,78 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module RubyProf
4
+ # The MethodInfo class is used to track information about each method that is profiled.
5
+ # You cannot create a MethodInfo object directly, they are generated while running a profile.
4
6
  class MethodInfo
5
7
  include Comparable
6
8
 
7
- def <=>(other)
8
- if self.total_time < other.total_time
9
- -1
10
- elsif self.total_time > other.total_time
11
- 1
12
- elsif self.min_depth < other.min_depth
13
- 1
14
- elsif self.min_depth > other.min_depth
15
- -1
16
- else
17
- self.full_name <=> other.full_name
18
- end
9
+ # Returns the full name of a class. The interpretation of method names is:
10
+ #
11
+ # * MyObject#test - An method defined in a class
12
+ # * <Class:MyObject>#test - A method defined in a singleton class.
13
+ # * <Module:MyObject>#test - A method defined in a singleton module.
14
+ # * <Object:MyObject>#test - A method defined in a singleton object.
15
+ def full_name
16
+ decorated_class_name = case self.klass_flags
17
+ when 0x2
18
+ "<Class::#{klass_name}>"
19
+ when 0x4
20
+ "<Module::#{klass_name}>"
21
+ when 0x8
22
+ "<Object::#{klass_name}>"
23
+ else
24
+ klass_name
25
+ end
26
+
27
+ "#{decorated_class_name}##{method_name}"
19
28
  end
20
29
 
30
+ # The number of times this method was called
21
31
  def called
22
- @called ||= begin
23
- call_infos.inject(0) do |sum, call_info|
24
- sum + call_info.called
25
- end
26
- end
32
+ self.measurement.called
27
33
  end
28
34
 
35
+ # The total time this method took - includes self time + wait time + child time
29
36
  def total_time
30
- @total_time ||= begin
31
- call_infos.inject(0) do |sum, call_info|
32
- sum += call_info.total_time if !call_info.recursive?
33
- sum
34
- end
35
- end
37
+ self.measurement.total_time
36
38
  end
37
39
 
40
+ # The time this method took to execute
38
41
  def self_time
39
- @self_time ||= begin
40
- call_infos.inject(0) do |sum, call_info|
41
- sum += call_info.self_time if !call_info.recursive?
42
- sum
43
- end
44
- end
42
+ self.measurement.self_time
45
43
  end
46
44
 
45
+ # The time this method waited for other fibers/threads to execute
47
46
  def wait_time
48
- @wait_time ||= begin
49
- call_infos.inject(0) do |sum, call_info|
50
- sum += call_info.wait_time if !call_info.recursive?
51
- sum
52
- end
53
- end
47
+ self.measurement.wait_time
54
48
  end
55
49
 
50
+ # The time this method's children took to execute
56
51
  def children_time
57
- @children_time ||= begin
58
- call_infos.inject(0) do |sum, call_info|
59
- sum += call_info.children_time if !call_info.recursive?
60
- sum
61
- end
62
- end
52
+ self.total_time - self.self_time - self.wait_time
63
53
  end
64
54
 
55
+ # The min call depth of this method
65
56
  def min_depth
66
- @min_depth ||= call_infos.map(&:depth).min
67
- end
68
-
69
- def root?
70
- @root ||= begin
71
- call_infos.find do |call_info|
72
- not call_info.root?
73
- end.nil?
74
- end
75
- end
76
-
77
- def children
78
- @children ||= call_infos.map(&:children).flatten
57
+ @min_depth ||= callers.map(&:depth).min
79
58
  end
80
59
 
81
- def parents
82
- @parents ||= call_infos.map(&:parent)
83
- end
84
-
85
- def aggregate_parents
86
- # group call infos based on their parents
87
- groups = self.call_infos.each_with_object({}) do |call_info, hash|
88
- key = call_info.parent ? call_info.parent.target : self
89
- (hash[key] ||= []) << call_info
90
- end
91
-
92
- groups.map do |key, value|
93
- AggregateCallInfo.new(value, self)
94
- end
95
- end
96
-
97
- def aggregate_children
98
- # group call infos based on their targets
99
- groups = self.children.each_with_object({}) do |call_info, hash|
100
- key = call_info.target
101
- (hash[key] ||= []) << call_info
102
- end
103
-
104
- groups.map do |key, value|
105
- AggregateCallInfo.new(value, self)
60
+ # :enddoc:
61
+ def <=>(other)
62
+ if other == nil
63
+ -1
64
+ elsif self.full_name == other.full_name
65
+ 0
66
+ elsif self.total_time < other.total_time
67
+ -1
68
+ elsif self.total_time > other.total_time
69
+ 1
70
+ elsif self.min_depth < other.min_depth
71
+ 1
72
+ elsif self.min_depth > other.min_depth
73
+ -1
74
+ else
75
+ self.full_name <=> other.full_name
106
76
  end
107
77
  end
108
78
 
@@ -110,12 +80,11 @@ module RubyProf
110
80
  "#{self.full_name} (c: #{self.called}, tt: #{self.total_time}, st: #{self.self_time}, wt: #{wait_time}, ct: #{self.children_time})"
111
81
  end
112
82
 
113
- # remove method from the call graph. should not be called directly.
83
+ # Remove method from the call graph. should not be called directly.
114
84
  def eliminate!
115
85
  # $stderr.puts "eliminating #{self}"
116
- call_infos.each{ |call_info| call_info.eliminate! }
117
- call_infos.clear
86
+ callers.each{ |call_info| call_info.eliminate! }
87
+ callers.clear
118
88
  end
119
-
120
89
  end
121
90
  end
@@ -1,7 +1,14 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module RubyProf
4
+ # This is the base class for all Printers. It is never used directly.
4
5
  class AbstractPrinter
6
+ # :stopdoc:
7
+ def self.needs_dir?
8
+ false
9
+ end
10
+ # :startdoc:
11
+
5
12
  # Create a new printer.
6
13
  #
7
14
  # result should be the output generated from a profiling run
@@ -10,74 +17,56 @@ module RubyProf
10
17
  @output = nil
11
18
  end
12
19
 
13
- # Specify print options.
14
- #
15
- # options - Hash table
16
- # :min_percent - Number 0 to 100 that specifes the minimum
17
- # %self (the methods self time divided by the
18
- # overall total time) that a method must take
19
- # for it to be printed out in the report.
20
- # Default value is 0.
21
- #
22
- # :print_file - True or false. Specifies if a method's source
23
- # file should be printed. Default value if false.
24
- #
25
- # :sort_method - Specifies method used for sorting method infos.
26
- # Available values are :total_time, :self_time,
27
- # :wait_time, :children_time
28
- # Default value is :total_time
29
- # :editor_uri - Specifies editor uri scheme used for opening files
30
- # e.g. :atm or :mvim. For OS X default is :txmt.
31
- # Pass false to print bare filenames.
32
- # Use RUBY_PROF_EDITOR_URI environment variable to override.
33
- def setup_options(options = {})
34
- @options = options
35
- end
36
-
20
+ # Returns the min_percent of total time a method must take to be included in a profiling report
37
21
  def min_percent
38
22
  @options[:min_percent] || 0
39
23
  end
40
24
 
41
- def print_file
42
- @options[:print_file] || false
25
+ # Returns the time format used to show when a profile was run
26
+ def time_format
27
+ '%A, %B %-d at %l:%M:%S %p (%Z)'
43
28
  end
44
29
 
30
+ # Returns how profile data should be sorted
45
31
  def sort_method
46
- @options[:sort_method] || :total_time
47
- end
48
-
49
- def editor_uri
50
- if ENV.key?('RUBY_PROF_EDITOR_URI')
51
- ENV['RUBY_PROF_EDITOR_URI'] || false
52
- elsif @options.key?(:editor_uri)
53
- @options[:editor_uri]
54
- else
55
- RUBY_PLATFORM =~ /darwin/ ? 'txmt' : false
56
- end
57
- end
58
-
59
- def method_name(method)
60
- name = method.full_name
61
- if print_file
62
- name += " (#{method.source_file}:#{method.line}}"
63
- end
64
- name
32
+ @options[:sort_method]
65
33
  end
66
34
 
67
- # Print a profiling report to the provided output.
35
+ # Prints a report to the provided output.
68
36
  #
69
37
  # output - Any IO object, including STDOUT or a file.
70
38
  # The default value is STDOUT.
71
39
  #
72
- # options - Hash of print options. See #setup_options
73
- # for more information. Note that each printer can
40
+ # options - Hash of print options. Note that each printer can
74
41
  # define its own set of options.
42
+ #
43
+ # :min_percent - Number 0 to 100 that specifes the minimum
44
+ # %self (the methods self time divided by the
45
+ # overall total time) that a method must take
46
+ # for it to be printed out in the report.
47
+ # Default value is 0.
48
+ #
49
+ # :sort_method - Specifies method used for sorting method infos.
50
+ # Available values are :total_time, :self_time,
51
+ # :wait_time, :children_time
52
+ # Default value is :total_time
75
53
  def print(output = STDOUT, options = {})
76
54
  @output = output
77
55
  setup_options(options)
78
56
  print_threads
79
57
  end
80
58
 
59
+ # :nodoc:
60
+ def setup_options(options = {})
61
+ @options = options
62
+ end
63
+
64
+ def method_location(method)
65
+ if method.source_file
66
+ "#{method.source_file}:#{method.line}"
67
+ end
68
+ end
69
+
81
70
  def print_threads
82
71
  @result.threads.each do |thread|
83
72
  print_thread(thread)
@@ -91,14 +80,39 @@ module RubyProf
91
80
  end
92
81
 
93
82
  def print_header(thread)
83
+ @output << "Measure Mode: %s\n" % RubyProf.measure_mode_string
84
+ @output << "Thread ID: %d\n" % thread.id
85
+ @output << "Fiber ID: %d\n" % thread.fiber_id unless thread.id == thread.fiber_id
86
+ @output << "Total: %0.6f\n" % thread.total_time
87
+ @output << "Sort by: #{sort_method}\n"
88
+ @output << "\n"
89
+ print_column_headers
94
90
  end
95
91
 
96
- def print_footer(thread)
92
+ def print_column_headers
97
93
  end
98
94
 
99
- # whether this printer need a :path option pointing to a directory
100
- def self.needs_dir?
101
- false
95
+ def print_footer(thread)
96
+ @output << <<~EOT
97
+
98
+ * recursively called methods
99
+
100
+ Columns are:
101
+
102
+ %self - The percentage of time spent in this method, derived from self_time/total_time.
103
+ total - The time spent in this method and its children.
104
+ self - The time spent in this method.
105
+ wait - The amount of time this method waited for other threads.
106
+ child - The time spent in this method's children.
107
+ calls - The number of times this method was called.
108
+ name - The name of the method.
109
+ location - The location of the method.
110
+
111
+ The interpretation of method names is:
112
+
113
+ * MyObject#test - An instance method "test" of the class "MyObject"
114
+ * <Object:MyObject>#test - The <> characters indicate a method on a singleton class.
115
+ EOT
102
116
  end
103
117
  end
104
118
  end
@@ -4,7 +4,15 @@ module RubyProf
4
4
  # Prints out the call graph based on CallInfo instances. This
5
5
  # is mainly for debugging purposes as it provides access into
6
6
  # into RubyProf's internals.
7
-
7
+ #
8
+ # To use the printer:
9
+ #
10
+ # result = RubyProf.profile do
11
+ # [code to profile]
12
+ # end
13
+ #
14
+ # printer = RubyProf::CallInfoPrinter.new(result)
15
+ # printer.print(STDOUT)
8
16
  class CallInfoPrinter < AbstractPrinter
9
17
  TIME_WIDTH = 0
10
18
 
@@ -19,7 +27,7 @@ module RubyProf
19
27
  end
20
28
 
21
29
  def print_methods(thread)
22
- visitor = CallInfoVisitor.new(thread.top_call_infos)
30
+ visitor = CallInfoVisitor.new(thread.root_methods)
23
31
 
24
32
  visitor.visit do |call_info, event|
25
33
  if event == :enter
@@ -31,11 +39,13 @@ module RubyProf
31
39
  @output << "wt:#{sprintf("%#{TIME_WIDTH}.2f", call_info.wait_time)}, "
32
40
  @output << "ct:#{sprintf("%#{TIME_WIDTH}.2f", call_info.children_time)}, "
33
41
  @output << "call:#{call_info.called}, "
34
- @output << "rec:#{call_info.recursive?}"
35
42
  @output << ")"
36
43
  @output << "\n"
37
44
  end
38
45
  end
39
46
  end
47
+
48
+ def print_footer(thread)
49
+ end
40
50
  end
41
51
  end
@@ -3,10 +3,21 @@
3
3
  require 'erb'
4
4
  require 'fileutils'
5
5
  require 'base64'
6
+ require 'set'
6
7
 
7
8
  module RubyProf
8
- # prints a HTML visualization of the call tree
9
- class CallStackPrinter < AbstractPrinter
9
+ # Prints a HTML visualization of the call tree.
10
+ #
11
+ # To use the printer:
12
+ #
13
+ # result = RubyProf.profile do
14
+ # [code to profile]
15
+ # end
16
+ #
17
+ # printer = RubyProf::CallStackPrinter.new(result)
18
+ # printer.print(STDOUT)
19
+
20
+ class CallStackPrinter < AbstractPrinter
10
21
  include ERB::Util
11
22
 
12
23
  # Specify print options.
@@ -18,9 +29,6 @@ module RubyProf
18
29
  # for it to be printed out in the report.
19
30
  # Default value is 0.
20
31
  #
21
- # :print_file - True or false. Specifies if a method's source
22
- # file should be printed. Default value if false.
23
- #
24
32
  # :threshold - a float from 0 to 100 that sets the threshold of
25
33
  # results displayed.
26
34
  # Default value is 1.0
@@ -35,14 +43,9 @@ module RubyProf
35
43
  #
36
44
  # :application - a String to overide the name of the application,
37
45
  # as it appears on the report.
38
- #
39
- # :editor_uri - Specifies editor uri scheme used for opening files
40
- # e.g. :atm or :mvim. For OS X default is :txmt.
41
- # Use RUBY_PROF_EDITOR_URI environment variable to overide.
42
46
  def print(output = STDOUT, options = {})
43
47
  @output = output
44
48
  setup_options(options)
45
- @editor = editor_uri
46
49
  if @graph_html = options.delete(:graph)
47
50
  @graph_html = "file://" + @graph_html if @graph_html[0]=="/"
48
51
  end
@@ -64,29 +67,29 @@ module RubyProf
64
67
  thread.methods.each do |m|
65
68
  # $stderr.print m.dump
66
69
  next unless m.root?
67
- m.call_infos.each do |ci|
68
- next unless ci.root?
69
- print_stack ci, thread.total_time
70
+ m.callers.each do |call_info|
71
+ visited = Set.new
72
+ print_stack(visited, call_info, thread.total_time)
70
73
  end
71
74
  end
72
75
  @output.print "</ul>"
73
76
  end
74
77
 
75
78
  print_footer
76
-
77
79
  end
78
80
 
79
- def print_stack(call_info, parent_time)
81
+ def print_stack(visited, call_info, parent_time)
80
82
  total_time = call_info.total_time
81
83
  percent_parent = (total_time/parent_time)*100
82
84
  percent_total = (total_time/@overall_time)*100
83
85
  return unless percent_total > min_percent
84
86
  color = self.color(percent_total)
85
- kids = call_info.children
87
+ kids = call_info.target.callees
86
88
  visible = percent_total >= threshold
87
89
  expanded = percent_total >= expansion
88
90
  display = visible ? "block" : "none"
89
91
  @output.print "<li class=\"color#{color}\" style=\"display:#{display}\">"
92
+
90
93
  if kids.empty?
91
94
  @output.print "<a href=\"#\" class=\"toggle empty\" ></a>"
92
95
  else
@@ -95,14 +98,21 @@ module RubyProf
95
98
  @output.print "<a href=\"#\" class=\"toggle #{image}\" ></a>"
96
99
  end
97
100
  @output.printf "<span> %4.2f%% (%4.2f%%) %s %s</span>\n", percent_total, percent_parent, link(call_info), graph_link(call_info)
101
+
102
+ if visited.include?(call_info)
103
+ return
104
+ else
105
+ visited << call_info
106
+ end
107
+
98
108
  unless kids.empty?
99
109
  if expanded
100
110
  @output.print "<ul>"
101
111
  else
102
112
  @output.print '<ul style="display:none">'
103
113
  end
104
- kids.sort_by{|c| -c.total_time}.each do |callinfo|
105
- print_stack callinfo, total_time
114
+ kids.sort_by{|c| -c.total_time}.each do |child_call_info|
115
+ print_stack(visited, child_call_info, total_time)
106
116
  end
107
117
  @output.print "</ul>"
108
118
  end
@@ -116,22 +126,16 @@ module RubyProf
116
126
 
117
127
  def link(call_info)
118
128
  method = call_info.target
119
- file = File.expand_path(method.source_file)
120
- if file =~ /\/ruby_runtime$/
129
+ if method.source_file.nil?
121
130
  h(name(call_info))
122
131
  else
123
- if @editor
124
- "<a href=\"#{@editor}://" \
125
- "open?url=file://#{file}&line=#{method.line}\">" \
126
- "#{h(name(call_info))}</a>"
127
- else
128
- "<a href=\"file://#{file}##{method.line}\">#{h(name(call_info))}</a>"
129
- end
132
+ file = File.expand_path(method.source_file)
133
+ "<a href=\"file://#{file}##{method.line}\">#{h(name(call_info))}</a>"
130
134
  end
131
135
  end
132
136
 
133
137
  def graph_link(call_info)
134
- total_calls = call_info.target.call_infos.inject(0){|t, ci| t += ci.called}
138
+ total_calls = call_info.target.callers.inject(0){|t, ci| t += ci.called}
135
139
  href = "#{@graph_html}##{method_href(call_info.target)}"
136
140
  totals = @graph_html ? "<a href='#{href}'>#{total_calls}</a>" : total_calls.to_s
137
141
  "[#{call_info.called} calls, #{totals} total]"