Let's start Scheme

2012-07-01

3,2,1,0 バグッてハニー

コンパイラに少し手を入れたらなんだかSEGVが起きるようになった。
まぁ、普通はいじった部分がおかしいだろうということになるのだが、どうも様子がおかしい。

Cygwinではいまいちなにが起こっているのかわからなかったのでUbuntuで走らせてみてなんとなく見えてきた。(CygwinだとSEGVが起きてもSEGVだと知らせなかったり、意味不明に突然死ぬので)。

とりあえず、再現する方法と、回避できる方法がある。
再現する方法は非常に簡単で、make testをマルチスレッドバージョン(デフォルト)で2回走らせること。2回目はキャッシュを使うのだが、キャッシュを使うとなぜかアウト。
回避するには、test/tests.scmに手を入れてテストをマルチスレッドで行わないこと。こうするとなぜかコンパイルされたキャッシュが正しく作られるっぽい。(複数回走らせてもOKな上に、マルチスレッドで走らせてもOKになる)。

正直意味不明ではあるのだが、とりあえず仮説を立てる。マルチスレッドにしなければ動くということは、コンパイル結果自体には問題はなくて、(実際、キャッシュ読み込みで死んでるわけだし)、キャッシュ作成時に問題が起きている、はず。
ぱっと考え付いたのは以下の3点。
  • コンパイラをいじったために速度が改善されて今まであまり起きなかったロック取得部分の競合でおかしくなった。
  • コンパイル時間が増大したためロック取得で競合が起きるようになった。
  • コンパイルをいじったためGCのタイミングが変わり、今までは起きなかったメモリエラーが起きるようになった。
ロック周りが問題になっているなら、多分2番目・・・。ただ、起きているライブラリはテストケース内では1ファイルででしか使われていないので、読み書きは同一のスレッドで行われているはず。
3つ目はありえそうで、実際つい最近8要素いるはずの配列が7要素しかメモリを割り付けてなかったというのを発見した。同様のことが起きてて、シングルなら回収されないけどマルチだと回収されちゃったっていうのはあるかも。
さて、どうしたものか・・・

解決した。

原因はコンパイラに手を入れたことだった。
lambda liftingのコードを最適化のフェーズとばらす必要があったのだが、そこが問題だった。問題はそれまでライブラリを正しく取っていたのに、ばらされたせいでライブラリの取得が上手く行えておらずマルチスレッド環境で作成される無名ライブラリの情報をキャッシュに落としこめなかったのが問題だった。
修正1行。解析1日。 バグなんてこんなもんだよね。

No comments:

Post a Comment