kなんとかの日記 このページをアンテナに追加

2010-06-02

Rubinius 1.0.0 が速すぎてびっくりした

| 15:14 |  Rubinius 1.0.0 が速すぎてびっくりした - kなんとかの日記 を含むブックマーク

(追記: Rubiniusとは、Ruby自身で書かれたRuby処理系Javaで書かれているJRubyとともに、期待を集めているRuby処理系のひとつ。)

そもそもこのブログRubinius で遊んだ結果を紹介するために始めたようなものだったのに、せっかく Rubinius 1.0.0 がリリースされたのにスルーしてた (ごめんよ Evan)。

ようやく Rubinius をインストールしてベンチマークをとったので、衝撃的な結果とともに紹介する。



インストール

インストールは簡単。Web サイトからダウンロードし、コンパイルするだけ。Mac OS X ならバイナリも用意されているけど、今回は使用せず、自分でコンパイルインストール。なおコンパイルには Rake を使うので、Rubinius をコンパイルするには Ruby が必要。

### Mac OS X 10.6 で実験
$ wget http://rubini.us/download/latest
$ tar xzf rubinius-1.0.0-20100514.tar.gz
$ cd rubinius-1.0.0/
$ ./configure --prefix=/usr/local/ruby/rubinius-1.0.0
$ rake
$ rake install
$ export PATH=$PATH:/usr/local/ruby/rubinius-1.0.0
$ rbx -v    # コマンド名は rbx
rubinius 1.0.0 (1.8.7 release 2010-05-14 JI) [x86_64-apple-darwin10.3.0]

コンパイルでめちゃメモリ喰うわ。C++ でのコンパイルってこんなに重くてメモリ喰いだったのか。そりゃ Google がコンパイルの速い言語を欲しがるわけやわ


ベンチマーク: フィボナッチ数列

現実のアプリケーションではまず使われないくせにベンチマークでは必ず登場するフィボナッチ数列を実行してみた。


test1.rb

def f(n)
  if n <= 1
    return 1
  else
    return f(n-1) + f(n-2)
  end
end

require 'benchmark'
n = ($n || 34).to_i
Benchmark.bm(10) do |x|
  x.report(RUBY_VERSION) { f(n) }
end

実行結果は驚くべき結果に!

### Ruby 1.8.7
$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.2.0]
$ /usr/bin/time ruby test1.rb
                user     system      total        real
1.8.7      14.400000   0.020000  14.420000 ( 14.560012)
       14.56 real        14.40 user         0.02 sys

### Ruby Enterprise Edition 1.8.7
$ ruby -v
ruby 1.8.7 (2009-12-24 patchlevel 248) [i686-darwin10.3.0], MBARI 0x6770, Ruby Enterprise Edition 2010.01
$ /usr/bin/time ruby test1.rb
                user     system      total        real
1.8.7      12.610000   0.010000  12.620000 ( 12.839836)
       12.84 real        12.61 user         0.01 sys

### Ruby 1.9.1
$ ruby -v
ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-darwin10.2.0]
$ /usr/bin/time ruby test1.rb
                user     system      total        real
1.9.1       2.040000   0.000000   2.040000 (  2.125471)
        2.14 real         2.05 user         0.00 sys

### Rubinius 1.0.0
$ rbx -v
rubinius 1.0.0 (1.8.7 release 2010-05-14 JI) [x86_64-apple-darwin10.3.0]
$ /usr/bin/time rbx test1.rb
                user     system      total        real
1.8.7       1.108981   0.000000   1.108981 (  1.108993)
        1.53 real         1.53 user         0.07 sys

速い順でいうと、「Rubinius > Ruby 1.9 >>> REE 1.8.7 > Ruby 1.8.7」という結果に。なんと Rubinius は Ruby 1.9 より速いぞ! (フィボナッチ的に)。

なおこの結果をみると、Rubinius の起動時間が 1.53 real - 1.108993 = 約 0.4 秒程度ということがわかる。以前よりも改善されてはいるけど、Ruby 1.8.7 や 1.9.1 が瞬間で起動するのと比べると、ちょっと見劣りがする。やっぱり CGI 用途ではきついかな*1


ベンチマークその2: 文字列処理 (HTML 生成)

フィボナッチ数列のような「実験室用のプログラム」ではなく、もっと現実感のあるベンチマークとして、HTML を生成するプログラムを実行してみた。

ここでも Rubinius が驚くべき結果に!


test2.rb

items = [
  { 'id'=>1001, 'name'=>'AAA' },
  { 'id'=>1002, 'name'=>'BBB' },
  { 'id'=>1003, 'name'=>'CCC' },
  { 'id'=>1004, 'name'=>'DDD' },
  { 'id'=>1005, 'name'=>'EEE' },
  { 'id'=>1006, 'name'=>'FFF' },
  { 'id'=>1007, 'name'=>'GGG' },
  { 'id'=>1008, 'name'=>'HHH' },
  { 'id'=>1009, 'name'=>'III' },
  { 'id'=>1010, 'name'=>'JJJ' },
]

