Feature #2447

reduce GC pressure by symbol table without String instance

Added by mame (Yusuke Endoh) over 2 years ago. Updated about 1 year ago.

[ruby-dev:39846]
Status:Assigned Start date:12/06/2009
Priority:Normal Due date:
Assignee:ko1 (Koichi Sasada) % Done:

0%

Category:core
Target version:2.0.0

Description

遠藤です。

現在のシンボルテーブルは、シンボルごとに String のインスタンスを
割り当ててシンボル名を管理しますが、そのせいで GC の効率が落ちて
いると思います。

String ではなく ALLOC で直接確保した領域で管理するパッチを書きま
した。極端な例ではこのくらい早くなります。


# パッチ前
$ time ./ruby.org -e '10000.times { GC.start }; p ObjectSpace.count_objects[:T_STRING]'
1778

real    0m3.766s
user    0m3.764s
sys     0m0.004s

# パッチ後
$ time ./ruby.new -e '10000.times { GC.start }; p ObjectSpace.count_objects[:T_STRING]'
433

real    0m2.880s
user    0m2.876s
sys     0m0.004s


benchmark 結果は最後にあります。多くのものはほぼ変わらないか速く
なっていると思います。
so_meteor_contest は有意に速度低下しますが (再現性あり) 、理由は
よくわかりません。vm3_thread_mutex は実行する度に実行時間が大きく
変わっていた (3 秒以下から 30 秒超) ので、参考になりませんでした。

どなたか追試してくださると助かります。私の環境で make test-all は
通っています。


 1.89s (2.57%): vm2_eval 73.65->71.76
 1.88s (2.44%): so_fannkuch 77.14->75.25
 1.86s (8.08%): so_partial_sums 23.04->21.18
 1.73s (7.20%): so_mandelbrot 23.98->22.26
 1.43s (8.68%): so_spectralnorm 16.43->15.00
 1.02s (6.19%): so_nbody 16.49->15.47
 0.99s (1.13%): app_pentomino 87.50->86.51
 0.82s (6.67%): vm1_block 12.23->11.41
 0.76s (5.28%): so_nsieve_bits 14.37->13.61
 0.51s (15.68%): vm3_gc 3.25->2.74
 0.34s (3.16%): so_fasta 10.69->10.35
 0.23s (5.13%): so_exception 4.52->4.29
 0.22s (3.01%): loop_for 7.45->7.22
 0.19s (9.06%): app_raise 2.10->1.91
 0.18s (4.67%): so_object 3.88->3.70
 0.12s (1.77%): loop_times 6.54->6.42
 0.11s (8.49%): so_random 1.31->1.20
 0.09s (2.44%): app_uri 3.88->3.78
 0.09s (1.07%): vm1_simplereturn 8.35->8.26
 0.07s (4.13%): app_strconcat 1.64->1.57
 0.06s (0.80%): vm2_mutex 7.33->7.27
 0.06s (2.94%): app_erb 1.95->1.89
 0.05s (0.59%): vm2_method 8.94->8.89
 0.04s (1.04%): vm2_array 3.63->3.59
 0.04s (0.97%): vm1_rescue 3.80->3.76
 0.03s (0.56%): so_nested_loop 5.88->5.85
 0.03s (0.75%): loop_generator 3.83->3.80
 0.03s (0.51%): so_pidigits 5.38->5.35
 0.03s (2.87%): io_file_read 0.95->0.93
 0.03s (0.74%): vm2_proc 3.51->3.48
 0.02s (0.65%): vm1_ensure 3.82->3.79
 0.02s (1.45%): vm2_poly_method_ov 1.64->1.61
 0.02s (0.74%): vm2_zsuper 2.88->2.86
 0.02s (2.50%): app_mandelbrot 0.83->0.80
 0.02s (0.46%): app_tak 4.36->4.34
 0.02s (1.34%): vm2_case 1.24->1.23
 0.01s (1.04%): io_file_create 1.18->1.17
 0.01s (0.43%): so_matrix 2.11->2.10
 0.01s (0.18%): so_ackermann 3.62->3.62
 0.01s (0.19%): app_fib 3.21->3.21
 0.01s (1.47%): so_sieve 0.41->0.40
 0.00s (0.06%): vm1_ivar 6.23->6.22
 0.00s (0.03%): so_concatenate 1.91->1.91
 0.00s (0.05%): app_factorial 0.66->0.66
 0.00s (0.00%): vm1_neq 6.22->6.22
