Class: Memtf::Analyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/memtf/analyzer.rb

Overview

Encapsulates logic that measures the memory footprint of all objects at a given point in time and compares the memory footprints of two points in time.

Defined Under Namespace

Classes: Memory

Constant Summary collapse

DEFAULT_THRESHOLD =

The threshold of total memory consumption required to be included in the output

0.005
MB =

Represents 1 million bytes

1024.0**2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Analyzer

Returns a new instance of Analyzer.



60
61
62
63
64
# File 'lib/memtf/analyzer.rb', line 60

def initialize(options={})
  @filter         = options[:filter]
  @threshold      = options.fetch(:threshold, DEFAULT_THRESHOLD)
  @memory_tracker = options.fetch(:memory_tracker, Memtf::Analyzer::Memory)
end

Instance Attribute Details

#filterObject (readonly)

Returns the value of attribute filter.



6
7
8
# File 'lib/memtf/analyzer.rb', line 6

def filter
  @filter
end

#memory_trackerObject (readonly)

Returns the value of attribute memory_tracker.



6
7
8
# File 'lib/memtf/analyzer.rb', line 6

def memory_tracker
  @memory_tracker
end

#thresholdObject (readonly)

Returns the value of attribute threshold.



6
7
8
# File 'lib/memtf/analyzer.rb', line 6

def threshold
  @threshold
end

Class Method Details

.analyze(options = {}) ⇒ Object

Determine the memory footprint of each class and filter out classes that do not meet the configured threshold.

Parameters:

  • options (Hash) (defaults to: {})


18
19
20
# File 'lib/memtf/analyzer.rb', line 18

def self.analyze(options={})
  new(options).analyze
end

.analyze_group(group) ⇒ Hash

Compare the memory footprints for the start and end memory snapshots within the same snapshot group.

Parameters:

  • group (String)

Returns:

  • (Hash)


27
28
29
30
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
# File 'lib/memtf/analyzer.rb', line 27

def self.analyze_group(group)
  start_analysis = Memtf::Persistance.load(Memtf::START, group)
  end_analysis   = Memtf::Persistance.load(Memtf::STOP,  group)

  comparison    = {}
  total_memsize = 0

  end_analysis.each do |clazz,end_stats|
    start_stats       = start_analysis[clazz]
    comparison[clazz] = {}

    end_stats.each do |stat_key, stat_values|
      start_val = start_stats.nil? ? 0 : start_stats[stat_key]
      end_val   = end_stats[stat_key]
      delta     = end_val - start_val

      comparison[clazz][stat_key]            = end_val
      comparison[clazz]["#{stat_key}_delta"] = delta

      total_memsize += end_val if stat_key == 'size'
    end
  end

  # Determine the relative memory impact of each class
  # TODO look into object count impact via ObjectSpace.count_objects
  comparison.keys.each do |klazz|
    stats           = comparison[klazz]
    stats['impact'] = (stats['size']*1.0) / total_memsize
  end

  comparison
end

Instance Method Details

#analyzeHash

Determine the memory footprint of each class and filter out classes that do not meet the configured threshold.

Returns:

  • (Hash)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/memtf/analyzer.rb', line 70

def analyze
  # Signal a new GC to attempt to clear out non-leaked memory
  # TODO investigate ObjectSpace.garbage_collect
  GC.start

  classes_stats = {}
  # TODO investigate ObjectSpace.count_objects_size[:TOTAL]
  total_memsize = 0

  # Track the memory footprint of each class
  # and calculate the cumulative footprint.
  #
  # Output:
  #
  #   {
  #     'Hash'   => [10, 15],
  #     'Fixnum' => [1],
  #     'Array'  => [20, 30, 40],
  #     'String' => [2,1]
  #   }
  #
  memory_tracker.iterate do |obj|
    if (clazz = obj.class).respond_to?(:name)
      class_name    = clazz.name
      class_stats   = (classes_stats[class_name] ||= [])

      obj_memsize   = memory_tracker.size_of(obj)
      class_stats   << obj_memsize

      # Note: could also use ObjectSpace.memsize_of_all(clazz)
      total_memsize += obj_memsize
    end
  end

  sorted_mem_hogs = identify_hogs(classes_stats, total_memsize)
  translate_hogs(sorted_mem_hogs)
end