2011年10月30日日曜日

bash で処理時間を 10 ミリ秒単位で計測する方法

bash スクリプト中の特定部分の処理時間(経過時間)を、1秒より細かい粒度で計測したいため、その方法を考えてみました。

まず、秒単位で良ければ、次の場所にあれこれと書いてある方法で良いかと思います。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=22451&forum=10

ただ、bash には組み込み変数 SECONDS (シェルが起動されてからの経過秒数) があるので、次のように書いたほうがオーバーヘッドが少ないはずです。
#!/bin/bash
#
# Name: elaps.bash
#

sleep 1

START=$SECONDS  #bash's builtin
echo START=$START

echo -e "\n### sleep 2"
sleep 2
echo

END=$SECONDS
let ELAPS=$END-$START
echo END=$END
echo ELAPS=START-END=$ELAPS
# ./elaps.bash 
START=1

### sleep 2

END=3
ELAPS=START-END=2

さて、わたしが取り組んでいる内容に対して、秒では粗すぎます。ミリ秒程度まで取得したいのですが、標準では bash から直接 gettimeofday() を呼ぶことができません。builtin を作れば不可能ではありませんが、ターゲットがそこまで自由に出来る環境ではないので、別の方法を考えました。

目をつけたのは、/proc/uptime です。このファイルから、システム起動からの経過時間を 10 ミリ秒の粒度で読み取ることができます。man proc 参照。
# cat /proc/uptime 
4542.13 4528.56
# uptime
 11:42am  up  1:15,  2 users,  load average: 0.13, 0.07, 0.02
bash の組み込みコマンド read を利用すれば、オーバーヘッド少なく 10 ミリ秒の粒度で経過時間を計測できるはずです。次が、テストスクリプトです。
#!/bin/bash
#
# Name: elaps_ms.bash
#

set_START() {
        local dummy
        read START dummy < /proc/uptime
}

get_ELAPS() {
        local dummy
        read END dummy < /proc/uptime
        let ELAPS=${END/./}0-${START/./}0
}

echo SECONDS=$SECONDS   #bash's builtin
time {
        set_START
}
echo START=$START

echo -e "\n### sleep (50 x 10 x 1000) [us]  using usleep"
time {
        usleep 500000
}

time {
        get_ELAPS
}
echo END=$END
echo ELAPS=START-END=$ELAPS
echo
echo SECONDS=$SECONDS   #bash's builtin
# ./elaps_ms.bash 
SECONDS=0

real    0m0.001s
user    0m0.000s
sys     0m0.000s
START=5579.40

### sleep (50 x 10 x 1000) [us]  using usleep

real    0m0.520s
user    0m0.000s
sys     0m0.010s

real    0m0.001s
user    0m0.000s
sys     0m0.000s
END=5579.92
ELAPS=START-END=520

SECONDS=0
このように、500 ミリ秒の usleep 実行の経過時間を 52 x 10 ミリ秒 = 520 ミリ秒と計測することができました。bash 組み込みの time コマンドの計測結果とも一致しています。一方、SECONDS による計測では、0 秒となってしまっています。

さてここで、少しだけ気になる点があります、bash で扱える整数の範囲です。上述のテストスクリプトでは、/proc/uptime から読み取った小数(小数点以下 2 桁)を、単位ミリ秒の整数に変換しています。1日をミリ秒で表すと 24 x 60 x 60 x 1000 = 86400000 となりますが、
# getconf INT_MAX
2147483647
# bc -l
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
2147483647 / (24 * 60 * 60 * 1000)
24.85513480324074074074
なので、システム起動から 25 日経過した時に大丈夫かな?と不安になりませんか?
しかし、過去に調べたとおり、最近は 32bit 環境の bash でも、64bit 幅までの整数を扱えるので、大丈夫なはずです。次の記事を参照してください。

bash で扱える整数の上限

2011-11-06追記
試しに bash のビルトインを自作して、もっと細かい粒度で経過時間を測定してみました。

ビルトインを自作して、bash で処理時間をミリ秒単位で計測

2011年10月29日土曜日

perl でモジュールの存在を確認する方法

perl で、使いたいモジュールがシステムにインストールされていない場合に、use hoge.pm のエラー(例外)を捕捉する方法を調べました。
「Perl クックブック VOLUME 1」のレシピ 12.2 に書いてあるのですが、次のような具合にします。
BEGIN {
        $zlib = "Compress::Zlib" ;
        unless (eval "use $zlib ; 1") {
                #warn "WARNING: couldn't use $zlib" ;  # 警告出すか否かは文脈次第
                undef $zlib ;  # あとでこの変数を確認することで、代替処理やエラー処理
        }
}
具体的な利用局面について補足しますと、gzip ファイルデータを直接扱いたかったのですが、わたしの主戦場である RHEL/CentOS では、Compress::Zlib が別パッケージ (perl-Compress-Zlib) になっており、必ずしもインストールされていないため、その場合、仕方ないので gzip コマンドを呼ぶという代行処理を行う必要がありました。

Python の”電池が付属しています”思想のように、perl でもこのあたりまでデフォルトで入っていてくれると手間が減るのにと思ってしまいます。Python の場合、かなり昔から gzip ライブラリが標準で入っているようです。

■関連記事
Perl のモジュール(.pm)のパスを調べたい

2011年10月24日月曜日

CentOS 5 サスペンドメニューを出さないようにする

CentOS 5 で、マシンが対応していると、System メニューに Suspend が表示されるが、これが Log Out のすぐ下に表示されるため、誤操作し易い。
サーバ用途では、サスペンドすることはまずないと思うので、このような位置に表示するというのは、デザイン上のミスじゃないのかと思ってしまいます。もちろん GNOME は、サーバ用途に作られているわけじゃないのでしょうけども、RHEL としてまとめるときに、配慮できないもんでしょうかね。

Suspend メニューを表示しないようにするには、gconf-editor をインストールして、apps / gnome-power-manager の can_suspend を外せば良いです。ついでに、can_hibernate も外しておいたほうが良いかと。


なお、そもそも、安定稼動のためには、サーバで X を使わないのが正解だろうと思います。

2011-11-12追記
コマンドラインからでも修正できるようです。
# gconftool-2 --type boolean --set /apps/gnome-power-manager/can_suspend false
# gconftool-2 --type boolean --set /apps/gnome-power-manager/can_hibernate false
http://blog.toracat.org/2009/04/getting-rid-of-suspend-on-a-desktop-machine/

なお、CentOS 6 では、仕組みが変更されているため、上記の方法は通用しません。
人気ブログランキングへ にほんブログ村 IT技術ブログへ