RPythonで書かれたRuby処理系Topazで遊ぶ

TopazというRuby処理系が話題となっているようだ。RPythonで書かれており、CRuby(YARV)よりも高速だという。

同僚でもあるパイパニスト(語弊ある)id: rokujyouhitoma がTopazをビルドできない!と言っていた。そんなに難しいのならチャレンジしてみよう。今日はなぜかPython Tシャツを着ているし。昨日はなぜか職場でNode.jsとPerlのコードを読んでいたし。

ビルド

python環境はpythonbrewで、今回はvirtualenvは使わない。OSはMountain Lion。git/Mercurial/各種ビルドツールは入っている感じで。

mkdir topazos
cd topazos
git clone http://github.com/topazproject/topaz
hg clone https://bitbucket.org/pypy/pypy
cd topaz
pip install -r requirements.txt
python ../pypy/rpython/bin/rpython -Ojit targettopaz.py

RPythonが出すマンデルブロ集合をぼーっと見ていると、ビルドが終わる。 最適化をかけたあと、RPythonの実行系も含んだC言語のソースコードを吐き出し、それをビルドするようだ。

起動してみる

まずは試しに起動、と。

> bin/topaz
RPython traceback:
  File "topaz_main.c", line 128, in entry_point
  File "topaz_main.c", line 2163, in _entry_point
Fatal RPython error: NotImplementedError
[1]    99870 abort      bin/topaz

Oh。なんか失敗した。-eでワンライナーするか、スクリプトファイルが必要らしい。

> bin/topaz -e "puts 'Hello Topaz.'"
Hello Topaz.

やたー、動いた。

簡単なベンチマーク

差が6つの素数の組である、セクシー素数を求めるRubyコードを動かしてみる。セクシーな結果は出るのかな。

> ruby -v
ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-darwin12.0.0]
> time ruby sexy_prime.rb
51.774221
ruby sexy_prime.rb  51.76s user 0.03s system 99% cpu 51.793 total
> time bin/topaz sexy_prime.rb
10.434968
bin/topaz sexy_prime.rb  10.42s user 0.02s system 99% cpu 10.444 total
[/shell]

Oh, Sexy! 確かにこのベンチマークコードではかなり速くなっているようだ。

実装を見てみる

せっかくなので、実装も見てみよう。topazのディレクトリ構成はこんな感じ。

  • lib-ruby: Rubyで書かれたRubyの標準クラス/モジュール。FileUtilsとかppとか。
  • topaz: RPythonで書かれた本体。構文解析とか。
  • topaz/modules: RPythonで書かれた標準モジュール。KernelとかMathとか。
  • topaz/objects: RPythonで書かれた標準クラス。BignumとかFileとかRegexpとか。

ためしに、topaz/modules/math.pyを見てみよう。

from __future__ import absolute_import

import math

from topaz.module import Module, ModuleDef


class Math(Module):
    moduledef = ModuleDef("Math", filepath=__file__)

    @moduledef.setup_module
    def setup_module(space, w_mod):
        space.set_const(w_mod, "PI", space.newfloat(math.pi))
        space.set_const(w_mod, "E", space.newfloat(math.e))

    @moduledef.function("exp", value="float")
    def method_exp(self, space, value):
        return space.newfloat(math.exp(value))

    @moduledef.function("sin", value="float")
    def method_sin(self, space, value):
        return space.newfloat(math.sin(value))

    @moduledef.function("sqrt", value="float")
    def method_sqrt(self, space, value):
        return space.newfloat(math.sqrt(value))

    @moduledef.function("log", value="float", base="float")
    def method_log(self, space, value, base=math.e):
        if base == math.e:
            return space.newfloat(math.log(value))
        else:
            return space.newfloat(math.log(value) / math.log(base))

どうみてもRPythonです。本当にありがとうございました。

もっと突っ込んだベンチマーク

調子に乗って、The Computer Language Benchmarks Gameにあるベンチマークプログラムを動かそうとしたけど、めんどそうなので挫折。動かし方が書いてあるページがあるので、誰かチャレンジしてほしいす。おっさんねむいっす。