class GemFootprintAnalyzer::Analyzer

A class that faciliates sampling of the original require and subsequent require calls from within the library. It initializes ChildProcess and uses it to start the require cycle in a controlled environment. Require calls are interwoven with RSS checks done from the parent process, require timing is gathered in the child process and passed along to the parent.

Attributes

fifos[R]
options[R]

Public Class Methods

new(fifos, options = {}) click to toggle source

@param fifos [Hash<Symbol>] Hash containing filenames of :child and :parent FIFO files

# File lib/gem_footprint_analyzer/analyzer.rb, line 9
def initialize(fifos, options = {})
  @options = options
  @fifos = fifos
end

Public Instance Methods

test_library(library = nil, require_string = nil) click to toggle source

@param library [String|nil] name of the library or parameter for the gem method

(ex. 'activerecord', 'activesupport').
Nil if user wants to analyze the whole Gemfile

@param require_string [String|nil] optional require string, if it differs from the gem name

(ex. 'active_record', 'active_support/time')

@return [Array<Hash>] list of require-data-hashes, first element contains base level RSS,

last element can be treated as a summary as effectively it consists of all the previous.
# File lib/gem_footprint_analyzer/analyzer.rb, line 21
def test_library(library = nil, require_string = nil)
  child = ChildProcess.new(library, require_string, fifos, options)
  child.start_child
  parent_transport = init_transport
  requires = collect_requires(parent_transport, child.pid)

  parent_transport.ack
  requires
end

Private Instance Methods

collect_requires(transport, process_id) click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 35
def collect_requires(transport, process_id)
  requires_context = {base_rss: nil, requires: [], process_id: process_id, transport: transport}

  while (cmd = transport.read_one_command)
    msg, payload = cmd

    break unless handle_command(msg, payload, requires_context)
  end

  requires_context[:requires]
end
handle_command(msg, payload, context) click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 47
def handle_command(msg, payload, context)
  case msg
  when :require
    context[:requires] << handle_require(context[:process_id], context[:base_rss], payload)
  when :ready
    handle_ready(context)
    context[:transport].start
  when :done then return false
  when :exit then handle_exit(payload)
  end
  true
end
handle_exit(payload) click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 67
def handle_exit(payload)
  puts "Exiting because of exception: #{payload}"
  exit 1
end
handle_ready(context) click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 72
def handle_ready(context)
  return if context[:base_rss]

  context[:base_rss] = rss(context[:process_id])
  context[:requires] << {base: true, rss: context[:base_rss]}
end
handle_require(process_id, base_rss, payload) click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 60
def handle_require(process_id, base_rss, payload)
  cur_rss = rss(process_id) -  base_rss
  name, parent_name, time = payload

  {name: name, parent_name: parent_name, time: Float(time) * 1000, rss: cur_rss}
end
init_transport() click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 83
def init_transport
  reader = File.open(fifos[:child], 'r')
  writer = File.open(fifos[:parent], 'w')

  Transport.new(read_stream: reader, write_stream: writer)
end
rss(process_id) click to toggle source
# File lib/gem_footprint_analyzer/analyzer.rb, line 79
def rss(process_id)
  `ps -o rss -p #{process_id}`.split.last.strip.to_i
end