Class: HeapScope::Snapshot

Inherits:
Object
  • Object
show all
Defined in:
lib/heapscope/snapshot.rb

Overview

Stable snapshot abstraction. Configurable fidelity — not a full heap dump.

Constant Summary collapse

SCHEMA_VERSION =
HeapScope::SCHEMA_VERSION
SLIM_CLASS_LIMIT =
40
SLIM_ALLOC_LIMIT =
20

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, timestamp:, mode:, gc_stat:, rss_bytes:, class_stats:, allocation_sites: {}, metadata: {}, limitations: [], sampled: false, process: {}, duration_ms: 0, object_sample: []) ⇒ Snapshot

Returns a new instance of Snapshot.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/heapscope/snapshot.rb', line 18

def initialize(id:, timestamp:, mode:, gc_stat:, rss_bytes:, class_stats:,
               allocation_sites: {}, metadata: {}, limitations: [],
               sampled: false, process: {}, duration_ms: 0, object_sample: [])
  @id = id
  @timestamp = timestamp
  @mode = mode
  @gc_stat = gc_stat || {}
  @rss_bytes = rss_bytes
  @class_stats = class_stats || {}
  @allocation_sites = allocation_sites || {}
  @metadata =  || {}
  @limitations = limitations || []
  @sampled = sampled
  @process = process || {}
  @duration_ms = duration_ms
  @object_sample = object_sample || []
end

Instance Attribute Details

#allocation_sitesObject (readonly)

Returns the value of attribute allocation_sites.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def allocation_sites
  @allocation_sites
end

#class_statsObject (readonly)

Returns the value of attribute class_stats.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def class_stats
  @class_stats
end

#duration_msObject (readonly)

Returns the value of attribute duration_ms.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def duration_ms
  @duration_ms
end

#gc_statObject (readonly)

Returns the value of attribute gc_stat.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def gc_stat
  @gc_stat
end

#idObject (readonly)

Returns the value of attribute id.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def id
  @id
end

#limitationsObject (readonly)

Returns the value of attribute limitations.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def limitations
  @limitations
end

#metadataObject (readonly)

Returns the value of attribute metadata.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def 
  @metadata
end

#modeObject (readonly)

Returns the value of attribute mode.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def mode
  @mode
end

#object_sampleObject (readonly)

Returns the value of attribute object_sample.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def object_sample
  @object_sample
end

#processObject (readonly)

Returns the value of attribute process.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def process
  @process
end

#rss_bytesObject (readonly)

Returns the value of attribute rss_bytes.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def rss_bytes
  @rss_bytes
end

#sampledObject (readonly)

Returns the value of attribute sampled.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def sampled
  @sampled
end

#timestampObject (readonly)

Returns the value of attribute timestamp.



14
15
16
# File 'lib/heapscope/snapshot.rb', line 14

def timestamp
  @timestamp
end

Class Method Details

.from_h(data) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/heapscope/snapshot.rb', line 126

def self.from_h(data)
  class_stats = (data[:class_stats] || {}).each_with_object({}) do |(name, stats), hash|
    hash[name.to_s] = {
      name: name.to_s,
      count: stats[:count].to_i,
      shallow_bytes: stats[:shallow_bytes].to_i,
      average_bytes: stats[:average_bytes].to_f
    }
  end

  new(
    id: data[:id] || SecureRandom.hex(8),
    timestamp: Time.parse(data[:timestamp].to_s),
    mode: (data[:mode] || "standard").to_sym,
    gc_stat: symbolize_keys(data[:gc_stat] || {}),
    rss_bytes: data[:rss_bytes],
    class_stats: class_stats,
    allocation_sites: data[:allocation_sites] || {},
    metadata: data[:metadata] || {},
    limitations: data[:limitations] || [],
    sampled: data[:sampled] || false,
    process: data[:process] || {},
    duration_ms: data[:duration_ms].to_f,
    object_sample: data[:object_sample] || []
  )
end

.load(path) ⇒ Object



121
122
123
124
# File 'lib/heapscope/snapshot.rb', line 121

