Solaris でメモリの利用量を記録する2016年08月24日 12時24分00秒

olaris C++ コンパイラがメモリ不足で落ちる時のエラーを調べるのに作ったスクリプト。
#!/bin/sh

CC=....

$CC $1 &

pid=$!
while ps -p `pgrep -p $pid` -o vsz
    do sleep 1
done | grep -v VSZ > $1.mem
CC にコンパイルオプションを渡しておき、$1 にてファイル名を指定している。ps -p で pid を指定して ps を行い、ps -o vsz にてメモリの利用量を表示する。

top でも見たり出来るが、記録をしづらい。また、表示プロセス数が多いと圏外にいってしまったりする。

前回

自己解凍・実行形式のシェルスクリプト2016年07月22日 11時45分08秒

シェルスクリプトを実行すると、自分で組み込まれたファイルを展開し実行する実装をしたことがある。一つのプログラムとしてまとめるのが困難で、いくつもの細かいプログラムを使って処理する必要があった。しかし、複数のファイルを各々インストールするのも手間が掛かりすぎるために、一つにまとめたのだ。

tar でファイルをまとめて、uuencode を使って文字に変換し、エディタで開いたりしても、問題ない形にする。実行するときは、自身に uudecode をかけて、まとめた分を展開し、処理を移行すれば良い。

-C を複数回使うと、付属の tar では動作が異なり GNU tar を使うのが一番移植性があった。二度目の -C が一度目からの相対位置になるか、プログラムが実行された位置を元にするのか等の違いがある。gtar は前回の位置を基準にする。

$ gtar cvf - program.pm -C ../../dir1 *.pm -C ../../dir2 *.pm | compress -c uuencode encoded.tar.Z >> driver.sh
driver.sh と言う名前のシェルスクリプトを使った。そして、driver.sh の方で行うのが展開作業。
mkdir $tmp
cat $0 | uudecode -o /dev/stdout | uncompress -c | ( cd $tmpdir ; tar xf - )

...
$tmp/program.pm
引数の処理などをしてから、$0 で自分自身を読み出す。uudecode は -o /dev/stdout の形がどの UNIX でも使えるようだ。そして、tar に入れておいた program.pm を呼び出して、プログラムの実行を移す。

Solaris のリンカーはファイル単位2016年07月07日 15時28分18秒

Solaris のリンカーがアーカイブファイルからオブジェクトファイルを取得するのはファイル単位だ。ar 等を見ても、静的ライブラリのシンボルを並び替えることはしない。また、複数の関数が一つのファイルに定義されていると、ファイルにある全ての関数が実行形式のファイルに取り込まれる。

さて、ここでのファイル単位とは、コンパイル毎のファイルに相当する。別の言い方をすれば、.o ファイル単位だ。元が、C 言語や Fortran でも大して変わらない。Solaris の .a のアーカイブファイルは .o ファイルを寄せ集めた物になる。動作的には tar に似ている。そのため、.a ファイルから一つの関数を探すことになっていても、全ての .o ファイルを取り込むわけではない。

少し具体例をあげるとする。main 関数が 関数 a を呼ぶとしよう。そして、そして、関数 a、関数 b、関数 c が一つの .c ファイルに実装されて、アーカイブファイルに取り込まれているとする。そうすると、このプログラムをリンクすると、プログラムは不要ではあるが、関数 b と関数 c の実装を取り込むことになる。

リンカーは基本的に全ての未解決シンボルを探そうとする。もし関数 b や関数 c が他の関数を呼んでいると、それらの実装も取り込むことになる。そして、この関数呼び出しの連鎖は終点まで続く。

そのため、Solaris 上では、実装を一つのファイルにあまりに無造作にかつ、大量に詰め込んでライブラリを作成すると、プログラムが肥大化する弊害が起きる。

Solaris C++ コンパイラがメモリ不足で落ちる時のエラー2015年11月05日 13時06分18秒

Solaris C++ コンパイラがメモリ不足で落ちる時のエラー。
>> Assertion:  DBGGEN ERROR: FILE="../src/dbg_alloc.c", LINE=%23, Ran out of
memory [DBG_GEN 5.3.3] (../lnk/dbg_dbggen.cc, line 4518)
    while processing .cpp at line 0.

Solaris のコンパイラは、コードの不正を見付けて終了する時には、オブジェクトファイルをしっかりと削除して終了してくれるが、このエラーの時は、コンパイラ自体が異常終了するため、オブジェクトファイルが消されない。そのため、make を使うと、二度目はファイルが存在するため通過してしまうが、リンカーが失敗する。