-0.00s (-0.03%): vm2_send 2.02->2.02
-0.00s (-0.41%): app_answer 0.24->0.25
-0.00s (-1.53%): so_reverse_complement 0.09->0.09
-0.00s (-1.96%): so_k_nucleotide 0.07->0.07
-0.00s (-0.38%): io_file_write 0.44->0.44
-0.00s (-0.11%): loop_whileloop 3.38->3.39
-0.00s (-0.13%): app_tarai 3.51->3.51
-0.01s (-0.64%): so_count_words 1.09->1.10
-0.01s (-0.68%): so_lists 1.68->1.69
-0.02s (-2.50%): loop_whileloop2 0.67->0.68
-0.02s (-1.04%): vm2_unif1 1.76->1.78
-0.02s (-1.12%): so_binary_trees 1.81->1.83
-0.03s (-1.10%): vm2_super 2.75->2.78
-0.03s (-0.56%): vm1_const 5.80->5.83
-0.05s (-0.70%): vm2_regexp 6.55->6.59
-0.05s (-0.51%): vm3_thread_create_join 10.49->10.55
-0.06s (-1.18%): vm1_swap 5.18->5.24
-0.11s (-2.21%): vm1_not 4.91->5.02
-0.14s (-1.19%): vm2_poly_method 11.83->11.97
-0.14s (-2.11%): vm1_length 6.64->6.78
-0.15s (-2.33%): vm1_ivar_set 6.57->6.72
-0.18s (-2.42%): so_array 7.40->7.58
-0.31s (-2.23%): so_nsieve 13.79->14.10
-2.22s (-8.38%): so_meteor_contest 26.50->28.72
-26.20s (-177.28%): vm3_thread_mutex 14.78->40.99

-- 
Yusuke Endoh <mame@tsg.ne.jp>

symbol_table_without_string.patch (8 kB) mame (Yusuke Endoh), 12/06/2009 11:24 pm

History

Updated by matz (Yukihiro Matsumoto) over 2 years ago

まつもと ゆきひろです

In message "Re: [ruby-dev:39846] [Bug #2447] reduce GC pressure by symbol table without String instance"
    on Sun, 6 Dec 2009 23:24:59 +0900, Yusuke Endoh <redmine@ruby-lang.org> writes:

|現在のシンボルテーブルは、シンボルごとに String のインスタンスを
|割り当ててシンボル名を管理しますが、そのせいで GC の効率が落ちて
|いると思います。
|
|String ではなく ALLOC で直接確保した領域で管理するパッチを書きま
|した。極端な例ではこのくらい早くなります。

確かに。実はSymbolをGCの対象としようとする伏線で現状のように
なっているのですが、思ったより難しくて放置してます。当面、
SymbolのGCはできそうにないんだから、遠藤さんの指摘のようにす
べきなのかなあ。

Updated by wanabe (_ wanabe) over 2 years ago

ワナベと申します。

09/12/06 Yusuke Endoh <redmine@ruby-lang.org>:
> 現在のシンボルテーブルは、シンボルごとに String のインスタンスを
> 割り当ててシンボル名を管理しますが、そのせいで GC の効率が落ちて
> いると思います。
>
> String ではなく ALLOC で直接確保した領域で管理するパッチを書きま
> した。極端な例ではこのくらい早くなります。
(中略)
> どなたか追試してくださると助かります。私の環境で make test-all は
> 通っています。

興味がありますので試してみたところ、
少し不思議な結果になりましたので報告させていただきます。
詳細はわかりませんが、環境が貧弱であることが関係していると思われます。

