CRuby 2.1 が速いとは限らない

先日 ruby と jruby の速度の差( http://qiita.com/Nabetani/items/9776d99d09476d07c9e2 )という記事を書いて、CRuby 2.1 がすごいという印象を与えたと思うんだけど、今度はそうじゃないよという記事。

前回と同様、調査対象は

* ruby 1.9
* ruby 2.0
* ruby 2.1
* jruby1.7.12 --1.9
* jruby1.7.12 --2.0

の5つ。

## わかったこと

* やることが違えば、何が速いかも違う。諸行無常。
* CRuby の 1.9 や 2.0 よりも 2.1 が遅いこともある。意外。

## 結果

横軸は時間なので、長いほうが遅い。

![vench.png](https://qiita-image-store.s3.amazonaws.com/0/6854/a0b0e366-9504-f174-13e9-c66f01052d2a.png "vench.png")

選んだ処理は思いつくまま。
あんまり込み入ってなくて、そのわりにバージョンによって差がでそうなものを適当に書いた。
2.1 が遅くなるものを選んだってわけじゃない。

以下、リハーサルは省略。

### ruby 1.9

```text
"ruby 1.9.3p545 (2014-02-24 revision 45159) [x86_64-darwin13.0.0]"
size : 2000
                         user     system      total        real
pack_unpack          1.200000   0.020000   1.220000 (  1.222390)
hugenum              0.840000   0.050000   0.890000 (  0.885420)
delete_if_and_push   5.930000   0.000000   5.930000 (  5.935082)
modify_string        3.310000   0.010000   3.320000 (  3.314836)
```

### ruby 2.0
```text
"ruby 2.0.0p481 (2014-05-08 revision 45883) [x86_64-darwin13.3.0]"
size : 2000
                         user     system      total        real
pack_unpack          1.230000   0.050000   1.280000 (  1.274881)
hugenum              0.940000   0.050000   0.990000 (  0.991847)
delete_if_and_push   5.760000   0.000000   5.760000 (  5.763749)
modify_string        3.530000   0.000000   3.530000 (  3.536681)
```

### ruby 2.1

```text
"ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]"
size : 2000
                         user     system      total        real
pack_unpack          2.470000   0.050000   2.520000 (  2.518461)
hugenum              0.850000   0.010000   0.860000 (  0.860112)
delete_if_and_push   7.220000   0.010000   7.230000 (  7.229943)
modify_string        3.530000   0.000000   3.530000 (  3.526038)
```

### jruby1.7.12 --1.9

```text
"jruby 1.7.12 (1.9.3p392) 2014-04-15 643e292 on Java HotSpot(TM) 64-Bit Server VM 1.7.0_07-b10 [darwin-x86_64]"
size : 2000
                         user     system      total        real
pack_unpack          1.730000   0.010000   1.740000 (  1.710000)
hugenum              2.510000   0.000000   2.510000 (  2.491000)
delete_if_and_push   2.600000   0.010000   2.610000 (  2.554000)
modify_string        1.820000   0.010000   1.830000 (  1.822000)
```

### jruby1.7.12 --2.0

```text
"jruby 1.7.12 (2.0.0p195) 2014-04-15 643e292 on Java HotSpot(TM) 64-Bit Server VM 1.7.0_07-b10 [darwin-x86_64]"
size : 2000
                         user     system      total        real
pack_unpack          1.760000   0.010000   1.770000 (  1.744000)
hugenum              2.530000   0.000000   2.530000 (  2.518000)
delete_if_and_push   3.320000   0.030000   3.350000 (  2.883000)
modify_string        1.850000   0.000000   1.850000 (  1.847000)
```

## 利用したプログラム

```ruby
#encode:utf-8

(p RUBY_DESCRIPTION) rescue p "1.8.x or former"
require "benchmark"

def pack_unpack(size)
  s=Array.new(30000){ [*"a".."z"].sample }.join
  size.times do
    s=[s].pack("m").unpack("m").first
    s=s.unpack("N*").pack("V*")
  end
end

def hugenum(size)
  a=10
  size.times do
    a=(a**a % 8191 )+10
  end
end

def delete_if_and_push(size)
  s=[]
  (2..size).each do |x|
    s.each{ |e| e<<1 unless e[0] % x ==0 }
    s.delete_if{ |e| e[0] % x ==0 }
    s<<(s.size.to_s*(s.size+1)) while s.size<size
  end
end

def modify_string( size )
  srand 1
  s=[*"\u1d400".."\u1d500"].zip( (?a..?z).cycle ).flatten.join
  (size/5).times do
    s[rand(s.size)]="a\u1f200"*size
  end
end

def run_bench( size )
  puts "size : #{size}"

  m=[ :pack_unpack, :hugenum, :delete_if_and_push, :modify_string ]
  len = m.map(&:to_s).map(&:size).max
  Benchmark.bmbm(len) do |x|
    m.each do |s|
      x.report(s.to_s){
        self.send(s, size)
      }
    end
  end
end

run_bench( 2000 )
```


## 結論

測ってみないとわからない。