Class: StripMem::App

Inherits:
Object
  • Object
show all
Defined in:
lib/stripmem/app.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv) ⇒ App

Returns a new instance of App.



21
22
23
24
# File 'lib/stripmem/app.rb', line 21

def initialize(argv)
  @command = argv
  @start_time = Time.now
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



26
27
28
# File 'lib/stripmem/app.rb', line 26

def command
  @command
end

#start_timeObject (readonly)

Returns the value of attribute start_time.



26
27
28
# File 'lib/stripmem/app.rb', line 26

def start_time
  @start_time
end

Class Method Details

.run!(argv) ⇒ Object



17
18
19
# File 'lib/stripmem/app.rb', line 17

def self.run!(argv)
  new(argv).run!
end

Instance Method Details

#find_childrenObject



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/stripmem/app.rb', line 55

def find_children
  children = `ps a -o ppid=,pid=,command=`.lines.each_with_object(Hash.new { |h,k| h[k] = [] }) { |line, h| (line =~ /(\d+) +(\d+) +(.*)/) && h[$1].push(:pid => $2, :name => $3) }
  parents = processes.keys
  while parent = parents.shift
    children[parent.to_s].each do |child|
      if child[:name] !~ /^ps /
        pid = child[:pid].to_i
        parents << pid
        processes[pid] ||= child[:name]
      end
    end
  end
end

#kill!Object



49
50
51
52
53
# File 'lib/stripmem/app.rb', line 49

def kill!
  Process.kill('QUIT', @child.to_i) unless @child_status
rescue => e
  puts "kill #{@child.inspect}: #{e}"
end

#processesObject



75
76
77
# File 'lib/stripmem/app.rb', line 75

def processes
  @processes ||= { $$ => '(stripmem)' }
end

#ps(channel) ⇒ Object



69
70
71
72
73
# File 'lib/stripmem/app.rb', line 69

def ps(channel)
  ps = `ps -o pid=,rss= -p #{processes.keys.join(',')}`.lines.each_with_object({}) { |line, h| pid, rss = line.split(/\s+/) ; h[pid.to_i] = rss.to_i }
  offset = Time.now - start_time
  channel.push :offset => offset, :samples => processes.map { |pid, name| { :name => "[#{pid}] #{name}", :rss => ps[pid] } }
end

#run!Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/stripmem/app.rb', line 28

def run!
  @timers = []
  EventMachine.run do
    spawn!
    channel = EM::Channel.new
    @timers = [
      EM::PeriodicTimer.new(1.0) { find_children },
      EM::PeriodicTimer.new(0.2) { ps(channel) },
      EM::PeriodicTimer.new(1.0) { wait_child },
    ]
    WebSocket.new(channel).run!
    Thread.new do
      Web.new(channel).run! # This doesn't return until sinatra exits. (Sinatra handles SIGINT.)
      kill!
      EM.stop
      exit
    end
  end
  kill!
end

#spawn!Object



79
80
81
82
83
84
# File 'lib/stripmem/app.rb', line 79

def spawn!
  @child = fork do
    exec(*command)
  end
  processes[@child] = command.join(' ')
end

#wait_childObject



86
87
88
89
90
91
92
# File 'lib/stripmem/app.rb', line 86

def wait_child
  if @child_status ||= Process.waitpid2(-1, Process::WNOHANG)
    @timers.each do |timer|
      timer.cancel
    end
  end
end