生のベンチマーク結果を末尾に添付します。
そのうち大きく差があったものについて、改めて再現性を調べました。

* 速くなったもの、再現性あり
app_pentomino   :  185 -  187 秒 =>  182 -  183 秒
so_fannkuch     :  194 -  195 秒 =>  191 -  192 秒
so_mandelbrot   : 56.1 - 56.3 秒 => 48.2 - 48.3 秒
so_nbody        : 39.2 - 39.5 秒 => 34.4 - 35.0 秒
so_partial_sums : 54.3 - 54.5 秒 => 47.0 - 47.0 秒
so_spectralnorm : 39.4 - 39.6 秒 => 35.4 - 35.5 秒
vm1_block*      : 28.5 - 29.5 秒 => 22.5 - 22.8 秒
vm1_const*      :  6.4 -  6.6 秒 =>  5.5 -  5.5 秒
vm1_not*        :  5.6 -  5.8 秒 =>  4.1 -  4.2 秒
vm3_gc          : 10.4 - 10.5 秒 =>  9.0 -  9.0 秒

* 遅くなったもの、再現性あり
loop_whileloop2       : 17.0 - 17.5 秒 => 18.0 - 18.5 秒
so_ackermann          :  8.6 -  8.7 秒 =>  8.7 -  8.9 秒
so_exception          : 11.8 - 12.2 秒 => 12.8 - 13.4 秒
so_meteor_contest     : 46.4 - 48.8 秒 => 50.4 - 51.2 秒
so_reverse_complement :  388 -  389 秒 =>  391 -  392 秒
vm2_eval*             :  195 -  198 秒 =>  206 -  207 秒

* 生データでは変化があったが、再現性のないもの
app_tak        : パッチ前後ともに 10.5 - 11.2 秒
io_file_read   : パッチ前後ともに   39 -   42 秒
loop_generator : パッチ前後ともに  5.6 -  6.2 秒
loop_times     : パッチ前後ともに 14.1 - 14.5 秒
so_count_words : パッチ前後ともに    2 -    5 秒
so_array       : パッチ前後ともに   13 -   19 秒
so_sieve       : パッチ前後ともに  1.3 -  4.2 秒

benchmark results:
name    ruby 1.9.2dev (2009-12-06 trunk 26029) [i386-mingw32]   ruby
1.9.2dev (2009-12-06 trunk 26029) [i386-mingw32]
app_answer      0.766   0.797
app_erb 4.484   4.422
app_factorial   2.500   2.641
app_fib 7.797   7.984
app_mandelbrot  2.125   2.172
app_pentomino   187.578 183.078
app_raise       5.422   5.438
app_strconcat   3.313   3.172
app_tak 10.547  11.141
app_tarai       9.203   9.313
app_uri 8.828   8.391
io_file_create  33.641  32.641
io_file_read    39.219  42.203
io_file_write   28.719  28.578
loop_for        15.875  15.875
loop_generator  5.719   6.125
loop_times      13.984  14.328
loop_whileloop  8.125   8.156
loop_whileloop2 1.734   1.844
so_ackermann    8.672   8.781
so_array        19.031  13.938
so_binary_trees 3.906   4.016
so_concatenate  3.719   3.813
so_count_words  5.734   6.844
so_exception    12.047  13.203
so_fannkuch     195.047 191.688
so_fasta        25.000  24.891
so_k_nucleotide 16.469  16.797
so_lists        3.453   3.406
so_mandelbrot   56.344  48.313
so_matrix       4.172   4.266
so_meteor_contest       46.438  50.484
so_nbody        39.297  34.922
so_nested_loop  11.859  12.031
so_nsieve       28.922  29.125
so_nsieve_bits  27.938  27.281
so_object       9.063   9.656
so_partial_sums 54.563  47.047
so_pidigits     17.578  17.594
so_random       3.609   3.328
so_reverse_complement   387.969 392.344
so_sieve        2.234   1.531
so_spectralnorm 39.375  35.422
vm1_block*      29.516  22.875
vm1_const*      6.438   5.547
vm1_ensure*     2.344   2.250
vm1_ivar*       7.844   7.547
vm1_ivar_set*   7.031   7.000
vm1_length*     8.797   8.594
vm1_neq*        6.547   6.922
vm1_not*        5.688   4.172
vm1_rescue*     2.328   2.250
vm1_simplereturn*       13.078  12.797
vm1_swap*       4.375   4.328
vm2_array*      15.063  15.016
vm2_case*       1.844   1.656
vm2_eval*       195.141 206.078
vm2_method*     19.266  19.016
vm2_mutex*      12.469  12.422
vm2_poly_method*        24.109  24.188
vm2_poly_method_ov*     2.344   2.328
vm2_proc*       5.859   5.844
vm2_regexp*     9.953   9.438
vm2_send*       3.156   2.891
vm2_super*      4.781   4.641
vm2_unif1*      2.813   2.625
vm2_zsuper*     5.500   5.406
vm3_gc  10.531  9.031
vm3_thread_create_join  27.234  27.828
vm3_thread_mutex        3.000   3.188

-- 
ワナベ

Updated by mame (Yusuke Endoh) over 2 years ago

遠藤です。

2009年12月8日18:37 wanabe <s.wanabe@gmail.com>:
>> どなたか追試してくださると助かります。私の環境で make test-all は
>> 通っています。
>
> 興味がありますので試してみたところ、
> 少し不思議な結果になりましたので報告させていただきます。
> 詳細はわかりませんが、環境が貧弱であることが関係していると思われます。
>
> 生のベンチマーク結果を末尾に添付します。
> そのうち大きく差があったものについて、改めて再現性を調べました。


とても詳しい追試、ありがとうございます。


> * 速くなったもの、再現性あり
> app_pentomino   :  185 -  187 秒 =>  182 -  183 秒
> so_fannkuch     :  194 -  195 秒 =>  191 -  192 秒
> so_mandelbrot   : 56.1 - 56.3 秒 => 48.2 - 48.3 秒
> so_nbody        : 39.2 - 39.5 秒 => 34.4 - 35.0 秒
> so_partial_sums : 54.3 - 54.5 秒 => 47.0 - 47.0 秒
> so_spectralnorm : 39.4 - 39.6 秒 => 35.4 - 35.5 秒
> vm1_block*      : 28.5 - 29.5 秒 => 22.5 - 22.8 秒
> vm1_const*      :  6.4 -  6.6 秒 =>  5.5 -  5.5 秒
> vm1_not*        :  5.6 -  5.8 秒 =>  4.1 -  4.2 秒
> vm3_gc          : 10.4 - 10.5 秒 =>  9.0 -  9.0 秒

それぞれ 2% 、2% 、14% 、12% 、14% 、10% 、21% 、15% 、27% 、13%
くらいの高速化ですね。


> * 遅くなったもの、再現性あり
> loop_whileloop2       : 17.0 - 17.5 秒 => 18.0 - 18.5 秒
> so_ackermann          :  8.6 -  8.7 秒 =>  8.7 -  8.9 秒
> so_exception          : 11.8 - 12.2 秒 => 12.8 - 13.4 秒
> so_meteor_contest     : 46.4 - 48.8 秒 => 50.4 - 51.2 秒
> so_reverse_complement :  388 -  389 秒 =>  391 -  392 秒
> vm2_eval*             :  195 -  198 秒 =>  206 -  207 秒

-6% 、-2% 、-9% 、-7% 、-1% 、-5% くらいですね。

総じて言えば、速くなっていると言えるのではないかと思います。
どうでしょうか。

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Updated by mame (Yusuke Endoh) about 2 years ago

遠藤です。

明らかに feature request なので移動します。

-- 
Yusuke Endoh <mame@tsg.ne.jp>

Updated by shyouhei (Shyouhei Urabe) over 1 year ago

  • Status changed from Open to Assigned

Also available in: Atom PDF