2011年8月19日金曜日

PyPy 1.6 - kickass panda

原文はこちら: PyPy 1.6 - kickass panda

私たちは、PyPy1.6のリリースを発表できることを嬉しく思います。このリリースでは、多くのバグ修正と1.5以上のパフォーマンスの向上をもたらし、Windows32とOS X 64bitのサポートの向上をします。このバージョンでは、Python2.7.1を完全に実装し、CPythonのC拡張読み込みをベータレベルサポートしています。ここからダウンロードできます。

http://pypy.org/download.html

PyPyとは?

PyPyは、非常に準拠しているPythonインタプリタであり、ほぼ、簡単にCPython2.7.1を代替できます。それはトレーシングJITコンパイラを統合しているため、高速です。(pypy1.6とCPython2.6.2のパフォーマンス比較

このリリースでは、x86マシンで実行しているLinuxの64/32または、Mac OS Xがサポートされています。Windows 32はベータです(ほぼ動作しますが、多くの小さな問題はこれまで修正されていません)

このリリースの主なトピックは、スピードと安定性です: 私たちのベンチマークスイートの平均において、PyPy1.6は既に私たちのベンチマークではCPythonより高速なPyPy1.5より20%から30%速いです。

速度の改善はPyPyを構成する多くの層を最適化することで実現しました。
とりわけ、私たちはガーベージコレクタ、JITのウォームアップ時間、JITによって実行される最適化、生成されたマシンコードの品質とPythonインタプリタの実装を改善しました。

ハイライト

  • 多数のパフォーマンス向上は、全体にかなりのスピードアップをもたらします:

    • 非常に大きなオブジェクトや配列を扱う時のGCの振る舞い。

    • fast ctypes:現在呼ばれるctypes関数はJITによって最適化され、PyPy1.5より60倍高速で、CPythonより10倍高速である。

    • ジェネレータの改良(1): 単純なジェネレータは現在、ループ呼出しをインライン展開しており、PyPy1.5より3.5倍高速化し、パフォーマンスアップしました。

    • ジェネレータの改良(2): 他の最適化のおかげで、ジェネレータはインライン化されてなくともPyPy1.5より10%から20%速いです。

    • JITの高速なウォームアップ時間。

    • single floatのJITサポート (e.g., for array('f'))。

    • 最適化された辞書: 辞書の内部表現は、現在、動的に保存されているオブジェクトの種類に応じて適宜選択します。高速なコードと小さなメモリフットプリントの結果です。例えば、キーがすべて文字列、またはすべて整数である辞書。 他の辞書でもバグ修正のため、より小さくなります。

  • これはあなたのPythonコードがJITによってコンパイルされアセンブリまで落とし込まれたものを確認するウェブベースツールであるJitViewerを含む最初の公式リリースです。
    jitviewer 0.1は既にリリースされておりPyPy1.6でうまく動いています。

  • CPythonの拡張モジュールAPIが改善され、より多くの拡張機能をサポートしています。何がサポートされているかの情報については、私たちの互換性wikiを参照してください。

  • マルチバイトエンコーディングのサポート:これはCPythonが原因となって残っていた最後の領域でした。しかし、今私たちはそれを完全にサポートしています。

  • numpyのための準備的サポート:このリリースでは、PyPy JITと統合された非常に高速なnumpyのモジュールのプレビューが含まれています。残念ながら、これは、あなたが既存のnumpyのプログラムを作って、PyPyでそれの実行を期待できるということを意味するものではありません。なぜならば、モジュールはまだ未完成であり、numpyAPIのいくつかをサポートしているためです。しかしながら、いくつかの詳細を除いて、その仕組は非常に高速でなければなりません:-)

  • バグ修正: 1.5リリース以来、私たちはバグトラッカーにある53のバグを修正しました。私たちが発見し、バグトラッカー以外の経路を介して報告された多くののバグはカウントしていません。

喝采を贈る

Hakan Ardo, Carl Friedrich Bolz, Laura Creighton, Antonio Cuni, Maciej Fijalkowski, Amaury Forgeot d'Arc, Alex Gaynor, Armin Rigo とPyPyチームへ

(原文:Posted by Maciej Fijalkowski)


(翻訳:Tohru Ike)

2011年8月15日月曜日

JITされたコードの視覚化

原文はこちら: Visualization of JITted code

こんにちわ。

私たちはjitviewerの最初の公式リリースを発表できることを誇りに思います。
現在のところ、jitviewerはPyPyのJITによってマシンコードにコンパイルされた
Pythonソースコードの理解を助けるちょっとした内部ツールです。

インストールするには、PyPyのごく最近のバージョン(8月9よりも新しい)、例えば、ナイトリービルドのいずれかが必要です:

  • pipとdistributeをインストールするまたは、PyPyで作られたvirtualenvか、次の述べるinstallation instructions

  • PyPyのソースコードチェックアウトし、PYTHONPATHに確実に入れてください。

  • pip install jitviewer。グローバルにインストールされたpipではなく、PyPyの管理下にあるpipを実行する必要があることに注意して下さい。


jitviewerをはじめるにはREADMEを見るまたは、それをただ実行したいならオンラインデモを試みてください。

jitviewerはflaskとjinja2で書かれたWebアプリケーションです。
ウェブ開発経験があって、PyPyを助けたいなら、私たちに遠慮無く連絡してください。PyPyを向上する多くのことがあります :-)

本当のところjitviewerは何をするのでしょうか?


