Island Life

< gitメモ | アセンブラをぶっとばせ >

2010/06/26

性能へのアプローチ

http://twitter.com/yoriyuki/status/17071304021

Listp好きの人って、なぜLispをCやPythonやJavaとばかり比較して、HaskellとかMLとかとは比較しないんだろう。そのほうがよっぽど面白いのに。と、これを読んで思った。http://bit.ly/cnrWxy

ここでは性能の話をしていたから。性能の話なら、一応広く信じられているのが Fortran/C/C++あたりは性能が出るってことなんで、チャレンジするなら そっちを相手にせざるを得ない (Cf. As Fast As Cee)。 LispとMLで性能比較してもアピールする読者がごく限られるだろうし。 自分もこのネタは何度も書いてて飽きてるんだけどねぇ。 あとまあ、自分がそれでコードを書いて性能を追求したことのある言語が CとLispくらいだから、というのもある。 Haskellでどうやって性能を出したらいいのかわからないもの。

ただまあ、おおまかな傾向というのは言えるかも。

たぶん、HaskellにせよMLにせよ、性能へのアプローチの柱になってるのは コンパイラをとにかく賢くするってことだ。 コンパイラがうまいコードを出せるようなヒントの与え方、 ってノウハウはあるけれど、 最後の最後はやっぱりコンパイラにお任せ。 Schemeもわりとそっち寄りのところがあって、 例えばcall/ccはナイーブに実装するととても遅くなるのだけれど、 「それは実装がタコだからだろ」で済まされる。 理屈の上で速い実装が可能ならば、それをしていないのは 意識的な選択でなければ実装者の怠慢とされる。

Common Lisp陣営は逆の立場。今、ここに、目的の性能を達成できる Sufficiently Smart Compilerが無いのなら、ぐだぐだ言わず 俺に低レベルコードを触らせろ、というわけだ。 なぜって、アプリケーション特有の最適化のツボを一番知っているのは アプリケーションプログラマであって、コンパイラ作者じゃないのだから。 コンパイラ作者が一番最適化できるなんてのは幻想、あるいは傲慢。 (Naughty Dogのように、アプリケーション作者=コンパイラ作者である場合は別で、 その場合は効果が最大となるけどね)。 実際問題として、 例えば「確実に、ここからここまでは一切アロケーションを行わない」という コードは必要とされるわけですよ。コンパイラが解析を頑張って、その間に 作られるオブジェクトはどこにもリークしないってことを証明できれば アロケーション無しのコードを吐けるだろうけど、 そうでない時に「コンパイラがタコでした」では済まされないよ、と。

現実的には両者のハイブリッドで行くしなかないと思うのだけどね。 アプリケーション作者が一番ツボを知っているというのはたぶん真実だけど、 その部分のコードというのは全体の1%くらいで、残りの99%は コンパイラの一般的な最適化で頑張ってくれた方がずっと良い。

ただ、関数型言語陣営がSufficiently Smart Compilerの存在を 当てにしているのだとすると、ちょっと危うい見通しがある。 今現在、関数型言語のひとつのコンパイラ、例えばghcの開発に関わっている人間/予算と、 C++のひとつのコンパイラ、例えばiccの開発に関わっているそれとを比べると、 後者の方がかなり大きいだろう。 また、最適化というのは最適化したいアプリケーションがあって始めて 進むものなので、アプリケーションの量も多いに越したことはない。 さらに、プロセッサもまた主流の言語処理系が吐くコードのパターンを意識して作られる。

結局、理屈の上で関数型言語の方が最適化しやすいのだとしても、 性能の面で主流の言語が強くなるポジティブフィードバックループの前では、 理論上の優位点なんてのはわずかなアドバンテージでしかない。 その優位点が本当に現実の問題を解決するか、ということを証明するのは、 関数型言語プログラマに課された仕事だろう。

★ ★ ★

性能性能と言うけれど、関数型言語のアドバンテージは別にあるんじゃないの、 という意見もあるかもしれない。そりゃもちろんそうだけれど、 だからといって性能の方を妥協すべきではない。

Haskellで書いたらこんなに綺麗、型不整合のバグとも無縁でハッピー、 っていうのはプログラマにとっての大きなメリットだけど、 それが商用プログラムなら、お金を出してるお客さんにとっては 出来上がったものが期待した機能と性能を提供するかどうかが第一で、 プログラマがハッピーかどうかは二の次だ。 プログラマが楽しいと生産性が上がりますよ(=期間が短いので安くできますよ)、 ってのはアピールポイントだけど、安くても必要な性能が出なけりゃ意味が無い。

ハードが速くなってきたから性能を気にする時代じゃなくなった、 なんて言う人もいるけれど、 (世界中で求められている総計算量/世界中の総計算資源)を考えれば、 むしろ大部分のコードは今以上の性能を求められてると言えるんじゃなかろうか。 そりゃ周辺部分では性能要件は緩くなってきたけれど、 言語としてそういうニッチだけを狙うというのは目標が小さかろう。 (特定のビジネスや特定の処理系がポジションとしてニッチを狙うのはありだが。)

★ ★ ★

さてそろそろ、12億レコード喰わせるのに3時間かかってる処理を 50倍に高速化する作業に戻らねば。

Tag: Programming

Past comment(s)

yoriyuki (2010/07/10 08:14:59):

何だかいい加減なつぶやきかな、と思っていたので、丁寧にお答えいただいて嬉しいです。

性能へのアプローチということですが、Haskellは仰る通りコンパイラがかなり頑張っているみたいですね。融合変換のようにアルゴリズムのオーダーまで変えてしまうようなことを平気でする。一方で、MLだとこれはいろいろ処理系がありますが、OCamlは最適化は行ないません。なので、OCamlのソースコードから生成されるマシンコードは大体わかります。この辺でGCがトリガーされるな、とか。OCamlプログラマはGCの挙動やアロケーションがどういうときに起きるかなどを頭に入れた上でコードを書くと思います。

で、Smart Compilerを作るという目的で言うと、Haskellは値がimmutableであったり、強く型附けられていたりするので、CやC++に比べて最適化の可能性があるかもしれません。

shiro (2010/07/13 14:54:41):

なるほど、するとOCamlでのチューニングプロセスはCommonLispのそれと近いものがあるのかもしれませんね。 関数型言語での最適化のアドバンテージというのはよく言われるのですが、実際に大規模開発で(例えば)C++などに比べて優位性を示せた、みたいなケーススタディがあれば知りたいです。

Post a comment

Name: