Redmine のリポジトリ全文検索プラグイン

メリークリスマス!でしたね。今年のクリスマスは ruby を書いて過ごしました。えぇ。ついに ruby デビューです。 作ってたのは Redmine のリポジトリ全文検索プラグインです。会社のプロジェクト管理サイトを Trac から乗り換えるにあたり、これ!ってのが見つけられなかった情弱です。
Trac では、full-text サーチエンジンに Hyper Estraier を使う TracRepoSearch という素晴らしいプラグインを使ってました。ということで、便乗して redmine_reposearch というプラグインを作って見ました。バックエンドも同じく Hyper Estraier です。
 個人的に欲しかった機能は、
  • インストールステップが簡単
  • プロジェクト、サブプロジェクト、全プロジェクト間で検索できる
  • Redmine のアクセス権管理に対応する
  • MIME タイプを限定して検索する (今後実装予定)
です。ある程度は満足がいく出来に作ることが出来ました。インストール方法等は wiki にまとめました。わかりにくかったらお気軽に Issue か Twitter でお申し付けください。

# インストールステップは 2 ステップ
これは結構苦労しました。いろんな OSS 検索エンジンの仕様を調べ、一番インストールが簡単で、動作が軽快で、気の利いた ruby バインディングがあるやつを選びました。ライブラリのインストールとプラグインのインストールのみで動作します。
Estraier の DB は RAILS_VAR/reposearch 以下にプロジェクト毎に作成されます。Ubuntu の場合は、 /var/lib/redmine/reposearch になります。クラスタ組みたい場合は、RAILS_VAR はアップロードファイル保存ディレクトリでもあるので、ネットワークファイルシステムをマウントするなどすればいいと思います。
あと SCM との連携は fetch_changesets と同じ仕組を流用しています。まだ ruby script/runner "Repository.fetch_changesets" -e production のようなコマンドでは動きません。 /lib/crawl.rake なるものを作ればイケそうってとこまでは調べました。要望があれば。
インストールじゃなくて、インデックス作成もなるべく軽量になるように考えました。一応最終チェンジセットからの差分のみを再インデックス処理するようにしています。

# プロジェクト、サブプロジェクト、全プロジェクト間で検索できる
これも Hyper Estraier を選んだ理由にもなります。DB をまたいで検索できますし、リポジトリ毎に DB を作成するので、インデックス破損の影響を最小限に抑えることができるかなと。

# Redmine のアクセス管理に対応する
アクセス管理といわず、めんどくさいので使えるものは既存のライブラリを使うようにしました。ページング処理、ワードハイライト、文字コード、SCM の差異吸収、アクセス可能なプロジェクトの選択、プロジェクト選択フィルタなどなど。Redmine code search さまさまです。他に使い回せそうなコードがあれば教えてください先生方。けっこう親和性高くできたと思います。

# MIME タイプ限定検索など今後実装したい機能とか

  • テストを書きたい。書いてません。書き方わかりません。rails とか ruby とか勉強します
  • MIME タイプ限定検索
  • もっと軽量化したい。動作もコード量も
  • マッチパートのシンタックスハイライト (挫折済み)
言い訳を書いておくと、ruby も rails も redmine を初めて触ってるところです。Issue とかで色々教えていただけると喜びます。あと、他のプラットフォームでの動作確認とかも喜びます。

Python の新ユニットテストフレームワーク (or unittest2)

これは Python3 Advent Calendar の記事です。夢はテストエンジニアです!ということでユニットテストについて書きます。

Python3 縛りとのことですが、この新ユニットテストフレームワークは Python 3.2 以降と 2.7 以降が対象です。これ以前のバージョンでこの新ユニットテストフレームワークを利用したい場合は、それぞれ unittest2py3k (3 系)、 unittest2 (2 系) というバックポートが用意されています。新ユニットテストは mock や IronPython 等の開発者としても知られている Michael Foord 氏を中心に開発されました。

