GaucheはBoehm GCを使っている: A garbage collector for C and C++
(2002/12/01 20:01:41 PST) たっちん gc の話題ではないですが、他にないのでここに書きます。
pair-attribute はどういう意図で用意したのですか。現在は source-info にしか使っていないようですが。これのために ScmPairRec にポインタひとつ追加するのはもったいないような気がしますけど。
(2002/09/18 06:08:37 PDT) satoru ただいま作っているメールフィルタを実行すると
GC Warning: Finalization cycle involving 84bb580
という警告が出力されたりされなかったりしされます。 この警告を防ぐにはどうしたらよいものでしょう。
(2002/06/20 04:18:02 PDT) RedHat 7.3だとGauche-0.5.6がgcでクラッシュするという報告があった。 Gauche-0.5.6はBoehm GC-6.0を使っている。 Boehm GC 6.1alpha5だと大丈夫だったというので、 6.1安定版まで待つつもりだった予定を変更して6.1alpha5をインテグレート中。
こういうことが多いと、GCをGauche中に囲い込まない方がいいのかな。 もともと、パフォーマンスチューニングとか、stack GCの実験とかで GCに手を入れる可能性があったためGaucheの中に入れておいたのだが。
Boehm GC 6.1はlibtoolを使っている。Gauche本体の方では今までなんとなく libtoolを避けて来たのだが、どうせGCの方で使うならGauche本体にも 入れてしまおうか。
(2002/06/20 22:17:35 PDT) Gauche-0.5.6までは、プロセッサがi686以上だったら Boehm GCのコンパイル時にUSE_I686_PREFETCHを定義するようにconfigure.in とMakeifle.inに手を入れていた。 Boehm GCのドキュメントに「かなり効く」みたいなことが書いてあったからだ。
Boehm GC-6.1alpha5ではautomakeを使っているので、 Makefile.inにまた手を入れるのも気がひける。そこで、 USE_I686_PREFETCHがどのくらい効いているかを簡単に調べてみた。 defaultがGC-6.1alpha5のままでconfigure+makeした場合、 prefetchがUSE_I686_PREFETCHを入れた場合。 なお、比較のためにGauche-0.5.6そのもの(GC-6.0)も示してある。
applicaton: compplot cvt -----------+----------+---------- default | 89.93 | 5.80 prefetch | 88.93 | 5.67 0.5.6 | 94.80 | 6.57
数値はtimeコマンドで測ったuser time(second)の平均。 一応ヒープの消費が多そうなスクリプトを選んだつもり。 プラットフォームはLinux (RH7.2, kernel 2.4.7, gcc 2.96, glibc2.2.4)/Pentium III 450MHz.
まあ、多少は効いているのかもしれない。 それより、0.5.6から速くなったのにちょっとびっくり。
なお、GCのコンパイルフラグはMYCFLAGSで指定できるみたいなんで、 GC本体のソースではなく、MYCFLAGS経由でフラグを渡す方が良さそうだ。
(2002/06/21 03:04:35 PDT) libtool....
現行のbuild processのだとMac OS Xでfail. GCの方がlibtoolizeされたため、 static link用のgc/*.oとdynamic link用のgc/*.loが別々に生成されるのだが、 gc/*.o が-fno-commonでコンパイルされない。libgaucheの方ではこれまで gc/*.oを-fno-commonでコンパイルしてリンクしていたので、これではまずい。 取るべき道は。
うーん。現状でマルチプラットフォームでshared libraryをサポートするのに、 libtool以上のツールは無いとは思うんだが、libtoolの持ち込む複雑さが 嫌なんだよなあ。なんとなく本能的に避けたくなる類の複雑さなんだ。
(2002/08/02 02:04:53 PDT) コンパイルフラグ
Boehm GC 6.1alpha5に入れ換えた時に、コンパイルフラグをほぼデフォルトのまま 使うようにしたのだが、それだとDONT_ADD_BYTE_AT_ENDがdefineされていなかった。 ALL_INTERIOR_POINTERSがdefineされているので、GC_mallocは要求バイト数より 1バイトだけ多めにallocateする(現実的には1ワード余分になる)。
これだけならメモリ喰いなだけでロジック的には正しく動作するはずなのだが、 pairのアロケートに関してはGCのインラインマクロを使っており、きっちり4ワード アロケートしていた。ところがDONT_ADD_BYTE_AT_ENDをdefineしないと、 オブジェクトの最終ワードをgcがスキャンしないという。 pairの場合、最終ワードはpair attributeに使われている。 現在のところ、pair attributeはソースコード情報を格納するのにだけ 使われている。これがgcで回収されてしまっていたため、 エラー時のスタックトレースがおかしくなっていたのであった。
何でGCがこんな仕様になっているのかと言えば、Cの仕様ではオブジェクトの 配列の最終要素の「次」を指すことが許されているからなんだろうが、 Gaucheでは唯一のポインタがそういう場所を指すような使い方はしていない はずなので問題ない。Gauche-0.6.1ではDONT_ADD_BYTE_AT_ENDをdefineした。
Gauche-0.6で迷ったのは、THREAD_LOCAL_ALLOC。マルチスレッド時にこれを defineしておくと、各スレッドがメモリプールを持って、グローバルから メモリを取って来るのはメモリプールを使い切った時のみになる。 ローカルのメモリプールからmallocする際はロックする必要が無いから、 かなりスピードが速くなる可能性がある、とドキュメントにはある。
ところが、マルチスレッドでTHREAD_LOCAL_ALLOCをdefineして ビルドしたgoshでシングルスレッドアプリケーションを走らせると、 ものすごく(20%程度)速度が低下した。THREAD_LOCAL_ALLOCの元では GC内のlockが重くなる(spin lockを使わないようになる)のが原因ではないかと 睨んでいるのだが、とにかくこれでは話にならない。 goshの想定する応用範囲ではシングルスレッドのスクリプトが多いと 考えられるので、ここはそちらを優先してTHREAD_LOCAL_ALLOCはデフォルトで 使わないことにした。
もともと、シングルプロセッサマシンでgoshをマルチスレッドで走らせる 第一の意味は、ブロッキングI/Oを扱うコードが書きやすいという点だと 考えている。協調スレッドならcall/ccで書けるわけだし。 だもんで、マルチスレッド化による性能の向上というのはあまり期待していない。
マルチプロセッサマシン上でgoshをマルチスレッドで使って性能を上げたい、 という場合はTHREAD_LOCAL_ALLOCをdefineした方が良いかもしれない。 手元に環境が無いので試せないのだが。
Tag: GC