Haskell beats C

2012年に PLDI 2013 に投稿され惜しくも reject されてしまった "Haskell beats C" とその実装の紹介です。(その後、ICFP 2013 に再投稿されました。)
4
shelarcy(しぇらーしぃ) @shelarcy

で、この拡張の結果、合成性のある(非ボックス化)vector の抽象度の高いコードで、SSE を使った手書きの C コードに勝つ性能を発揮できるようになったそうです。

2013-02-05 15:39:30
shelarcy(しぇらーしぃ) @shelarcy

Dot Product の処理性能では、普通の手書きの C コードには勝てるけれど、流石に GotoBLAS を使っての処理には負けるみたいですね。Gaussian RBF の処理性能なら、GotoBLAS にも勝てるようです。

2013-02-05 15:40:59
shelarcy(しぇらーしぃ) @shelarcy

ただ、Gaussian RBF の処理性能に関しては、配列の要素数が多くなってくると、SSE を使わないバージョンの vector でも(メモリトラフィックを削減できる)ことにより Goto BLAS に勝てるそうですが。

2013-02-05 15:41:11
shelarcy(しぇらーしぃ) @shelarcy

Dot ProductでHaskellの方が速くなる理由としては、「VectorからMultiStream(ベクトル演算を使った処理のストリーム)に変換を行う時に、これから行われるメモリアクセスのパターンが分かっているのでプリフェッチ命令を適切な形で挿入できる」ことを挙げてますね

2013-02-05 15:45:25
shelarcy(しぇらーしぃ) @shelarcy

(言及してませんでしたが、GHC HEAD にプリフェッチ命令を使うための primitive が入ってます。 https://t.co/tFW43gGx

2013-02-05 15:45:45
shelarcy(しぇらーしぃ) @shelarcy

(で、この primitive を使ったコードが、primitive パッケージの simd branch と vector パッケージの simd branch に入ってます https://t.co/Bh2f3loe https://t.co/AbgN41aU

2013-02-05 15:47:01
shelarcy(しぇらーしぃ) @shelarcy

あと、vector ではベクトル演算を利用するために mfold や mzipWIth などの特別な関数を使いますが、DPH は元々ベクトル化のための仕組みを持っているので、DPH では特別な関数を用意しなくても実装の内部でベクトル演算を利用するようにできるそうです。

2013-02-05 15:47:15
shelarcy(しぇらーしぃ) @shelarcy

実際、前に公開された DPH の SIMD 対応の記事では、利用するモジュール名が違うだけで後はいつものままのコードでしたね。 http://t.co/QrHfRS9Y

2013-02-05 15:47:29
shelarcy(しぇらーしぃ) @shelarcy

.。oO(モジュール名を変えているのは、今のところ GHC HEAD のベクトル演算用の primitive が LLVM バックエンドにしか対応していない(そして Windows 環境では利用できない……[https://t.co/5DU7XvuW ] )からだと思います。)

2013-02-05 15:48:22
shelarcy(しぇらーしぃ) @shelarcy

現在の DPH の実装は SIMD 命令用に特化したものではないので性能に揺らぎがありますが、SIMD 命令を使ってそこそこ高速に処理できる上に、CPU 数の増加に応じてスケールしていくみたいで素晴らしいですね。

2013-02-05 15:49:36
shelarcy(しぇらーしぃ) @shelarcy

あっ、さっき言ったのは、現在の DPH ライブラリではなく simd branch 版 vector を使った simd branch 版 DPH [https://t.co/fgu0h8cx ] の話ね。念のため。

2013-02-05 16:00:48

ICFP に再投稿された新しいバージョンで追加された内容

shelarcy(しぇらーしぃ) @shelarcy

あっ、"Haskell beats C" が ICFP 2013 に再投稿されてますね。 http://t.co/eGn05XgFy0

2013-03-30 03:26:50
shelarcy(しぇらーしぃ) @shelarcy

"Haskell beats C" の新しいバージョンですが、ページ数が増えたからか、対象読者が異なるからか、実装の説明が詳しくなっていますね。

2013-03-31 23:11:38
shelarcy(しぇらーしぃ) @shelarcy

ただし、説明用に本来のコードにはない型を加えているので、実際の vector のコードを見る時は MultisC = MultiStream である点や MultisP は存在してない点に注意してください。

2013-03-31 23:11:51
shelarcy(しぇらーしぃ) @shelarcy

"5.1 Prefetching and loop unrolling" では、ただ単に説明を詳しくしているだけでなく、新しく入れた変更 [ https://t.co/xavB3tBLjf ] に基づいた説明をしてますね。

2013-03-31 23:12:18
shelarcy(しぇらーしぃ) @shelarcy

"5. Evaluation" の性能比較ですが、つっこみがあったのか、比較対象がかなり広がっていますね。

2013-03-31 23:14:23
shelarcy(しぇらーしぃ) @shelarcy

Cとの比較では、普通のCコード(を普通にコンパイルしたもの)と、SSE を使って手書きで最適化したCコードを使っていましたが、このうち普通のCコードを GCC の自動ベクトル化機能を使って最適化するようにしてますね。

2013-03-31 23:15:00
shelarcy(しぇらーしぃ) @shelarcy

(正確には -O3 -msse4.2 -ffast-math -ftree-vectorize -funroll-loops で最適化したコードを使うようにしたそうです。)

2013-03-31 23:15:27
shelarcy(しぇらーしぃ) @shelarcy

で、自動ベクトル化機能を使って最適化した普通のCコードと、SSE を使って手書きで最適化したCコードの両方に勝てることを確認しています。

2013-03-31 23:15:42
shelarcy(しぇらーしぃ) @shelarcy

もちろん、手でプリフェッチ命令を適切なところに入れていけば C でも同様の性能を出せるでしょうけれど、コードの抽象性を失わせずに適切なところにプリフェッチ命令を入れるようコンパイルできるのがこの手法の利点という話です。

2013-03-31 23:16:34
shelarcy(しぇらーしぃ) @shelarcy

また、従来の vector と SIMD 命令を利用できるようにした vector との間での、Haskell 同士の性能比較を行う節が増えてます。

2013-03-31 23:17:07
shelarcy(しぇらーしぃ) @shelarcy

Gaussian RBF に関しては、融合変換が大きく効いてくることから、融合変換のできないCとの比較は藁人形相手に戦っているようなものということで、新しく式テンプレートによって融合変換できるC++との比較を行う節が追加されています。

2013-03-31 23:18:50
shelarcy(しぇらーしぃ) @shelarcy

残念ながら、現時点では SIMD を使えるようにした改良版の vector よりも C++ のライブラリの方がより高い性能を発揮できるようです。(Eigen をきちんと使った場合、L3 キャッシュから漏れるぐらいのメモリを利用した場合の Boost.uBLAS など)

2013-03-31 23:20:33
shelarcy(しぇらーしぃ) @shelarcy

負けてしまった原因についてもきちんと分析されているので、将来的にこれらC++のライブラリにも勝てるようになると良いですね。

2013-03-31 23:21:08