CPU実験でTravis CIを使ってみた

この記事はCPU実験 Advent Calendar 2015の15日目の記事です。

CPU実験において、僕の班は(主に僕の独断で)Travis CIを導入しました。
もう一度CPU実験の概要について説明します。

CPU実験では主に

  1. コア係(VHDL)
  2. コンパイラ
  3. シミュレータ係
  4. FPU係(VHDL)

の4つの係があり、

  1. コンパイラで所与のレイトレプログラムを実行可能機械語列に変換する
  2. 実機コアと手持ちPC上のシミュレータでそれぞれ実行して差分を比較
  3. 差分がなければ(かつ実機の実行時間が15分以内であれば)単位

という流れになります。FPUはコアに組み込みます。また、シミュレータの浮動小数点演算もx86組み込みのfadd命令ではなく、自班のFPUの動作を模倣するシミュレータを書きます(コア/シミュレータの差分を比較するため)。
ここで重要になってくるのは、いかにしてまずシミュレータをバグなく完成させるかということです。
コアやコンパイラは一般にバグなく書き上げるのは難しいので、シミュレータを正しく動作させるのが先決です。
また、コンパイラ→シミュレータのパスを正確につくり上げることでコア係のデバッグに役立ちます。
というか、コンパイラ→シミュレータのパスに信頼性がないと、コアのバグがコアの原因なのかコンパイラやシミュレータの原因なのかわからず、何からデバッグすればいいか手をつけにくいです。
(CPU実験においてはこういう状況は精神衛生によくない)

そのため、コンパイラ→シミュレータのパスの信頼性を担保するのは重要であり、ここにTravis CIを用いることを考えました。

テストの流れ

1. 必要パッケージのインストール
2. min-camlのビルド
3. シミュレータのビルド
4. テストケースの実行

この流れはMakefileに書きました(make testで実行できるようにした)。実際には.travis.ymlのscript属性にmake testと記述してあります。

【参考】.travis.yml

依存パッケージのインストール

テストケースの実行にはPythonのnoseというユニットテストモジュールを用いているので、pipで必要パッケージをインストールします。

pip install -r .install.txt

また、min-camlはOCamlで記述されているためOCamlが必要です。僕はBytesというモジュールを使っているのですが、これはOCaml 4.0.2から導入されたモジュールです。
しかし、travisで標準で用いられているOCamlはもっと古いので、新しいバージョンをインストールする必要があります。
これはTravis CIでOCamlを使うまでの道のり - Handwritingで紹介したので、参考にしてみてください。

min-caml、シミュレータのビルド

これは普通にビルドするスクリプトを書いただけです。

テストケースの実行

テストケースの実行には、上述の通りPythonのnoseというモジュールを用いました。
これはリポジトリ内にある、「test」と名前についているファイル中に含まれる「test」を冠するテストメソッドを実行します。
説明するより見るほうが早いので、僕が書いたテストスクリプトを置いておきます。

github.com

これが実際に走るとこのログのようになります。
各々のテストメソッドで行っているのはシミュレータの答えと期待される答えが一致しているかどうかのアサーションで、等しければOK、違っていればそこでテストが落ちます。

各々のテストケースはここに置いてあります。
これらのmlファイルを「コンパイルアセンブル→実行」します。

Slackへの通知

TravisはSlackへの通知をサポートしています。pushする度にテストが走り、Slackにテスト結果が通知されます。

Configuring Build Notifications - Travis CI

所感

Travisを使うのは初めてでしたが、pushする度に100行超のログが流れてテストに通るのはなかなか快感でした(自己満足)。
ただ、実際CPU実験の役にたったのかどうかというのは少し疑問です。
というのも、どちらかというとTravisのテストに通すために非本質的なfixを強制されることがありました。
例えば、

  1. uint32_tを使うためにstdint.hのインクルードを強要される
  2. gccのビルドオプションで-D_POSIX_C_SOURCE=199309Lをつけなければならなかった(理由は忘れた)

などなど。まあ恐らくコンパイラアセンブラ、シミュレータのデグレーションは防げていたのだろうけど、逆にデグレーションしなかったからあまりありがたみが感じられなかったのかもしれません。「失って初めて気づく幸せ」というやつですね。

あと、浮動小数点演算のテストを作るのはちょっと面倒です。結局僕は面倒だったのでサボりました。
FPUのレギュレーションはx87完全一致ではなく、数ulpの誤差が許されています。
逆にそのせいで浮動小数点演算の答えがx87と一致しないので、テストを書くのが難しいです。

例えば、僕は次のようなロジスティック写像を15回ほど回すlogisticというテストケースを作りました。

github.com

ところが、元々1回の浮動小数点演算(ここではfmul)がx87と一致しないので、15回回すと結構大きな誤差になりました。確か1万ulp程度はずれていたと記憶しています。これでも一応レギュレーションは満たしているのですが。
そのため、本当に厳密にテストを書くのならば、ちゃんと不等式で幅を持たせて期待される答えの範囲を記述する必要が出てくるので、非常に面倒くさいです。

まとめ
  1. CI気持ちいい
  2. デグレーションは防げたと思う
  3. テストに通すための非本質的なfixが多少生じる
  4. 浮動小数点演算の対応は面倒

ありがとうございました。