Unladen Swallow 回顧録

Unladen Swallow 回顧録

これはPyCon参加中に書きましたが、更新は続けました。とにかく、はじめましょう :)

すでに明らかになっていることですが、Unladen Swallow自体、あるいはそのpy3kへの移植を行なっている人は誰もいません。何故いないんでしょうか?

スポンサーに関心がない

まず一番大きな理由は、Google内部に十分なユーザを得られなかったということです。これにはいくつか理由があります:

  1. Google内のPythonコードはたいていパフォーマンスが致命傷ではありません。Pythonは主にツールやプロトタイプに使われていて、ユーザ向けアプリケーションはJavaとC++で書かれています。
  2. 興味があったユーザにも、デプロイすることが非常に困難でした。置き換えるだけでは不十分でした。どんな新しいPython実装もややこしい設定なしで動作しなければなりませんでした。C拡張とSWIGコードは普通に動いているので、新しいものを作るよりCPython上で構築することでこの問題を回避しようと思いました。しかしながら、単純にCPythonの過去バージョンを2.6ベースのPythonに変更するのは非常に困難でした。
  3. 最も大きな顧客が結果的にパフォーマンスの問題をもっとデプロイしやすい方法で解決してしまったのです。

インターンシップが終わった後、私はUnladen SwallowをMITでの修士論文のテーマにしようと思いました。しかし、アドバイザーはUnladen Swallowから得られたものは大きなインパクトを与えるには足らず、かつ私が実装したがっていた技術は全く目新しいものではなくなっていると感じました。大抵の技術は、フィードバックに関してはSmalltalkでUrs Hölzleに実現されていて、トレースに関してはJavaでAndreas Gilによって実現されていました。目新しい技術がないわけではないのですが、その時は思いつきませんでした。

個人的関心がなくなった

これは2010年の第1四半期ごろに感じていたことです。まだこのときはUnladen Swallowに時間を割くという選択もできたのですが、その時事態は少し違ったように思えました。

まず最初に、プロジェクトを個人的に進めるのは、他の人と一緒にやるよりだいぶつまらないものでした。特に、ユーザがいるのかどうか分からない場合にはです。

次に、このプロジェクトのモチベーションの大部分は、PyPyが絶対にCPythonのC拡張モジュールやSWIGラッパーをサポートしないと思っていたからです。PyPyがそういったことに歩を進めるのを見てとても驚きました。これでいくらかCPythonにJITを追加する必要性が取り除かれました。また、PyPyプロジェクトが立ち上がった時には、x86_64サポートもしていませんでした。しかししばらくしてからそれも追加されました。

最後に、python-devから得られたメッセージがあまり芳しくありませんでした。もしUnladen Swallowがpy3kで実装されたら、Googleがそれを保守してくれるのではないか、という思惑もありましたが、もはやそうもいかなくなってしまいました。もしマージが行われたら、Unladen Swallowはデフォルトでは無効にされて、塩漬けにされたあと、1年後には取り除かれるのでしょう。少数の開発者だけが新しいJITに興奮するくらいです。マージは全然終わってませんが、もし終わったら、CPython開発者を勧誘して是非新しいJITのハックをしてもらいたいものです。

というわけで、こういった理由からもう誰もUnladen Swallowを開発していないわけですが、そこから何を学んだのでしょうか?

LLVMに関する教訓

まず最初に、JITコード生成器にLLVMを使うことの多くの利点と欠点を知りました。LLVMを使おうと決めた最初の理由は、始めた当初は開発者の誰もx86アセンブラで何か作ったことがなく、かつx86, x86_64そしてゆくゆくはARMもサポートしたかったからです。psycoを強化するための投資というのもあったんですが、x86をよく知っていないといけないのでストレスがたまるなと思いました。

不運にも、LLVMは今は静的コンパイラの最適化とそのバックエンド向けにデザインされています。LLVMのコード生成と最適化は良いのですがコストが高いです。最適化は、Cに似た静的言語によって生成されたLLVM IRに対してデザインされています。Pythonの最適化において最も重要な最適化には、プログラムが前のイテレーションからどのように実行されるかに関する高水準な知識が必要なのですが、LLVMではそういったことに関する手助けはしてくれません。

コード生成において高水準な知識が必要とされる例は、Pythonスタックへのアクセスを最適化する部分です。LLVMはPythonスタックに渡る外部関数への呼び出し(つまりCPython実行系)からの負荷を展開しません。結果的に、この問題を解決するために、解析器のエイリアスを用意しました。しかしこれは、独自のコード生成器を紐解くのでなければ、やらなければいけないことの例です。

LLVMには他の制限もあります。例えば、LLVMはバックパッチをサポートしていません。バックパッチはPyPyが抜け道を作るときに使っているものです。これはかなりメモリを消費しますが、Steven Noonanが彼のGSOCで行ったことを考えると、メモリ消費量を抑えられると思います。特にPyPyのメモリ消費量が大きいことを考えると、ここは抑えられると思います。

夏にはLLVMのJITとgdbの間のインターフェースを追加することに時間を費やしました。これは必要というわけではなかったのですが、いいツールでした。PyPyではどのようにデバッグしているかわかりませんが、PyPyのデバッグから学べることがいくつかあるでしょう。

Unladen Swallowから得たもの

個人的には、このプロジェクトを始める前にコンパイラとOSの授業を取っていました。しかし、このプロジェクトでは多くのシステムプログラミングスキルの経験を得ることができました。いまや、gdbをつかって、gdb自体をハックして、そのgdbをそれ自身で動作させるなんていうこともしています。そして、x86やコンパイラ最適化技術、JITトリックについてもとても詳しくなりました。JITトリックについては修士論文を書く中で大いに使いました。

実世界のPythonアプリケーションに対してのマクロベンチマークスイートの出来に自信を持っています。そして、PyPyは speed.pypy.org に実際にそれを使っています。Unladen Swallowを始める前や後に行ったすべてのパフォーマンスに関して行なってきたことの中で、このマクロベンチマークスイートが一番役にたったということを強調しておきます。コード変更前後のあらゆるパフォーマンスの変化が簡単に確認出来ます。

またLLVMへも、ParrotやRubiniusのような他のLLVM JITプロジェクトが利益を享受できる形で、多大な貢献ができました。たとえばJITコードサイズには16MBの制限があったのですが、直しました。LLVMのJITもgdbインターフェースがあります。JeffもインラインのCランタイム関数をJITコードに出来るようにしたり、メモリリークを直したり、LLVMでCの型を作るためにTypeBuilderテンプレートを追加したりと多くの貢献をしました。

多くの人材がいて、Unladen Swallowプロジェクトが存続することを願う一方で、プロジェクト自身は私にとって素晴らしい経験で、LLVMに対して実際に成果物を貢献できたし、いま使われているベンチマークスイートも作ることが出来ました。