>>> Python とユニットテストの歴史

Python のユニットテストは、1999 年 xUnit ファミリーの PyUnit として開発され、2001 年に公開された Python 2.1 から unittest として標準ライブラリとなりました。それ以降、アップグレードといえば assert* メソッドの追加や削除といった感じ。PyCon 2010 での Michael Foord 氏のプレゼンテーションによると "Python には革新的なテストインフラが数多くありますが、unittest は標準ライブラリという理由により最も利用されているテストフレームワークです。しかし、他のテストフレームワークが革新的な進歩を遂げている中、unittest は遅れを取っています"。

しかしついに、ユニットテストは Python 3.2, 2.7 で革新されることになりました。それも Python らしく "後方互換" がかなり意識されています。これも Michael Forrd 氏の言葉を借りると "これは革命ではなく、進化です"。

>>> どこが "進化" したのか

新ユニットテストフレームワークには以下の機能の追加や更新が行われています。

  • 便利な assert* メソッドの追加
  • 名称の統一、重複の排除
  • コマンドラインからの制御をより便利に / 或いはディスカバリ
  • テストのスキップ
  • モジュールレベル、クラスレベルのテストフィクスチャ

などなどです。各進化の詳細について解説していきたいと思います。

>>> 便利な assert* メソッドの追加

追加されたメソッドには以下が含まれています。

  • 3.1 以降に追加されたメソッドも含んでいます
  • 3.2 / 3.3 で非推奨 / 廃止されたメソッドは含んでいません
  • 3.2 / 3.3 で名称変更されたものは新名称で記載しています
  • 利用できるメソッドはバージョンによって違うので、確認する必要があります
メソッド 検証内容 Ver.
assertIsNone / assertIsNotNone(x, msg=None) x is [not] None >= 3.1
assertIs / assertIsNot(a, b) a is [not] b >= 3.1
assertIn / assertNotIn(a, b) a [not] in b >= 3.1
assertIsInstance / assertNotIsInstance(a, b) [not] isinstance(a, b) >= 3.2
assertGreater / assertGreaterEqual(a, b)
assertLess / assertLessEqual(a, b)
a >[=] b
a <[=] b
>= 3.1
assertAlmostEqual / assertNotAlmostEqual(a, b) round(a-b, 7) [!|=]= 0
※ 仕様変更 (delta を追加)
>= 3.2
assertRegex / assertNotRegex(s, re) [not] re.search(s) >= 3.1 (not は >= 3.2)
assertCountEqual(a, b) 配列の個数と値 >= 3.2
assertMultiLineEqual(a, b) a = b: 文字列 >= 3.1
assertSequenceEqual(a, b) a = b: 配列+タイプ >= 3.1
assertListEqual(a, b) a = b: list >= 3.1
assertTupleEqual(a, b) a = b: tuple >= 3.1
assertSetEqual(a, b) a = b: set >= 3.1
assertDictEqual(a, b) a = b: dict >= 3.1
assertRaises(exc, fun, *args, **kwds) fun(*args, **kwds) raises exc >= 3.1
※ 3.2, 3.3 で仕様変更
assertRaisesRegex(exc, re, fun, *args, **kwds) fun(*args, **kwds) raises exc \
and re.match(exc.message)
>= 3.1
※ 3.2, 3.3 で仕様変更
assertWarns(warn, fun, *args, **kwds) fun(*args, **kwds) raises warn >= 3.2
assertWarnsRegex(warn, re, fun, *args, **kwds) fun(*args, **kwds) raises warn \
and re.match(exc.message)
>= 3.2

これは Google さんの協力も得て追加されたようです。このメリットをいくつか挙げたいと思います。

まず、a=b 等の状態検証用のメソッドが増えたこと。テスト開発者の皆様も待ち望んでいたのではないでしょうか?なんでこれが幸せなのか。既存の assert* を駆使して作ってたメソッドが 1 行で検証できるようになり、バグを発見しやすくなります。

