Scheme で CRC 計算の件について、いくつかの処理系で動かして時間を計ってみた。 表の数値は 200MB のデータを対象にしたときにかかった時間。 CRC32 改は値を 16bit ずつに分けて計算するバージョン。 pic.twitter.com/COhgUkOYWv
— (32) 齊藤敦志 (@SaitoAtsushi) August 16, 2013
問題は結果のほうである。後ろから数えた方が早い位置にいる。Sagittariusは最速を目指しているわけではないのだが、(明示してないけど)高速であることも売りにしている。幸いにもソースは公開されていらしたのでプロファイルを取って速度改善に望むことにした。
Fixnumは30ビット幅しかないので(32ビット環境)CRCテーブルの要素ほぼ全てはBignumになると思っていい。これは避けようがないので放置。ざっとソースを見ると(当たり前だが)ビット演算が多用されているので実装を眺める。Fixnum-Bignumの組み合わせの場合にFixnumをBignumに変換してBignum同士で演算するようにしていたので、とりあえずこいつのメモリ割り当てをやめるようにする(ちょこっと改善された)。
次にプロファイルを取る。するとbitwise-xorやたら遅い。実装もまぁ、そりゃ遅いわという感じだったので、ゴリゴリ書き直し。(15%くらい改善)。次いで気になったのでbytevector-u8-refがやたらサンプリングされていた。こんなの単なる配列アクセスだからどれだけ呼ばれてもそんなにあるわけ無いだろうと思ったら実装があほなことをしていたので直す(微々たる改善)。
とりあえず、この段階で既存のものと比較してみた。結果は以下。
$ sash crc.scm ;; (crc32 data) ;; 121.992214 real 124.3640 user 6.130000 sys $ ./build/sash.exe crc.scm ;; (crc32 data) ;; 100.720778 real 101.5090 user 3.6040000915527344 sysうむむ、まだ遅い。bitwise-xorが処理時間の半分を占めているのでそこの改善がほぼダイレクトに効くのだが、どうやら効かせ方が足りないらしい。
Stub側を弄ったらさらに30%程度高速化できた。単にbitwise-xorに渡された引数が2引数までだったらパックしないようにしただけなんだけど、効果覿面である。以下がベンチマーク結果。
$ ./build/sash.exe crc.scm ;; (crc32 data) ;; 76.704494 real 76.83000 user 1.311000 sys初期から見ると倍近く高速化された。おそらく同様の方法で改良版も高速化できそう。
No comments:
Post a Comment