class MemKit::Profiler

Public Class Methods

collect(limit: nil) click to toggle source
# File lib/mem_kit/profiler.rb, line 50
def self.collect(limit: nil)

  @rvalue_size ||= GC::INTERNAL_CONSTANTS[:RVALUE_SIZE]

  total_memory_size = ObjectSpace.memsize_of_all

  result = { total_memory_usage: format_size(total_memory_size), total_allocations: ObjectSpace.each_object{}, symbol_count: Symbol.all_symbols.size, object_counts: ObjectSpace.count_objects, objects: [] }

  ObjectSpace.each_object do |o|
    update_object(o, result, total_memory_size)
  end

  result[:objects].sort! { |a,b| b[:bytes] <=> a[:bytes] }

  if limit != nil
    result[:objects] = result[:objects][0, limit]
  end

  return result

end
format_percentage(value, total) click to toggle source
# File lib/mem_kit/profiler.rb, line 111
def self.format_percentage(value, total)
  return "#{(value.to_f / total.to_f * 100.0).round(2)}%"
end
format_size(bytes) click to toggle source
# File lib/mem_kit/profiler.rb, line 79
def self.format_size(bytes)
  value = bytes
  unit = 'Bytes'
  if bytes >= 100000
    #format as MB
    value = (bytes.to_f / 1000.0 / 1000.0).round(2)
    unit = 'MB'
  elsif bytes >= 500
    #format as KB
    value = (bytes.to_f / 1000.0).round(2)
    unit = 'KB'
  end
  return "#{value} #{unit}"
end
is_running() click to toggle source
# File lib/mem_kit/profiler.rb, line 6
def self.is_running
  return @is_running
end
start(logger: nil, interval: 120, limit: nil) click to toggle source
# File lib/mem_kit/profiler.rb, line 10
def self.start(logger: nil, interval: 120, limit: nil)

  if logger == nil
    logger = Logger.new(STDOUT)
  end

  logger.debug("[MemKit::Profiler] - Starting Memory Profiling. Interval: #{interval} seconds | Limit: #{limit || 'N/A'}.")

  %w'INT TERM'.each do |sig|
    Signal.trap(sig) {
      stop
    }
  end

  if @is_running == true
    raise "[MemKit::Profiler] - Profiler is already running."
  end

  @is_running = true

  @thread = Thread.new do

    while @is_running == true do

      GC.start

      result = collect(limit: limit)

      logger.debug("[MemKit::Profiler}] - #{JSON.dump(result)}")

      sleep(interval)

    end

  end

  return @thread

end
stop() click to toggle source
# File lib/mem_kit/profiler.rb, line 72
def self.stop
  @is_running = false
  if @thread != nil
    Thread.kill(@thread)
  end
end
update_object(object, result, total_memory_size) click to toggle source
# File lib/mem_kit/profiler.rb, line 94
def self.update_object(object, result, total_memory_size)
  obj = result[:objects].detect { |o| o[:klass] == object.class }
  if obj == nil
    mem_usage = ObjectSpace.memsize_of(object) + @rvalue_size
    # compensate for API bug
    mem_usage = @rvalue_size if mem_usage > 100_000_000_000
    obj = { klass: object.class, allocation_count: 1, memory_usage_size: format_size(mem_usage), memory_usage_percentage: format_percentage(mem_usage, total_memory_size), bytes: mem_usage }
    result[:objects].push(obj)
  else
    obj[:allocation_count] += 1
    obj[:bytes] += ObjectSpace.memsize_of(object)
    obj[:memory_usage_size] = format_size(obj[:bytes])
    obj[:memory_usage_percentage] = format_percentage(obj[:bytes], total_memory_size)
  end
  return obj
end