def gen_html(n, items)
  buf = nil
  n.times do
    buf = ''
    buf << <<END
<html>
  <body>
   <table>
     <thead>
       <tr>
         <th>id</th><th>name</th>
       </tr>
     </thead>
     <tbody>
END
    is_odd = false
    for item in items
      is_odd = !is_odd
      buf << "       <tr class=\"#{is_odd ? 'odd' : 'even'}\">
         <td>#{item['id']}</td><td>#{item['name']}</td>
       </tr>
"
    end
    buf << <<END
     </tbody>
   </table>
  </body>
</html>
END
  end
  buf
end

require 'benchmark'
html = nil
n = ($n || 100000).to_i
Benchmark.bm(10) do |x|
  x.report(RUBY_VERSION) { html = gen_html(n, items) }
end

#print html
#puts "Enter to exit"
#$stdin.read

実行結果

### Ruby 1.8.7
$ /usr/bin/time ruby test2.rb
                user     system      total        real
1.8.7       3.970000   0.000000   3.970000 (  4.014548)
        4.02 real         3.97 user         0.00 sys

### Ruby Enterprise Edition 1.8.7
$ /usr/bin/time ruby test2.rb
                user     system      total        real
1.8.7       3.910000   0.000000   3.910000 (  3.948740)
        3.95 real         3.91 user         0.00 sys

### Ruby 1.9.1
$ /usr/bin/time ruby test2.rb
                user     system      total        real
1.9.1       4.640000   0.010000   4.650000 (  4.680164)
        4.69 real         4.65 user         0.01 sys

### Rubinius 1.0.0
$ /usr/bin/time rbx test2.rb
                user     system      total        real
1.8.7       3.334340   0.000000   3.334340 (  3.334336)
        3.75 real         3.79 user         0.08 sys

なんとここでも Rubinius が最速に! 速い順で「Rubinius > REE 1.8.7 > Ruby 1.8.7 > Ruby 1.9.1」という結果になった。

Rubinius の文字列処理は、2年前は泣きたくなるくらい遅かったんだけど、1.0.0 では大幅に高速化されていた。

Rubinius の作者である Evan Phoenix のコメント:

我々は、 Rubiniusでは、string(文字列オブジェクト)が遅くなる傾向にあると聞いた、そして大抵のRubyアプリにおいて、stringは、大きな部分を占めるので、現在、Rubiniusを使ってどの程度期待できで、将来、この問題は、どのように処理されるのかを知りたかった:

全てのstringが1.8.xより遅い、と言うのは正確でありません。Stringメソッドの多くは、1.8と同じか速いです。現在のところ、僅かなものだけが、遅い、例えば、tr, gsub, unpackなどです。我々はこれらをより高速にするために鋭意開発中です。

Rubiniusが1.0になった

ということで、文字列処理はきちんと高速化されてました。すばらしい。


結論

「Rubinius が速い」というのは、ウソ偽りのない本当のことでした。

Rubinius が高速なのは、LLVMJIT のおかげ。今回の結果や、LuaJIT が異常に高速なことや、PyPy が CPython より高速なことを考えると、今後は「どれだけ優秀な JIT を搭載しているか」がプログラミング言語高速化のカギを握るのだろう。

TODO: メモリ使用量の測定

あわせてよみたい:

*1:でも Rubinius はスクリプトを事前にコンパイルする機能があるから、スクリプトのロード時間は短縮できるはず。

2008-11-21

Engine Yard が Rubinius の開発支援を縮小

| 09:09 |  Engine Yard が Rubinius の開発支援を縮小 - kなんとかの日記 を含むブックマーク

たぶん、昨今の金融危機オープンソースに影響を与えた例。それも目に見えて。


Rubinius の作者である Evan Phoenix は、自身のブログで、Engine Yard が Rubinius の開発支援を縮小することを発表した。

There have been some sad developments within the Engine Yard Rubinius team that I’d like to address head on.

Earlier today, I had the unfortunate task of reducing the team size to 2 people, which meant laying off the rest of the team.

Error: Domain mapping upgrade for this domain not found

また Engine Yard のブログでも報告された。

A few weeks ago at RubyConf 2008, Koichi Sasada, the lead developer of Ruby 1.9 (also known as YARV) did Rubinius the honor of projecting that Rubinius would eventually be the Ruby interpreter of choice. We agree -- however, we also agree that it will take a while to get there.

So today we made a substantial change in the Rubinius team sponsored by Engine Yard and reduced the team to two members from its previous six.

Engine Yard | Cloud Application Management Platform

Engine Yard は Rubinius の開発を支援しており、Evan をはじめ 6 名のプログラマフルタイムで Rubinius の開発に従事させていた。

しかし Rubinius が実用的に使われるようになるまではかなりの時間と労力が必要となるため、Engine Yard は Rubinius の開発者を (Evan を含めて) 2 名に減らし、残りの 4 人をレイオフすることに決めた。

Rubinius は、Ruby の仕様を定める RubySpec を開始するなど大きな成果を挙げていたが、最近はカーネルC++ で書き直す作業に時間を取られていたため、見た目の進捗が思わしくないと上層部に思われたのかもしれない。

