週刊mosh - メモリ効率の改善 / 非同期I/O / LTOの効能

先週とうってかわって今週は怒涛の動きだった  ような気がする。
追記 : higepon先生が一晩でやってくれました(see http://d.hatena.ne.jp/higepon/20110425/1303740074 )。 - http://storage.osdev.info/pub/mosh/mosh-current.tar.gz
今のところ、annotated-pairの導入によって通らなくなったテストがあるので、currentは更新されていません。本当に必要なら
http://storage.osdev.info/pub/mosh/mosh-check.tar.gz
が最新のリリース候補ツリーになっています。
現在の自動ビルドの仕組みは

  1. gitチェックアウト
  2. git clean -xfd
  3. 最後に正常にテストが通ったmoshバイナリでgen-git-build.sh
  4. ビルド&(テストせずに)リリースtarball生成 → mosh-check.tar.gz
  5. mosh-check.tar.gzを展開してFreeBSD amd64コンパイル
  6. テストに通ったらmosh-check.tar.gzをmosh-current.tar.gzにコピー

という手順になってます。
遠くないうちにWin32版のnightly buildsも提供したいけど、パッケージの署名等難しい問題があるので保留中。WeeklyくらいだったらGoogle codeの方を使ってもいいかな。。

提供されたパッチ

熱心にバグ投稿をしてくれているamoebaeから、psyntax-moshでもgetpidが使えるようになるパッチが提供された。

このパッチは取り込まれたので、0.2.7からは(mosh process)がgetpidを提供するようになる。

closeされたバグ

今回のannotated-pair最適化の導入で、事実上不可能になったのでWONTFIX。

R7RS対応のため、nmoshでもSRFI-38コードの実行に対応することに。

メモリ効率の改善

Gauche風のannotated-pair最適化がコミット/マージされた。今まで、moshのpairは全てアノテーション情報を持っていたのでcar+cdrの2ワードよりも大きかった。今回の変更でannotationの無いペアは2ワードになった。

やっていることはこれとほぼ同様。先頭の構造を同一にして、アロケートしたサイズを元にアノテーションの有無を調べる。
また、VMスタックやvectorGC_MALLOC_IGNORE_OFF_PAGEで確保されるようになった。
ここは(問題が発見されなければ)0.2.7のセールスポイントになる部分で、手元のコードではWin64版を使わざるを得なかった静的解析ツールがWin32版でも機能するようになるなど大きな成果があった。

非同期I/Oと擬似FFIスタブ

非同期I/Oは順調に進捗。0.2.7には入らない可能性が高いが、その次のバージョンには入るだろう。
BSD/MacOS XのkqueueとWin32のI/O completion port向けにスタブを実装。あとはライブラリの仕様を決めて繋ぎ込むところ。これらのスタブ(擬似FFIスタブ)はプログラム内部にあるものの現在はFFIで呼ばれるので、FFIに対応していないMIPSやARMでは暫く利用不可。。

擬似FFIのインターフェースは全てS式で書いてあって、ソースコードのbootstrap時にmisc/scripts/gen-nmosh-stubs.spsで生成される。
こういう回りくどい仕組みになっているのは、将来的にI/Oルーチン/スレッドをコンパイルできるようにするため。moshC++で書かれているので、スタブをC++にしてしまうとちゃんとしたコンパイラをつくらない限りスタブを呼び出せなくなってしまう。(i.e. LLVM自体はC++の呼び出し規約を知らない)
非同期I/OのAPIは、WindowsPOSIX AIOスタイルの、"I/O命令を発行し、その完了通知を受ける"APIFreeBSD KqueueやLinux epollのような、"I/O ready通知のみを受け取る"スタイルのAPIで大きく対立している。nmoshの非同期I/Oは前者のAPIだけ提供し、FreeBSDLinuxではエミュレーションを行う。前者のAPIのほうがコンテキストスイッチが少なくて済み、他の多くのI/Oアーキテクチャとも整合性が高いため。(FreeBSDの場合は、POSIX AIOの完了通知をKqueueで受け取ることもできるので、それに対応するかもしれない。)
あと、Cygwinには当然のようにepollのような非同期APIは無いので、Win32側の仕組みを使うことになる。Cygwinはfd→HANDLEの変換をサポートしていないので、ファイルをオープンする段階から非同期APIを使う必要がある。。(これはScheme側のportを非同期APIで扱えない理由にもなっている。)

LTO(リンク時最適化)/PGO(Profile Guided Optimization)の効能 (VisualStudio編)

とりあえず、先日の単純なTCP discardクライアントで性能測定したところ、次のような性能となった(測定環境はWin7 x64 + mosh Win32 + phenom2 3.2GHz)。

オプション IOリクエスト発行数
通常の最適化(/O2) 9400 req/sec
リンク時最適化(/LTCG) 23000 req/sec
プロファイル最適化(PGO) 28000 req/sec

ということで、リンク時最適化するのが最低限、プロファイル最適化もそれなりに効くことがわかった。ただ、通常のシチュエーションでは、moshのようなコードがリンク時最適化で倍速くなったりはしないので、原因を調べる必要は有る。。リンク時最適化を掛けると正確なプロファイリングが地味に難しくなる。
moshGCCのリンク時最適化では正常にコンパイルできないケースが有るので調査中。この手の問題はソースコードを正しく記述していないケースで起こる場合が多いので、そろそろコンパイル時の警告を精査すべきかもしれない。

対応環境の追加 - NetBSD / Wine1.3

NetBSDとWineを対応環境に追加した。というかWineは以前直したけど忘れてた。。
NetBSDLinuxと同様procfsを使って実行中のmoshのpathを取るようにした。fllogがR6RSの要求に沿わないので原因を調査中。多分libc側の問題。
Wineは内部でpathをUNIXパスにマッピングする関係で、正常にキャッシュが行われないことがあった。0.2.7からアプリケーション組み込みモードが(nmoshに)入るので、それを使えばWineでも正常に実行できる。システムにインストールするmoshとしては使えないけどそういうケースではホストOSで直接使うだろう。たぶん。
Wineは1.3以降が必要。nmoshの非同期I/O APIとBoehmGCが1.3以降に入った修正に依存しているため。。UbuntuFedoraのようなメジャーなディストリビューションでは問題ないはず。