2015年8月4日火曜日

[Ruby][Linux] 同名のジョブが複数走っている時、区別の手助けになるスクリプト lsrun

研究で、PC に大量のジョブを流すことがあります。
で、どのジョブが終わっている(落ちている)か、走行中かを確認することがあります。

もし、同名のジョブを複数実行している場合、top や ps では区別が付きません。
たとえば、top したときに一番右のカラムが全部 ./a.out とかになってしまいます。

バイナリの名前や引数をジョブごとに変更すれば
区別が付くようになりますが、いちいちやってられません。

で、どうするかというと、ここでは
ファイル /proc/(pid)/cwd がプロセス番号 pid のジョブが走っているディレクトリへの
シンボリックリンクになっていることを利用します。

少なくとも私の場合、同じディレクトリ内で同時並行にジョブを
走らせることはなく、実行ディレクトリのパスは必ず違うからです。

シンボリックリンクの中身を ls -l などでいちいり覗くのは面倒くさいので、
「自分が実行している」「CPU 利用率の高い」ジョブの
実行ディレクトリの一覧を出すようにしたのが以下の Ruby スクリプトです。
勝手に lsrun と名付けました。

#!/usr/bin/env ruby

# これより CPU 使用率が高いプロセスだけ表示
THRE_CPU_USAGE = 10.0
username = ENV['USER']

myprocs = `ps aux | grep #{username}`.split("\n").map{|line| line.split(" ")}

myprocs.each{|proc|
  cpu_usage = proc[2].to_f
  if cpu_usage > THRE_CPU_USAGE then
    pid = proc[1].to_s
    command = proc[10..-1].join(" ").to_s
    cwd = File.readlink("/proc/#{pid}/cwd")
#    puts [pid, cpu_usage.to_s, command, cwd].join(" ")  # 1 行で表示したいとき
    pid = sprintf("%5i", pid.to_i)
    puts [pid+" "+cpu_usage.to_s, "  "+command, "  "+cwd].join("\n")
  end
}

実行結果はこのようになります。

12345 99.9
  ./a.out
  /home/username/work/exp01
23456 99.8
  ./a.out
  /home/username/work/exp02

前から順に、pid、CPU 使用率、実行コマンド(引数がある場合はそれも含む)、実行ディレクトリ、です。

私は見やすさのためにこういう出力形式にしましたが、
1ジョブを1行で出力したい場合は
if ~ end の中にあるコメントアウトを外して、
その後ろ2行を削除してください。