class MemoryProfiler::Results
Constants
- METRICS
- NAMES
- TYPES
- UNIT_PREFIXES
Attributes
strings_allocated[RW]
strings_retained[RW]
total_allocated[RW]
total_allocated_memsize[RW]
total_retained[RW]
total_retained_memsize[RW]
Public Class Methods
register_type(name, stat_attribute)
click to toggle source
# File lib/memory_profiler/results.rb, line 21 def self.register_type(name, stat_attribute) @@lookups ||= [] @@lookups << [name, stat_attribute] TYPES.each do |type| METRICS.each do |metric| attr_accessor "#{type}_#{metric}_by_#{name}" end end end
Public Instance Methods
normalize_path(path)
click to toggle source
# File lib/memory_profiler/results.rb, line 160 def normalize_path(path) @normalize_path ||= {} @normalize_path[path] ||= begin if %r!(/gems/.*)*/gems/(?<gemname>[^/]+)(?<rest>.*)! =~ path "#{gemname}#{rest}" elsif %r!ruby/2\.[^/]+/(?<stdlib>[^/.]+)(?<rest>.*)! =~ path "ruby/lib/#{stdlib}#{rest}" elsif %r!(?<app>[^/]+/(bin|app|lib))(?<rest>.*)! =~ path "#{app}#{rest}" else path end end end
pretty_print(io = $stdout, **options)
click to toggle source
Output the results of the report @param [Hash] options the options for output @option opts [String] :to_file a path to your log file @option opts [Boolean] :color_output a flag for whether to colorize output @option opts [Integer] :retained_strings how many retained strings to print @option opts [Integer] :allocated_strings how many allocated strings to print @option opts [Boolean] :detailed_report should report include detailed information @option opts [Boolean] :scale_bytes calculates unit prefixes for the numbers of bytes @option opts [Boolean] :normalize_paths print location paths relative to gem's source directory.
# File lib/memory_profiler/results.rb, line 113 def pretty_print(io = $stdout, **options) # Handle the special case that Ruby PrettyPrint expects `pretty_print` # to be a customized pretty printing function for a class return io.pp_object(self) if defined?(PP) && io.is_a?(PP) io = File.open(options[:to_file], "w") if options[:to_file] color_output = options.fetch(:color_output) { io.respond_to?(:isatty) && io.isatty } @colorize = color_output ? Polychrome.new : Monochrome.new if options[:scale_bytes] total_allocated_output = scale_bytes(total_allocated_memsize) total_retained_output = scale_bytes(total_retained_memsize) else total_allocated_output = "#{total_allocated_memsize} bytes" total_retained_output = "#{total_retained_memsize} bytes" end io.puts "Total allocated: #{total_allocated_output} (#{total_allocated} objects)" io.puts "Total retained: #{total_retained_output} (#{total_retained} objects)" unless options[:detailed_report] == false TYPES.each do |type| METRICS.each do |metric| NAMES.each do |name| dump_data(io, type, metric, name, options) end end end end io.puts print_string_reports(io, options) io.close if io.is_a? File end
print_string_reports(io, options)
click to toggle source
# File lib/memory_profiler/results.rb, line 150 def print_string_reports(io, options) TYPES.each do |type| dump_opts = { normalize_paths: options[:normalize_paths], limit: options["#{type}_strings".to_sym] } dump_strings(io, type, dump_opts) end end
register_results(allocated, retained, top)
click to toggle source
# File lib/memory_profiler/results.rb, line 41 def register_results(allocated, retained, top) @@lookups.each do |name, stat_attribute| memsize_results, count_results = allocated.top_n(top, stat_attribute) self.send("allocated_memory_by_#{name}=", memsize_results) self.send("allocated_objects_by_#{name}=", count_results) memsize_results, count_results = retained.top_n(top, stat_attribute) self.send("retained_memory_by_#{name}=", memsize_results) self.send("retained_objects_by_#{name}=", count_results) end self.strings_allocated = string_report(allocated, top) self.strings_retained = string_report(retained, top) self.total_allocated = allocated.size self.total_allocated_memsize = total_memsize(allocated) self.total_retained = retained.size self.total_retained_memsize = total_memsize(retained) self end
scale_bytes(bytes)
click to toggle source
# File lib/memory_profiler/results.rb, line 67 def scale_bytes(bytes) return "0 B" if bytes.zero? scale = Math.log10(bytes).div(3) * 3 scale = 24 if scale > 24 "%.2f #{UNIT_PREFIXES[scale]}" % (bytes / 10.0**scale) end
string_report(data, top)
click to toggle source
# File lib/memory_profiler/results.rb, line 75 def string_report(data, top) grouped_strings = Hash.new { |hash, key| hash[key] = [] } data.each_value do |stat| if stat.string_value grouped_strings[stat.string_value.object_id] << stat end end grouped_strings = grouped_strings.values if grouped_strings.size > top grouped_strings.sort_by!(&:size) grouped_strings = grouped_strings.drop(grouped_strings.size - top) end grouped_strings .sort! { |a, b| a.size == b.size ? a[0].string_value <=> b[0].string_value : b.size <=> a.size } .map! do |list| # Return array of [string, [[location, count], [location, count], ...] [ list[0].string_value, list.group_by { |stat| stat.location } .map { |location, stat_list| [location, stat_list.size] } .sort_by!(&:last) .reverse! ] end end
Private Instance Methods
dump_data(io, type, metric, name, options)
click to toggle source
# File lib/memory_profiler/results.rb, line 195 def dump_data(io, type, metric, name, options) print_title io, "#{type} #{metric} by #{name}" data = self.send "#{type}_#{metric}_by_#{name}" scale_data = metric == "memory" && options[:scale_bytes] normalize_paths = options[:normalize_paths] if data && !data.empty? data.each do |item| count = scale_data ? scale_bytes(item[:count]) : item[:count] value = normalize_paths ? normalize_path(item[:data]) : item[:data] print_output io, count, value end else io.puts "NO DATA" end nil end
dump_strings(io, type, options)
click to toggle source
# File lib/memory_profiler/results.rb, line 215 def dump_strings(io, type, options) strings = self.send("strings_#{type}") || [] return if strings.empty? options = {} unless options.is_a?(Hash) if (limit = options[:limit]) return if limit == 0 strings = strings[0...limit] end normalize_paths = options[:normalize_paths] print_title(io, "#{type.capitalize} String Report") strings.each do |string, stats| print_output io, (stats.reduce(0) { |a, b| a + b[1] }), @colorize.string(string.inspect) stats.sort_by { |x, y| [-y, x] }.each do |location, count| location = normalize_path(location) if normalize_paths print_output io, count, location end io.puts end nil end
print_output(io, topic, detail)
click to toggle source
# File lib/memory_profiler/results.rb, line 191 def print_output(io, topic, detail) io.puts "#{@colorize.path(topic.to_s.rjust(10))} #{detail}" end
print_title(io, title)
click to toggle source
# File lib/memory_profiler/results.rb, line 185 def print_title(io, title) io.puts io.puts title io.puts @colorize.line("-----------------------------------") end
total_memsize(stat_hash)
click to toggle source
# File lib/memory_profiler/results.rb, line 177 def total_memsize(stat_hash) sum = 0 stat_hash.each_value do |stat| sum += stat.memsize end sum end