def self.load(path)
  data = JSON.parse(File.read(path), symbolize_names: true)
  from_h(data)
end

.stringify_keys(hash) ⇒ Object



153
154
155
# File 'lib/heapscope/snapshot.rb', line 153

def self.stringify_keys(hash)
  hash.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
end

.symbolize_keys(hash) ⇒ Object



157
158
159
# File 'lib/heapscope/snapshot.rb', line 157

def self.symbolize_keys(hash)
  hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
end

Instance Method Details

#class_bytes(name) ⇒ Object



60
61
62
# File 'lib/heapscope/snapshot.rb', line 60

def class_bytes(name)
  (class_stats[name.to_s] || {})[:shallow_bytes].to_i
end

#class_count(name) ⇒ Object



56
57
58
# File 'lib/heapscope/snapshot.rb', line 56

def class_count(name)
  (class_stats[name.to_s] || {})[:count].to_i
end

#gc_generationObject



36
37
38
# File 'lib/heapscope/snapshot.rb', line 36

def gc_generation
  gc_stat[:count]
end

#heap_free_slotsObject



44
45
46
# File 'lib/heapscope/snapshot.rb', line 44

def heap_free_slots
  gc_stat[:heap_free_slots]
end

#heap_live_slotsObject



40
41
42
# File 'lib/heapscope/snapshot.rb', line 40

def heap_live_slots
  gc_stat[:heap_live_slots]
end

#same_process?(other) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/heapscope/snapshot.rb', line 68

def same_process?(other)
  process[:pid] == other.process[:pid]
end

#save(path, slim: false) ⇒ Object



116
117
118
119
# File 'lib/heapscope/snapshot.rb', line 116

def save(path, slim: false)
  File.write(path, JSON.pretty_generate(to_h(slim: slim)))
  path
end

#stringify_keys(hash) ⇒ Object



161
162
163
# File 'lib/heapscope/snapshot.rb', line 161

def stringify_keys(hash)
  self.class.stringify_keys(hash)
end

#to_h(slim: false) ⇒ Object



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
107
108
109
110
# File 'lib/heapscope/snapshot.rb', line 72

def to_h(slim: false)
  stats = class_stats
  sites = allocation_sites
  sample = object_sample
  meta = .dup
  limits = limitations.dup

  if slim
    top = top_classes(SLIM_CLASS_LIMIT)
    stats = top.to_h { |row| [row[:name], row] }
    sites =
      if allocation_sites.is_a?(Hash)
        allocation_sites.to_a.first(SLIM_ALLOC_LIMIT).to_h
      else
        Array(allocation_sites).first(SLIM_ALLOC_LIMIT)
      end
    sample = []
    meta[:slim] = true
    limits << "slim_json_truncated_classes" unless limits.include?("slim_json_truncated_classes")
  end

  {
    schema_version: SCHEMA_VERSION,
    heapscope_version: VERSION,
    id: id,
    timestamp: timestamp.iso8601(3),
    mode: mode.to_s,
    gc_stat: stringify_keys(gc_stat),
    rss_bytes: rss_bytes,
    class_stats: stats.transform_values { |v| stringify_keys(v) },
    allocation_sites: sites,
    metadata: meta,
    limitations: limits,
    sampled: sampled,
    process: process,
    duration_ms: duration_ms,
    object_sample: sample
  }
end

#to_json(*_args) ⇒ Object



112
113
114
# File 'lib/heapscope/snapshot.rb', line 112

def to_json(*_args)
  JSON.pretty_generate(to_h)
end

#top_classes(limit = 20, by: :count) ⇒ Object



64
65
66
# File 'lib/heapscope/snapshot.rb', line 64

def top_classes(limit = 20, by: :count)
  class_stats.values.sort_by { |s| -(s[by] || 0) }.first(limit)
end

#total_allocated_objectsObject



48
49
50
# File 'lib/heapscope/snapshot.rb', line 48

def total_allocated_objects
  gc_stat[:total_allocated_objects]
end

#total_freed_objectsObject



52
53
54
# File 'lib/heapscope/snapshot.rb', line 52

def total_freed_objects
  gc_stat[:total_freed_objects]
end