ページの上部には、JITでコンパイルされたコードの一部分のリストが表示されます。
あなたは通常のループと"エントリブリッジ"の両方を確認することができます。ここでは、それらの違いについて議論する適当な場所ではありませんが、たぶんあなたは、通常はほとんどの時間が費やされている場所なので、ループをもっとも見たがっているでしょう。

各ループにおいて、ループの最初の命令を含んだ関数の名前が表示されることに注意してください。
しかしながら、JITによって行われるインライン化のおかげで、それに他の関数のコードが含まれます。

あなたがひとたびループを選択すると、jitviewerはJITがどのような階層的な方法でPythonソースコードをアセンブラにコンパイルしたのかを示します。それは4つのレベルで表示します:

Pythonソースコード: 空色で示された行だけが、この特定のループのためにコンパイルされており、灰色のものはそうではありません。

Pythonバイトコード, あなたが実行することによって得るもの:
def f(a, b):

return a + b
import dis
dis.dis(f)
命令コード(opcodes)は、例えば LOAD\_FAST, LOAD\_GLOBAL などです。
太字になっていない命令コード(opcodes)は、完全にJITで常に最適化されています
  • JITコードの中間表現(IR)。これは操作(整数加算のような、構造体のフィールド読み出し)とガード(私達の仮定が実際に真であることを確認する)の組合せです。ガードは赤色です。それらの操作は"Cと同じレベルで": そう、例えば、+は、CPUのレジスタに格納された2つのボックス化が解除された整数を取ります。

  • アセンブラ: あなたは、右上メニューの"Show assembler"をクリックして、それを確認することができます。


時に、ガードが頻繁に失敗し、アセンブラの新しい部分が呼ばれてコンパイルされた事がわかるでしょう。
これはコードを通した迂回経路であり、そして、それはブリッジと呼ばれます。
ガードの横にリンクがある時には、jitviewerでブリッジを見ることができます。

詳しい情報の成果を得たいのであればjit documentationを探して下さい。

いまだに混沌としています


私が現状について説明すると、Jitviewerは完全ではありません。
あなたが、IRC上に現れたり、私たちのメーリングリストへメールを送ることは自由であり、また私たちはそれを説明し、解決策を改良するでしょう。
詳細については、お問い合わせのページを参照してください。

Cheers,
fijal & antocuni

(原文:Posted by Maciej Fijalkowski)

2011年8月3日水曜日

PyPyはCより速い。あらためて:stringフォーマッティング

原文はこちら: PyPy is faster than C, again: string formatting

stringフォーマッティングは、おそらくPythonであなたが通常することであり、あえて考えたりはしないでしょう。
それはとても簡単で、まさに"%d %d" % (i, i)すれば完了です。
結果のバッファをどのように測るかは考えません。あなたの出力の最後に適したNULLバイトを持っているようと、または他の細かい事があろうと。Cに相当するのは次のようになります:
char x[44];
sprintf(x, "%d %d", i, i);

2行目のところで立ち止まり、数がどれくらい大きくなるかもしれないかを考慮して、サイズを過大評価しなければならなかったことに注意してください。
(44 = 64ビット上で最も大きい数の長さ(20) + 1 (符号のための) * 2 + 1 (空白のための) + 1 (NULバイト))
この投稿の著者、fijalとalexはこの3つの計算の試みを異議なしで実現しました :-)

この関数からxを返すことができない場合を除きすばらしいです。よりよい比較は次のようになります。
char *x = malloc(44 * sizeof(char));
sprintf(x, "%d %d", i, i);

xはいくらかの状況でわずかに過剰割り当てされますが、すばらしいです。

しかし、ただstringフォーマッティングの実現について議論するために、私たちはここいるわけではなく、速いPyPyを明確に新たなunroll-if-altブランチとともに示し、議論するためにここにいます。Pythonは次のコードをもたらします:
def main():
for i in xrange(10000000):
"%d %d" % (i, i)

main()

Cコード:
#include 
#include


int main() {
int i = 0;
char x[44];
for (i = 0; i < 10000000; i++) {
sprintf(x, "%d %d", i, i);
}
}

PyPyのunroll-if-alt branchブランチのheadで実行し、コンパイルはGCC4.5.2 -O4(他の最適化レベルをテストし、これが最高のパフォーマンスをもたらした)。PyPyで実行すると0.85秒、コンパイル済みのバイナリで実行すると1.63秒かかりました。
私たちはこれは動的コンパイルの信じられないほどの可能性を示すと考えおり、GCCはsprintfの呼び出しをインライン化またはアンロールすることができません。理由はlibcが内部に位置しているためです。

Cのベンチマークコード:

#include
#include


int main() {
int i = 0;
for (i = 0; i < 10000000; i++) {
char *x = malloc(44 * sizeof(char));
sprintf(x, "%d %d", i, i);
free(x);
}
}

前に議論されたとおり、これはPythonに匹敵し、1.96秒の結果が得られます。

パフォーマンスの結論:
PlatformGCC (stack)GCC (malloc)CPythonPyPy (unroll-if-alt)
Time1.63s1.96s10.2s0.85s
relative to C1x0.83x0.16x1.9x

全体的にPyPyは2倍速いです。これは明らかに、静的より動的コンパイラが優っています。 - sprintf関数はlibcにあり、不変な文字列に特化することができず、実行されるときはつねに、文字列を評価しなければなりません。
PyPyのケースでは、私たちは、剰余演算子の左側の文字列が不変であると検出すれば、アセンブラに特化することができます。

Cheers,
alex & fijal

(原文:Posted by Maciej Fijalkowski)