Engine Yard はこの夏に 1.5 億ドルの資金を調達したとの情報もあったので、資金的には問題ないと思われていたが、やっぱり金融危機の影響があったものと思われる。

ただ、2 名だけとはいえ Rubinius の開発を支援し続けるのは確かなので、最悪の事態は避けられた。

なお Engine Yard は Merb の開発も支援しているが、こちらのほうは支援縮小の話はなさそうである。


Rubinius と MagLev が協力するみたい

| 09:09 |  Rubinius と MagLev が協力するみたい - kなんとかの日記 を含むブックマーク

Finally, we're delighted to be working with Gemstone to refactor the Rubinius kernel (the part written in Ruby), to allow using it as a shared component between Rubinius and their MagLev runtime.

Engine Yard | Cloud Application Management Platform

Rubinius は、Gemstone 社が開発中である MagLev と協力し、いくつかのコンポーネントを Rubinius と MagLev で共有することにしたようだ。

具体的にどうするのかはわからないが、両者はともに Smalltalk を参考にした Ruby 処理系であるため、協力しあうのはいいことかもしれない。

2008-10-11

Ruby にとって JRuby や Rubinius が必要な理由

| 22:03 |  Ruby にとって JRuby や Rubinius が必要な理由 - kなんとかの日記 を含むブックマーク

Ruby には、本家実装である MRI 以外に、JRuby や Rubinius といった alternative implementation が登場している。

でも、いちばんよく使われるのは本家 MRI だし、それはこれからも変わらないだろう。

じゃあ MRI 以外の実装は必要ないじゃん、と言われるかもしれないけど、そんなことはない。

Ruby の別実装は、本家の実装にプレッシャーを与えるために大変必要である。


JRuby や Rubinius が登場することで、Ruby の実装について競争が発生した。

それは速度かもしれないし、安定性かもしれない。

競争が発生したおかげで、本家 MRI の速度や安定性について悪いところが改善されていくなら、たとえ JRuby や Rubinius が使われないとしても、それらは大変重要な役目を果たしてくれていることになる。

RubySpec なんて、Rubinius がなかったら未来永劫登場することはなかっただろう。Ruby の仕様が明文化されるのは、明らかに別実装が存在したおかげだ。


そう考えると、PHP の別実装が必要なんじゃないかと思うのだが、どうだろうか。

PHP チームはセキュリティの意識が低いという批判があるけど、もし PHP の secure な別実装が登場すれば、本家 PHP 開発チームも考え方を変えざるを得なくなるだろう。


そういえば、JRuby や Jython はあるけど JPHP はないね。もし作れば、Sun がスカウトしてくれるかな。

anatooanatoo 2008/10/11 23:41 どうもはじめまして。
重箱の隅をつつくようなことかもしれませんがJavaで実装されたPHPはありますよー、と一応指摘しておきます。
http://www.caucho.com/resin-3.0/quercus/
失礼しました。

anatooanatoo 2008/10/11 23:47 あーあと言い忘れてましたがこういうのもあるみたいです。
http://code.roadsend.com/pcc/

2008-06-14

呼び出し元のローカル変数を変更する

| 00:35 |  呼び出し元のローカル変数を変更する - kなんとかの日記 を含むブックマーク

Evanから資料が上がってこないので、Rubiniusで遊んでみる。

次のコードは、あるメソッドの中から呼び出し元のローカル変数を変更するサンプル。

もちろんRubinius限定。

def f()
  var = 1
  g(var)                   # var が 2 に変更される
  puts "f(): var=#{var}"   #=> "f(): var=2"
end

def g(x)
  ## 呼び出し元のローカル変数の値を操作する
  context = MethodContext.current.sender
  v = context.locals[0]    # context.locals[:a] とできて欲しい
  context.locals[0] = v + 1
end

f()

こんなことができてうれしいかというと、なんともいえない。

ただ、これを喜ぶ人は優秀なハッカーになれる資質がある。

喜ばない人は、RubyよりJavaやC#が向いていると思う。

2008-04-22

ついに Ruby の正式な仕様が登場するかも

| 23:02 |  ついに Ruby の正式な仕様が登場するかも - kなんとかの日記 を含むブックマーク

第 1 回 Ruby 設計ミーティングのメモが公開された。

これによると、Rubinius が主導して作った RubySpec が、Ruby の正式な仕様およびテストスイートとなりそう。パチパチ。

RubySpec は、RSpec のサブセットに独自の改良を施した MSpec (たぶん mini spec の意味) で記述されている。実装間の差異を吸収できるような仕掛けがあって、たとえば MRI では動くけど JRuby では動かない機能があったとき、そういうことを記述できるようになっている。

今のところ、RubySpec は標準ライブラリのカバー率が低いけど、MRI でも RubySpec を使うようになれば、標準ライブラリのカバー率はぐんと上がると期待される。

ついに、Ruby にも正式な仕様ができる日がやってきそうです。そして、その中心にいるのは Rubinius です。すごいぞ Rubinius!