Gnome で CPU の負荷をお知らせ

awk はシンプルに使って行くのが良いと言われることがあります。 これは awk 単独で全てを行うのではなく、他のツールと合わせて使うことで awk らしくなるということです。 最近流行っている Command-line-fu にはタグクラウドを見ても分かるように多くの awk を使った一行野郎がアップされていますが、awk 単独ではなく、他のコマンドと組み合わせることで威力を発揮していることが分かるでしょう。

この AWK Users JP を運営しているサーバーはLenovo T61 を使っているのですが、どうも Fedora10 になってから IRQ の衝突のような現象に見舞われています。 知らないうちに、CPU の IRQ 負荷が増えていき、リブートすらできなくなっている現象が発生しています。 そうなる前に検知しようと思うのですが、コンソールでワーニングを表示してもウインドウの裏に隠れてしまっていたりすることも多く、気が付いた時にはサーバーが止まってしまっています。 Gnome の最前面で表示してくれるような仕組みが欲しいのですが、awk 単独で GTK を操作することはできませんので、ここでは Python の簡単なスクリプトと連携させてみます。

まず、Python のスクリプトですが、以下のものは第 1 引数をタイトル、第 2 引数を内容とする Gnome 上で Notification (お知らせ) を表示するものです。 なお、ここでは使っていませんが、 Notification() の第 3 引数に画像ファイルを指定すると表示の際に画像も合わせて表示することができます。

#!/usr/bin/python
# notify.py

from pynotify import *
import sys

init("cli notify")
n = Notification(sys.argv[1], sys.argv[2])
n.show()

Python と Gnome の親和性は昔から知られていますが、これだけでできてしまうのが凄いところです。 もちろん、このスクリプトそのものではなく、pynotify が請け負っているのですけどね。 これを $HOME/bin に notify.py という名前で実行権限を付けて保存します。

さて、awk の方ですが、こちらの方が長くなってしまいましたが、以下のようなものです。

#! /usr/bin/gawk -f
# check_irq.awk
# http://d.hatena.ne.jp/greenrine23/20081027/1225128909

BEGIN {

    # Settings
    interval_time       = 180;
    sleep_cmd           = "/bin/sleep";
    notification_cmd    = ENVIRON["HOME"] "/bin/notify.py";
    stat_file           = "/proc/stat";
    title               = "'CPU Info'";     # needs single quote

    # Infinit loop
    for (;;) {

        # Initial
        read_stat(stat_file, i++);

        system(sleep_cmd " " interval_time);

        if (i >= 2) {
            total = 0;

            sub_user    = abs(user[2]      - user[1]);
            sub_nice    = abs(nice[2]      - nice[1]);
            sub_sys     = abs(sys[2]       - sys[1]);
            sub_idle    = abs(idle[2]      - idle[1]);
            sub_iowait  = abs(iowait[2]    - iowait[1]);
            sub_irq     = abs(irq[2]       - irq[1]);
            sub_softirq = abs(softirq[2]   - softirq[1]);

            total = sub_user + sub_nice + sub_sys + sub_idle + \
                    sub_iowait + sub_irq + sub_softirq;

            content = "'"\
                      sprintf("user:%3.2f%, ",    sub_user    / total * 100) \
                      sprintf("nice:%3.2f%, ",    sub_nice    / total * 100) \
                      sprintf("system:%3.2f%, ",  sub_sys     / total * 100) \
                      sprintf("idle:%3.2f%, ",    sub_idle    / total * 100) \
                      sprintf("iowait:%3.2f%, ",  sub_iowait  / total * 100) \
                      sprintf("irq:%3.2f%, ",     sub_irq     / total * 100) \
                      sprintf("softirq:%3.2f%.",  sub_softirq / total * 100) \
                      "'";

            # for debugging
            ##print notification_cmd " " title " " content;
            ##if (i > 3) {exit;}

            system(notification_cmd " " title " " content);
        }
    }
}

# abs():    return absolute number
#   in:     num:    number
#   out:    absolute number of inputed number
function abs(num) {
    if (num < 0) {
        return -num;
    } else {
        return num;
    }
}

# read_stat():  read from stat file and set individual value to array
#   in:     file:   stat file (ex. /proc/stat)
#   in:     num:    number (odd or even)
#   out:    arraies of user, nice, sys, idle, iowait, irq, softirq
function read_stat(file, num) {

    # even:     ititial
    # odd:      measurement point
    if (num % 2 == 0) {
        num = 1;
    } else {
        num = 2;
    }

    while (getline < file > 0) {
        if ($0 ~ /^cpu /) {
            user[num]       = $2;
            nice[num]       = $3;
            sys[num]        = $4;
            idle[num]       = $5;
            iowait[num]     = $6;
            irq[num]        = $7;
            softirq[num]    = $8;
        }
    }
    close(file);
}

計算方法などは proc/statを使ってcpu使用率を計算するに書かれているものを使わせてもらいましたので、そちらを参照してください。

notify.png

内容は 2 分毎に CPU の負荷を notify.py を介して表示するというものです。 Linux では /proc から様々な情報を取得することができ、様々なツールで解析することができます。 ほとんどの情報がテキストになっていますから、awk で簡単に処理することができます。 今回は UI の部分を Python にお任せしましたが、GNU screen を使う場合にはそのまま awk でステータスラインに出力することもできます。

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png