history

青木日記 RSS

<前の日 | この月 | 次の日>

2003-10-17

Ruby / 実行速度 (2)

わかった。他のは全て GC が 2 回なのに対して foreach を使ったときは 4 回動いてる。たぶんこれが原因だな。

なんでだろう。統計をとってみた。

# foreach.rb
GC start
malloc_limit    = 0x007a1200
malloc_increase = 0x0007b3bd
freelist        = 0x00000000
newobj          =      14388
freed           =       4392
GC start
malloc_limit    = 0x8fca857b
malloc_increase = 0x0003ae66
freelist        = 0x00000000
newobj          =       7320
freed           =       2928
GC start
malloc_limit    = 0xdf27c882
malloc_increase = 0x0011b9d5
freelist        = 0x00000000
newobj          =      34880
freed           =      13952
GC start
malloc_limit    = 0xefab32f4
malloc_increase = 0x000bea3b
freelist        = 0x00000000
newobj          =      23252
freed           =       9298
program end
malloc_limit    = 0xfa9ba240
malloc_increase = 0x0001f36f
freelist        = 0x401fc5ec
newobj          =       3876
 
# readlines.rb
GC start
malloc_limit    = 0x007a1200
malloc_increase = 0x0010c8f7
freelist        = 0x00000000
newobj          =      10002
freed           =          8
GC start
malloc_limit    = 0xffdc70c1
malloc_increase = 0x001855fa
freelist        = 0x00000000
newobj          =      35044
freed           =          0
program end
malloc_limit    = 0x007a1200
malloc_increase = 0x0006ac72
freelist        = 0x401e78f4
newobj          =      70798

単語解説

  • malloc_limit: これを越えて malloc すると GC が発生する閾値
  • malloc_increase: GC 発生までに malloc/realloc したバイト総数 (GC 起動でリセット)
  • freelist: オブジェクト管理領域 (RVALUE) のリストへのポインタ
  • newobj: GC 発生までに作成されたオブジェクトの数 (GC 起動でリセット)
  • freed: その回の GC で回収できた RVALUE の数

ここからわかることは以下の通り。

  • すべての GC が freelist (オブジェクト管理領域) 枯渇によって起動している。 (freelist が毎回 0=NULL になっているから)
  • malloc のトータルは readlines のほうが多い。 (malloc_increase を合計すれば総 malloc 量がわかる)
  • 生成したオブジェクト総数も readlines.rb のほうが多い。
  • readlines.rb では初回の GC でほとんどオブジェクトを回収できておらず、 それに伴って malloc_limit も激増している。

つまり、readlines.rb のほうが速いのはメモリ使用量が少ないからでもなく オブジェクト生成数が少ないからでもなく、オブジェクト生成パターンが 現在の Ruby のガーベージコレクタのアルゴリズムとマッチしてしまった からだと考えられる。そのパターンとは、

  • 回収できないオブジェクト数が一気に増えて一気に減る

である。下手にちまちまとオブジェクトを回収できてしまうと GC が平坦に発生してしまう。 負荷をかけるときは容赦なく負荷をかけて、 早いうちに ruby に回収をあきらめさせたほうがよいのだ。

というのが結論だけど、どうだろう?

おまけ

今回使った GC 統計報告パッチ (CVS HEAD 用)

64bit マシンならそれくらいは積んでるかもしらん

なんか、malloc_limit がでかすぎる? これだと閾値が 3GB ってことになるな。

Ruby / 実行速度 (3)

いや待てよ、そもそも GC が原因であると特定していないじゃないか。 GC を切って測定してみるべきだな。

% time ruby -ramstd/nogc foreach.rb
0.30s user 0.04s system 101% cpu 0.335 total
% time ruby -ramstd/nogc readlines.rb
0.30s user 0.05s system 101% cpu 0.344 total

ほとんど変わらないな。やっぱ GC が原因か。

名前
メールアドレス

<前の日 | この月 | 次の日>
2002|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|04|05|06|09|10|
2009|07|
2010|09|

Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved. LIRS