5 if method_module.is_a?(MetaClass)
7 "#{method_module.attached_instance.inspect}.#{name}"
9 "#{method_module.attached_instance.class}##{name}"
13 "#{method_module.name}##{name}"
22 def initialize(freq=nil)
24 @frequency ||= ENV['PROFILE_FREQ'].to_i
25 @frequency = 100 if @frequency == 0
27 @call_graph = ENV['PROFILE_FULL']
31 @start_clock = activate(@frequency)
36 @results, @last_clock, @interval = terminate()
42 attr_accessor :descendants_slices
44 attr_accessor :parents
45 attr_accessor :children
50 @descendants_slices = 0
52 @parents = Hash.new { |h,k| h[k] = 0 }
53 @children = Hash.new { |h,k| h[k] = 0 }
57 @slices + @descendants_slices
60 def count_parent(call)
63 call.children[self] += 1
68 def display(out=STDOUT)
70 @calls = Hash.new { |h,k| h[k] = Call.new(k) }
72 @results.each do |ent|
80 # skip context unwinding for a primitive
81 next if ent.kind_of? Fixnum
84 # count parents and children
85 call.count_parent(find_call(ent.sender))
88 seen_calls = { call => 1 }
96 # unwind to the root, but count each call only once
100 c.descendants_slices += 1
106 out << "Total slices: #{@total_slices}, #{@last_clock - @start_clock} clocks\n\n"
107 out << "=== FLAT PROFILE ===\n\n"
108 out << " % time slices name\n"
110 @calls.sort { |a, b| b[1].slices <=> a[1].slices }.each do |name, call|
111 out.printf " %6.2f %8d %s\n", percent(call.slices), call.slices, name
115 out << "\n=== CALL GRAPH ===\n\n"
116 out << " % time slices % self slices name\n"
117 @calls.sort { |a, b| b[1].total_slices <=> a[1].total_slices }.each do |name, call|
118 print_relatives(out, call.parents.sort { |a,b| a[1] <=> b[1] })
120 out.printf " %6.2f %8d %6.2f %8d %s\n",
121 percent(call.total_slices), call.total_slices,
122 percent(call.slices), call.slices,
125 print_relatives(out, call.children.sort { |a,b| b[1] <=> a[1] })
127 out << "----------------------------------------------------------------------\n"
133 def context_name(entry)
134 # a Fixnum means that a primitive was running
135 if entry.kind_of? Fixnum
136 "VM.primitive => #{Rubinius::Primitives[entry]}"
138 entry.normalized_name
143 @calls[context_name(entry)]
147 100.0 * slices / @total_slices
150 def print_relatives(out, rels)
151 rels[0,5].each do |rel|
152 out << " #{rel[0].name} (#{rel[1]})\n"
157 def show_stats(range=30)
159 count = Selector::ALL.size
161 entries = Selector::ALL.values.map { |s| [s, s.receives] }
163 entries.delete_if { |e| e.last < 10 }
165 sort = entries.sort { |a,b| b.last <=> a.last }
167 puts "\nTotal Selectors: #{count}"
168 puts "Top #{range}, by receives:"
169 puts "%-20s| %-20s| %s" % ["name", "receives", "send sites"]
170 puts "=========================================================="
171 sort[0,range].each do |entry|
172 puts "%-20s| %-20d| %d" % [entry.first.name, entry.last, entry.first.send_sites.size]
178 def show_stats(range=30)
179 send_sites = Selector::ALL.values.inject([]) { |acc,s| acc.concat(s.send_sites) }
180 count = send_sites.size
182 send_sites.delete_if { |e| (e.hits + e.misses) < 10 }
184 sort = send_sites.sort { |a,b| (b.hits + b.misses) <=> (a.hits + a.misses) }
186 puts "\nTotal SendSites: #{count}"
187 puts "Top #{range}, by sends:"
188 puts "%-32s| %-18s| %-10s| %s" % ["sender", "name", "hits", "misses"]
189 puts "========================================================================"
190 sort[0,range].each do |entry|
191 mod = entry.sender.staticscope.module if entry.sender.staticscope
192 sender = "#{mod}##{entry.sender.name}"
193 puts "%-32s| %-18s| %-10d| %d" % [sender, entry.name, entry.hits, entry.misses]