Class: MemoryProfiler::Reporter

Inherits:
Object
  • Object
show all
Defined in:
lib/memory_profiler/reporter.rb

Overview

Reporter is the top level api used for generating memory reports

Examples:

Measure object allocation in a block


report = Reporter.report(top: 50) do
  5.times { "foo" }
end

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Reporter

Returns a new instance of Reporter.



13
14
15
16
17
18
# File 'lib/memory_profiler/reporter.rb', line 13

def initialize(opts = {})
  @top          = opts[:top] || 50
  @trace        = opts[:trace]
  @ignore_files = opts[:ignore_files]
  @allow_files = Array(opts[:allow_files])
end

Instance Attribute Details

#topObject (readonly)

Returns the value of attribute top.



11
12
13
# File 'lib/memory_profiler/reporter.rb', line 11

def top
  @top
end

#traceObject (readonly)

Returns the value of attribute trace.



11
12
13
# File 'lib/memory_profiler/reporter.rb', line 11

def trace
  @trace
end

Class Method Details

.report(opts = {}, &block) ⇒ Object

Helper for generating new reporter and running against block



21
22
23
# File 'lib/memory_profiler/reporter.rb', line 21

def self.report(opts={}, &block)
  self.new(opts).run(&block)
end

Instance Method Details

#allow_file?(file) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
80
# File 'lib/memory_profiler/reporter.rb', line 77

def allow_file?(file)
  return true if @allow_files.empty?
  !/#{@allow_files.join('|')}/.match(file).to_s.empty?
end

#ignore_file?(file) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
75
# File 'lib/memory_profiler/reporter.rb', line 72

def ignore_file?(file)
  return true if file == __FILE__
  @ignore_files && @ignore_files =~ file
end

#object_list(generation, rvalue_size) ⇒ Object

Iterates through objects in memory of a given generation. Stores results along with meta data of objects collected.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/memory_profiler/reporter.rb', line 84

def object_list(generation, rvalue_size)

  results = StatHash.new
  objs = []

  ObjectSpace.each_object do |obj|
    next unless generation == ObjectSpace.allocation_generation(obj)
    begin
      if trace_all? || trace.include?(obj.class)
        objs << obj
      end
    rescue
      # may not respond to class so skip
    end
  end

  objs.each do |obj|
    file = ObjectSpace.allocation_sourcefile(obj)
    next if !allow_file?(file) || ignore_file?(file)

    line       = ObjectSpace.allocation_sourceline(obj)
    class_path = ObjectSpace.allocation_class_path(obj)
    method_id  = ObjectSpace.allocation_method_id(obj)

    class_name = obj.class.name rescue "BasicObject"
    begin
      object_id = obj.__id__

      memsize = ObjectSpace.memsize_of(obj) + rvalue_size
      # compensate for API bug
      memsize = rvalue_size if memsize > 100_000_000_000
      results[object_id] = Stat.new(class_name, file, line, class_path, method_id, memsize)
    rescue
      # __id__ is not defined, give up
    end
  end

  results
end

#run(&block) ⇒ MemoryProfiler::Results

Collects object allocation and memory of ruby code inside of passed block.

Parameters:

  • opts (Hash)

    the options to create a message with.

Returns:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/memory_profiler/reporter.rb', line 31

def run(&block)

  allocated, rvalue_size = nil

  rvalue_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]
  Helpers.full_gc
  GC.disable

  ObjectSpace.trace_object_allocations do
    generation = GC.count
    block.call
    allocated = object_list(generation, rvalue_size)
  end

  results = Results.new
  results.strings_allocated = results.string_report(allocated, top)

  GC.enable

  Helpers.full_gc

  retained = StatHash.new
  ObjectSpace.each_object do |obj|
    begin
      found = allocated[obj.__id__]
      retained[obj.__id__] = found if found
    rescue
      # __id__ is not defined on BasicObject, skip it
      # we can probably trasplant the object_id at this point,
      # but it is quite rare
    end
  end

  results.register_results(allocated, retained, top)
  results
end

#trace_all?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/memory_profiler/reporter.rb', line 68

def trace_all?
  !trace
end