前回

Solaris C++ コンパイラがメモリ不足で落ちる2015年08月25日 12時44分42秒

この度、Solaris の C++ コンパイラがメモリ不足で落ちる自体になった。ほぼ 2GB のメモリを割り当てた後に、コンパイラが異常終了してしまう。

コンパイラの動作と、コードを見ていると、テンプレートの処理に大量のメモリが必要になるようだ。

あまり作法良く書かれたコードでは無いので、インライン関数やテンプレートが乱用されている。インライン関数自体は害では無いのだが、インラインにするために大量のヘッダーを #include しているため、どのヘッダーを読み込んでも大量のインライン関数に遭遇し、それに加えて大量のテンプレートが散りばめられている。

ヘッダーはフィルから綺麗に書き直すのが正攻法なのだが、時間と手間的にも無理。目の前のコンパイルできないソースから処理していくしかない。単純だが、最初に行なうのは cpp ファイルの分割。なるべく、必要なヘッダー毎に組になるように分ける。その後に、徐々に分割するしか無い。

signal SEGV (access to address exceeded protections)2015年03月03日 01時08分46秒

プロセスが正体不明のクラッシュをする。同じコードでもプログラムによって、問題なかったり、クラッシュをしたりする場合がある。また、デバッガによっては問題ない時もあった。そこで、dbx で動かしたら、signal SEGV (access to address exceeded protections) が出て止まった。

原因は、スタックに大きい構造体の配列を作ったことだった。特にスレッドプログラムの各々のスタックサイズを越えてしまったかららしい。修正は、malloc/calloc と free を用いてヒープからメモリを割り当てること。

どの UNIX でも ccyymmdd 形式で date を取得2014年07月19日 12時12分58秒

特に Solaris に入っている date が古くて、どのプラットフォームでも動くシェルスクリプトを書くのには気をつかう。Linux などは、/bin/sh といっても現実は bash であり、FreeBSD も ash、AIX などは ksh になっている。Solaris の sh は本当に最古参の物なので、変数を export する時にはしっかり改行しないといけなかったりする程。特に苦手だったのは date の出力の統一。

やっと一番好きな書式をどこでも出せるものを知った。


% date "+%Y%m%d"

で、四桁の西暦、二桁ずつの月日が出せる。

まずは、Solaris から、順次アクセス出来るプラットフォームで。


Solaris % /usr/bin/date "+%Y%m%d"
20140718
Solaris % /usr/xpg4/bin/date "+%Y%m%d"
20140718
AIX % date "+%Y%m%d"
20140718
FreeBSD % date "+%Y%m%d"
20140718
Liunx % date "+%Y%m%d"
20140718

Solaris で /dev/stdout2014年03月26日 16時54分22秒

Solaris 11 の試用機が幾つか入ってきた。

一部のスクリプトが動かなくなっている。調べてみると、/dev/stdout への出力が出来なくなっていた。/dev/stdin、/dev/stdout、/dev/stderr は、その名の通り stdin 等のデバイス。ファイルにしか出力できないプログラムでパイプを使いたいときには、/dev/stdout が重宝する。

vfstab に fd が記載されていなかったのが問題だったようだ。


fd       -       /dev/fd fd      -       no      -

これをマウント後にこれらのデバイスが見えるようになる。

$ ls /dev/fd
0   1   10  11  12  13  14  2   3   4   5   6   7   8   9

Solaris の id2014年02月01日 13時44分32秒

id -unの件だが、Solaris だと、/usr/xpg4/bin/id の id でないと、-un のオプションが使えないようだ。

PATH に気を付けないと /usr/bin のものを使ってしまい、id -un では動かない。

ディレクトリ内のファイル数2014年01月11日 13時28分07秒

あるディレクトリ内にファイルが数万個だか、数十万個だかが作られていたらしい。どうなるかと言うと、ファイル操作が遅くなるのだ。ディレクトリの閲覧はもちろん、更新なども全てが遅くなる。

あまりにも増えてしまうと、シェルのコマンドラインの展開も出来なくなるし、削除をするのも色々と時間がかかり大変になる。今回の件では Solaris だったが、他も似たようなものだと思う。

実際に起こると結構見付けづらい問題だ。読み書きの速度が致命的な程に落ちたりするのだが、fsck などを含めてあれこれの診断も問題ないと出してくる。原因不明のディスクの速度低下があったら、find などで、ファイル構造を見るのは習慣にした方が良さそうだ。