class TestTest(unittest.TestCase):
    def setUp(self):
        self.list_first = [1, 2, 3, 4, ]
        self.list_second = [1, 2, 4, 4, 5, ]

    def test_old(self):
        self.assertEqual(len(self.list_first), len(self.list_second))
        self.assertEqual(self.list_first, self.list_second)

    def test_new(self):
        self.assertCountEqual(self.list_first, self.list_second)

if __name__ == '__main__':
    unittest.main()

例がむちゃくちゃでごめんなさい。。。

======================================================================
FAIL: test_new (__main__.TestTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_test.py", line 14, in test_new
    self.assertCountEqual(self.list_first, self.list_second)
AssertionError: Element counts were not equal:
First has 1, Second has 0:  3
First has 1, Second has 2:  4
First has 0, Second has 1:  5

======================================================================
FAIL: test_old (__main__.TestTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_test.py", line 10, in test_old
    self.assertEqual(len(self.list_first), len(self.list_second))
AssertionError: 4 != 5

----------------------------------------------------------------------
Ran 2 tests in 0.000s

テスト結果を見ても、4 != 5 じゃなんのことかさっぱりですよね。以前は "テストメソッド数 = 機能数" というのが一般的でしたが、モダンなテストは "テストメソッド ≒ 検証" です。ひとつのテストメソッド (test_*) 内に複数の検証 (assert*) を書いた場合、複数のテストに失敗しても最初の失敗しか出力されません。「分割すると時間がかかるし、まとめると失敗したときに追いかけるの大変だし。。。しゃーない独自の assert* 定義するか」ってな悩みから解放されます。

また、失敗時の結果出力もバグが分かりやすいように大幅に改善されています。

### Python 2.6
AssertionError: [1, 2, 3, 4] != [1, 2, 4, 4, 5]
### Python 3.2
AssertionError: Lists differ: [1, 2, 3, 4] != [1, 2, 4, 4, 5]

First differing element 2:
3
4

Second list contains 1 additional elements.
First extra element 4:
5

- [1, 2, 3, 4]
?        ^

+ [1, 2, 4, 4, 5]
?        ^   +++

適材適所の assert* を使うことで、バグを見つけやすくなります。

次に、assertRaises も大きな変更の 1 つです。以前は try-catch で書いていた検証が 1 行で書けるようになりました。

class TestTest(unittest.TestCase):
    def test_old(self):
        try:
            int("spam")
            self.fail("Expected a ValueError")
        except (Exception, ) as e:
            self.assertTrue(isinstance(e, ValueError))

    def test_new(self):
        self.assertRaises(ValueError, int, "spam")

if __name__ == '__main__':
    unittest.main()

このテストはもう 1 つ問題があります。例外が発生しない場合は、"self.fail" が通らないことですね。テストのカバレッジも重要ですが、テスト自体のカバレッジも大切です。try 節が長くなったり、ネストしたりするとテストが複雑になってしまいます。通らない可能性があるコードなんて書かないようにしましょう (書いてて耳が痛い)。

>>> 名称の統一、重複の排除

追加された便利機能もあれば、非推奨になったものもあります。名称の統一と重複の解除により、以下のメソッドが非推奨になりました。

  • assert_: assertTrue を利用する
  • fail*: assert* を利用する
  • assertEquals: assertEqual に統一

バージョンによって推奨・非推奨は異なっています。

>>> コマンドラインからの制御をより便利に / 或いはディスカバリ

unittest モジュールはコマンドラインから使えます (参考)。これに、py.test や nose とまではいきませんが、ディスカバリ機能が追加されました!

# テストモジュールやテストクラスを指定して実行
python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
# ファイル名を指定して実行
python -m unittest tests/test_something.py
# 結果の詳細出力 (verbosity=3)
python -m unittest -v test_module
# ディスカバリ実行 <- New!!!
python -m unittest
python -m unittest discover

ディスカバーと便利なオプションたち。

  • -v, --verbose: 結果を詳細に出力する
  • -f, --failfast: 最初に失敗した所でテストを終了する (>= 3.2)
  • -c, --catch: テストを中断し、それまでに実行したテスト結果を出力する (>= 3.2)
  • -b, --buffer: 出力先を指定する (>= 3.2)
  • -s: ディスカバリを開始するディレクトリ (>= 3.2)
  • -p: ディスカバリ時にテストファイルにマッチさせるパターン (>= 3.2)
  • -t: ディスカバリさせたいプロジェクトのトップレベルディレクトリ (>= 3.2)

-v, -f, -c, -b についてはディスカバリ時以外でも使えます。

python -m unittest discover -s project_directory -p '*_test.py'
python -m unittest discover project_directory '*_test.py'

ディスカバリのために、load_tests プロトコルが追加されています。テストモジュールに TestSuite を返す load_tests を定義することにより、テストを制御することができます。例えば以下の例ではディスカバリする際のテストクラスを限定しています。

test_cases = (TestCase1, TestCase2, TestCase3)

def load_tests(loader, tests, pattern):
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite

限定しなければ、TestCase を継承するすべてのクラスがテスト対象となります。

>>> テストのスキップ

テストクラスとテストメソッドをスキップ出来るようになりました。スキップする条件も指定できます。

class TestTest(unittest.TestCase):
    @unittest.skip("無条件スキップ")
    def test_nothing(self):
        self.fail("shouldn't happen")

    @unittest.skipIf(mylib.__version__ < (1, 3),
                     "not supported in this library version")
    def test_format(self):
        # 指定したバージョンのライブラリでのみテスト
        pass

    @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
    def test_windows_support(self):
        # Windows でのみテスト
        pass

verbosity を指定して実行すると以下のように出力されます。

$ python -m unittest -v test.py
test_nothing (test_test.TestTest) ... skipped '無条件スキップ'
test_format (__main__.TestTest) ... skipped 'not supported in this library version'
test_windows_support (__main__.TestTest) ... skipped 'requires Windows'

テストクラスごとスキップする場合は、以下のように書きます。

@skip("showing class skipping")
class TestTest(unittest.TestCase):
    def test_not_run(self):
        pass

どういう場合に有効なのかわかりませんが 失敗した場合でも失敗と数えないようにするデコレータも追加されています。テスト作成時には失敗するけど、修正してテストが成功すると通知してくれます。

    @unittest.expectedFailure
    def test_fail(self):
        self.assertEqual(1, 0, "broken")
# テストに成功してしまった場合の出力
test_fail (test_test.TestTest) ... unexpected success

>>> モジュールレベル、クラスレベルのテストフィクスチャ

これもテストコードも綺麗に書きたい方にとって待ち望んでいた機能だと思います。setUp / tearDown が無駄に長かったり、テストメソッド間で共有したいクラスレベル変数をメソッドレベルに定義したり。。。これは神アップデートです。テストがシンプルに、メンバの スコープも最小限に抑えることができます!!!そういえばモダンな xUnit では setUp/tearDown をなくしちゃった言語もありますね。

# Old... orz
connection = createExpensiveConnectionObject()

class TestTest(unittest.TestCase):
    def test_spam(self):
        connection

コネクションが違う場合は別モジュール orz...

# New !!!
class TestTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()

    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()

    def test_spam(self):
        cls._connection

スコープが素敵ですよね!スコープ範囲のためにモジュールやクラスを分割する必要がなくなります!上述のように "テストメソッド ≒ 検証" 形式で書いても、無駄に setUp を実行しないで済みます。

モジュールレベルは以下のように書けます。

def setUpModule():
    createConnection()

def tearDownModule():
    closeConnection()

setUp / tearDown の代替手段として addCleanup というメソッドが作られています。 addCleanup を使うことで、可読性が高いリソースのセットアップ処理 / 終了処理を書くことができるようになります。 これはテストの終了時 (LIFO) の動作が保障されています。tearDownsetUp 失敗時には動作しません。

def test_method(self):
    temp_dir = tempfile.mkdtemp()
    self.addCleanup(shutil.rmtree, temp_dir)
    ...

明示的に呼び出したい場合は、以下のように書けます。

def test_method(self):
    temp_dir = tempfile.mkdtemp()
    self.addCleanup(shutil.rmtree, temp_dir)
    ...
    self.doCleanups()
    ...
    self.doCleanups()

>>> まとめ

新ユニットテストフレームワーク素晴らしいですよね!バックポートも用意されていますので、是非移行しましょう!バックポートにはディスカバリ等に制限がありますが、assert* メソッドやテストフィクスチャの恩恵を受けることができます。バックポートとの後方互換を持たせるため、以下のように import することが推奨されています。

try:
    import unittest2 as unittest
except (ImportError):
    import unittest

新ユニットテストフレームワークには他にも多くの便利機能が用意されています。詳細については公式ドキュメントを参照してください。

>>> Python 3 に対応しているテストソリューション

  • テストフレームワーク: nose, py.test
  • テスト用モック: mock
  • TDD ならぬ BDD (ビヘイビアドリブン開発) フレームワーク: python-specfor

BDDフレームワークの PyCcuracy 等も今後の対応に期待したいですね。

ということで次は最近お子様が誕生された "@mopemope" 先生にバトンタッチです。

PyPy における Python のパフォーマンスチューニング

これは PyPy Advent Calendar の記事です。PyPyのコアディベロッパーである "Maciej Fijalkowski" 氏のブログ "Analysing python's performance under PyPy" の抄訳+αです。

Python の一般的なパフォーマン解析のモデルは、"プロファイラを実行して、ボトルネックを探し出し、それを最適化するか C で書き直す" ことです。しかし PyPy ではこのアプローチだけでは不十分です。なぜなら、

  • 多くの大規模アプリケーションで、プロファイラはフラットです: PyPy のトランスレーションツールチェーン、Twisted、モダンな Web サーバ等が良い例です
  • ボトルネックを発見したとしても、それが特定の関数内でのみ遅いのか、複数の関数が関係しているのか明確になるわけではありません。どうすれば遅くて、どうすれば速くなるかは CPython においても明確な答えはありません。JIT が適用されるとさらに複雑です。 JIT が特定のコードをどのようにコンパイルしたかを確認することが重要になります。
  • パフォーマンスにおいては、特に GC 関連の問題は多くの関数に影響がありますが、プロファイルでは確認できません。

PyPy には、問題を解決するためのいくつかのツールが提供されています。プログラムのパフォーマン解析に関するいくつかの方法を示します。これはガイドラインであり、銀の弾丸ではありません。アプリケーションが複雑な場合は、多くの鉛の弾丸が必要でしょう。

>>>> テストを作成する

これは品質に関するものではありません。多くの自動化されたテストを受けることで、その機能を失うことなく、よりパフォーマンスの高いコードにリファクタできるようにします。

>>>> ベンチマークを書く

これが重要な出発点となります。ひとつのスクリプトで、できれば引数を指定して、変更の影響を測定できるようにする必要があります。

1 回だけしか実行されないスクリプトでない場合は、同じテストを繰り返し実行することで JIT のウォームアップ時間がパフォーマンスにどのような影響があるかを測定することができます。それは連続して実行されるとどのように変化するかを視覚化する助けにもなります。

"Maciej Fijalkowski" さんのベンチマークは、ステップごとに 0.2 秒から 5 秒実行しているそうです。これにより、誤差を最小限にすることができます。JIT のウォーミングアップ時間は、コードベースによって違ってきます。それは一瞬かもしれませんし、1 分かもしれません。

>>>> cProfile の結果を考慮する

Python のプロファイラ (cProfile) をカスタマイズした lsprofcalltree.py を利用し、kcachegrid へ取り込み可能なフォーマットで出力します。これは役に立つ情報を提供するかもしれませんし、しないかもしれません。プロファイルから突出している関数がある場合に、その効率やアルゴリズムを確認します。

>>>> GC や JIT 等の比率を確認する

PyPy のコードベースには、この確認に便利なツールが提供されています。プログラムを pypy virtualenv で実行している場合は:

$ PYPYLOG=log ./test.py

を実行します。また、pypy のリポジトリのチェックアウトから:

$ pypy/tool/logparser.py print-summary log -

を実行します。また、グラフで確認したい場合は:

$ pypy/tool/logparser.py draw-time log out.png

を実行します。これは、だいたい何にどれぐらいの時間が費やされているかを確認することができます。GC、JIT トレース (ウォームアップ時間)、その他 JIT 化されたコードの実行時間が含まれています。

logparser の出力例については、PyPy Advent calendar: 7 日目の id:rokujyouhitoma (総帥) 先生のブログが参考になります。

>>>> jitviewer を利用する

jitviewer により、コードに何が起きたかを大まかに確認することができます。

インストール方法 (Ubuntu)

以下がインストールされていることが前提です。

  • virtualenvwrapper or virtualenv
  • pypy-1.7

    ※ PyPy は /opt/ 配下にインストールし、 /usr/bin にシンボリックリンク作ってます。

    cd /opt/
    wget https://bitbucket.org/pypy/pypy/downloads/pypy-1.7-linux.tar.bz2
    tar -jxf pypy-1.7-linux.tar.bz2
    sudo ln -s /opt/pypy-1.7/bin/pypy /usr/bin/
    

jitviewer 用の virtualenv を作成し、インストールします。

mkvirtualenv pypy-viewer -p /usr/bin/pypy
pip install JitViewer
# 開発版を使われたい方: pip install -e hg+https://bitbucket.org/pypy/jitviewer/#egg=jitviewer

最後に PYTHONPATH に /opt/pypy-1.7/lib_pypy, lib-python, py を追加します。

こんな感じで JIT ログ + アセンブラを確認することができます (これを見て盛り上がる pypyja のチャット)。

>>>> JIT にやさしいコード

本家にある Wiki翻訳しました。以下抜粋します。

  • 属性名は一定にする: setattr(x, 'a' + some_variable, y) よりも setattr(x, 'a', y) の方が高速
  • 新クラス形式を使う / クラスを継承させない
  • 関数の引数の指定で *args**kwargs を使わない: 内部コードが増える
  • JIT を無効化するコードは書かない: logging モジュール, トレース, フレームイントロスペクション (sys._getframe(), sys.exc_info()

現状は遅いけど改善に取り組んでるコード。

  • ジェネレータよりリスト内包表記が高速 -> ジェネレータの高速化
  • str.join(list) より cStringIO が高速 -> str の高速化

チューニングはひたすらベンチマークと格闘のようですね。次は @shomah4a 先生です。

[memo] Ubuntu 11.10 (kernel 3 系) にアップグレード時の注意書き

kernel 3 系ではディレクトリツリーが整理されています。しかし、現在のところ Ubuntu 11.10 にアップグレードしても、新ディレクトリツリーに完全に対応してくれません。ちなみに新規インストールの場合は問題ありません。 以下の手順で新ディレクトリツリーに対応します。

  1. 新ディレクトリへ移行
    sudo mv /var/run/* /run/
    sudo mv /var/lock/* /run/lock/
    sudo rm -r /var/run
    sudo rm -r /var/lock
    sudo ln -s /run /var/run
    sudo ln -s /run/lock /var/lock
    sudo rm /run/dbus/*
    
    参考
  2. apparmor の権限を更新

    例) /etc/apparmor.d/usr.sbin.mysqld の場合

    ---  /var/run/mysqld/mysqld.pid w,
    ---  /var/run/mysqld/mysqld.sock w,
    +++  /{,var/}run/mysqld/mysqld.pid w,
    +++  /{,var/}run/mysqld/mysqld.sock w,
    
  3. その他設定ファイルの見直し

    sock ファイルとか pid ファイルの設定は見直したほうがいいです

VMWare 上にインストールしている場合は、ライブラリが競合するので blacklist に以下を追加する。

# sudo vi /etc/modprobe.d/blacklist.conf
blacklist i2c_piix4

参考

pam が更新されているので、依存してるアプリケーションの更新が大変ですね。。。

PyPy! - PyPy Advend Calendar

今年も Advent Calendar の季節が始まりました。この記事は Python を高速化するソリューション PyPy の Advent Calendar の記事です。最初なので、簡単に PyPy の概要と PyPy-ja のご紹介をしたいと思います。

>>>> PyPy ってなんなの?

PyPyは日本語で、おっぱいの意味なんだよ ってUSのpythonやってるエンジニアに教えたら「今日ほどいい日はない!って大喜びしてた」
Oct 06 via webFavoriteRetweetReply

PyPy は Python 2.7.1 互換の高速な処理系です。現在、着々と py3k 対応の開発も進んでいます。Python 標準処理系である CPython と比較して以下のような特徴があります。
  • 速度: とにかく速いです。JIT パワーです。CPython と PyPy の速度はここに公開されています。現在は CPython の 5 倍ぐらい速いですね。特定の環境では Java より速いという計測結果もあります。ちなみに先日 Win32 環境で同じ計測をしましたが、Win32 環境では pypy 1.6 以降で Java よりも高速という結果がでましたよ。残念ながら 1.7 より 1.6 の方が高速という結果でしたが。。。
  • メモリ使用量: 多い。ほんとにメモリ食います。JIT の作者 Antonio 氏に Python 生みの親の Guide (oh...) Guido 氏が "PyPy の JIT はなんで速いの?" と質問した時に、"オブジェクトが持っているデータをメモリ上の固定位置に配置してるのが効いているみたい" と答えたとのことです (ats さんのブログより)。なるほど。
  • 互換性: 一部制限がありますが Python との互換性は高いです。1.7 になってさらに互換性が高まっています。動作する Python ライブラリはここにまとまっています。"このライブラリも動いたよ!" って方は是非この Wiki を編集してみてください。Django, Flask, Pyramid などのメジャー Web アプリケーションフレームワークや Twisted や Sphinx も動作しますよ!逆に C 拡張を含むライブラリは動作しないものが多いです。1.7 からは numpy も numpypy として動作するようになり、今後対応するライブラリがどんどん増えていきますよ!
  • スタックレス: スタックレスの軽量な擬似的スレッドによる並列処理ができます。
メモリ最適化して、JIT パワーで、Python 高速化したよってことです。ただ PyPy はそれだけじゃないんです。PyPy は動的言語の処理系を作ることもできます。PyPyPy とかも夢じゃないです。動的言語を作ってみたい方は是非 (この辺は勉強中のため後の方々へ丸投げ)!!

>>>> PyPy-ja ってなんなの?
巷では "PyPy 闇の軍団" と呼ばれています。あーみんファンクラブです。公式ドキュメントの翻訳や PyPy 技術情報の共有等を中心に活動しています。詳細は以下のページを参考にしてください。
総帥の @rokujouhitoma さんを中心に盛り上がっております。

pypy闇の軍団の総帥です。こんにちわこんにちわ。
Nov 09 via YoruFukurouFavoriteRetweetReply

こわくないよ。全然こわくないよ。 RT @shomah4a: 総帥こわーい [11時18分24秒 JST] Toru Ike(rokujyouhitoma, Tohru Ike): まだビルドしたことないの?( ゚д゚)、ペッ #pypyja
Nov 21 via YoruFukurouFavoriteRetweetReply

ご興味ごおありの方は是非コミュニティに参加してください。1 人でも多くの PyPy ユーザが増えるといいなーと思ってます。