Feature #3203
closedLazySweepGC patch
Description
=begin
ご無沙汰しています。nariです。
CRubyのGCにLazySweepを組み込んだパッチを作成しました(リビジョン27489向
け)。
= 実装について
== 概要
基本的に以下の動作を繰り返します。
0. オブジェクトが足りなくなったら 1.へ
- マーク済みのRubyヒープスロットの一つをスイープ
- もし、空きオブジェクトが見つかればオブジェクトを返却し、LazySweep終
了 - もし、空きオブジェクトな見つからなければ、次のマーク済みRubyヒープス
ロットをLazySweepの対象とし、1.へ - マーク済みRubyヒープスロットがすべてなくなった場合はマークを実施し、
1.へ
LazySweepしないGC(普通のGC)も残しており、GC.startの時はこちらを呼びま
す。
== Rubyヒープ拡張&縮小
Rubyヒープの拡張と縮小はタイミングが異なるだけです。
Rubyのヒープ拡張はLazySweepと同時に行います。具体的にはヒープスロットを
1個増やすと同時に、Rubyヒープスロットを1個スイープするようにしています。
この工夫によって、Rubyヒープ内にまったく空きがない場合でも、GC停止時間
を最低限に抑えることができます。
Rubyヒープ拡張をLazySweep時に行うため、マーク後には拡張の決定をしなけれ
ばなりません。そのため、マーク時に生きているオブジェクト数をカウントし
ています。これによってマークフェーズは以前と比べて少しだけ遅くなります。
Rubyヒープ縮小も同じくLazySweep時に行います。
== sorted_heaps_slot構造体の追加
heaps_slot構造体は配列として管理するのをやめ、LazySweepの対象となる
Rubyヒープスロットは双方向リストで管理しています。
is_pointer_to_heap()関数ではheaps_slot構造体の変わりに
sorted_heaps_slot構造体を使用するように変更しました。
= 性能評価
== ベンチマークプログラム
生きているオブジェクト、死んでいるオブジェクトがある程度バラバラにRuby
ヒープ内に分布するようなベンチマークプログラムを作成し、計測に使用しま
した(※添付ファイル参照)。
== 結果
GC最大停止時間:48.00ms => 28.00ms (58%)
GC総停止時間:0.83ms => 0.92ms (110%)
総停止時間は悪くなりますが、最大停止時間については改善が見られます。
その他、有用なベンチマークをご存じでしたら測ってご報告いただけると嬉し
いです。
= 動作検証
以下の環境でのmake test-allが通る(パッチ対象のリビジョンと比較して変化
がない)ことを確認しています。
$ uname -a
Linux nari-laptop 2.6.31-20-generic #58-Ubuntu SMP Fri Mar 12 05:23:09 UTC 2010 i686 GNU/Linux
=end
Files
Updated by matz (Yukihiro Matsumoto) over 14 years ago
=begin
まつもと ゆきひろです
In message "Re: [ruby-dev:41067] [Feature #3203] LazySweepGC patch"
on Tue, 27 Apr 2010 01:11:50 +0900, Narihiro Nakamura redmine@ruby-lang.org writes:
|CRubyのGCにLazySweepを組み込んだパッチを作成しました(リビジョン27489向
|け)。
コミットしちゃっていいんじゃないですかね。
=end
Updated by mame (Yusuke Endoh) over 14 years ago
=begin
遠藤です。
2010年4月27日1:11 Narihiro Nakamura redmine@ruby-lang.org:
その他、有用なベンチマークをご存じでしたら測ってご報告いただけると嬉し
いです。
有用かはわかりませんが、make benchmark の結果くらいは確認して欲しいです。
というだけなのもなんなので、自分で試してみましたが、app_pentomino で
./benchmark/bm_app_pentomino.rb:117:in block (2 levels) in setpiece': method
method_missing' called on unexpected T_NODE object (0x8217f0c
flags=0x383c klass=0x0) (NotImplementedError)
で落ちました。もうちょっとデバッグが必要なようです。
いずれにせよ、1.9.2 にはコミットするかは議論の余地があると思います。
--
Yusuke Endoh mame@tsg.ne.jp
=end
Updated by naruse (Yui NARUSE) over 14 years ago
=begin
成瀬です。
Yusuke ENDOH mame@tsg.ne.jp:
2010年4月27日1:11 Narihiro Nakamura redmine@ruby-lang.org>:
その他、有用なベンチマークをご存じでしたら測ってご報告いただけると嬉しいです。
有用かはわかりませんが、make benchmark の結果くらいは確認して欲しいです。
make test-all の所要時間と、make test-rubyspec の所要時間とか (結果も)、
あと encoding テーブルの作成時間とかもありますかね。
いずれにせよ、1.9.2 にはコミットするかは議論の余地があると思います。
え、1.9.2 に対してのコミットで議論の余地があるんですか?
このレベルの変更を今から 1.9.2 に対して行うのは無いと思います。
やるなら1.9.2ブランチを切ってからでしょう。
--
NARUSE, Yui
naruse@airemix.jp
=end
Updated by authorNari (Narihiro Nakamura) over 14 years ago
=begin
nariです。
2010年4月27日10:18 NARUSE, Yui naruse@airemix.jp:
成瀬です。
Yusuke ENDOH mame@tsg.ne.jp:
2010年4月27日1:11 Narihiro Nakamura redmine@ruby-lang.org>:
その他、有用なベンチマークをご存じでしたら測ってご報告いただけると嬉しいです。
有用かはわかりませんが、make benchmark の結果くらいは確認して欲しいです。make test-all の所要時間と、make test-rubyspec の所要時間とか (結果も)、
あと encoding テーブルの作成時間とかもありますかね。
ありがとうございます。調べてみます。
バグもあるみたいなので直します。
いずれにせよ、1.9.2 にはコミットするかは議論の余地があると思います。
え、1.9.2 に対してのコミットで議論の余地があるんですか?
このレベルの変更を今から 1.9.2 に対して行うのは無いと思います。
やるなら1.9.2ブランチを切ってからでしょう。
個人的な考えでは1.9.2に入れるつもりはありませんでした。
混乱させてしまってすみません。
--
Narihiro Nakamura (nari)
=end
Updated by authorNari (Narihiro Nakamura) over 14 years ago
=begin
nariです。
make test-rubyspec、check、benchmarkが通るようなりました。
また、make、make benchmark、test-all、test-rubyspecの実行速度も調べてみ
ました。極端に遅くなったものはなさそうです。そもそもプログラム実行時間
が早くなるたぐいの修正ではないので、目立ってに遅くなければOKだろうと思っ
ています。
make test-all
trunk : 183.42s
lazy_sweep : 196.92s
make test-rubyspec
trunk : 104.484065s
lazy_sweep : 106.389376s
make
trunk : 229.13s
lazy_sweep : 228.63s
make bechmark
minimum results in each 5 measurements.
name trunk lazy_sweep
app_answer 0.149 0.152
app_erb 1.027 1.090
app_factorial 0.495 0.500
app_fib 1.683 1.838
app_mandelbrot 0.460 0.506
app_pentomino 45.964 46.075
app_raise 1.364 1.403
app_strconcat 0.868 0.901
app_tak 2.334 2.447
app_tarai 1.857 1.840
app_uri 2.043 2.086
io_file_create 0.681 0.678
io_file_read 0.930 0.881
io_file_write 0.326 0.329
loop_for 3.810 6.067
loop_generator 1.984 1.988
loop_times 3.343 3.450
loop_whileloop 1.558 2.283
loop_whileloop2 0.322 0.477
so_ackermann 2.085 2.009
so_array 4.263 4.331
so_binary_trees 1.004 0.998
so_concatenate 0.956 0.970
so_count_words 0.424 0.439
so_exception 2.768 2.839
so_fannkuch 42.900 43.804
so_fasta 5.927 5.611
so_k_nucleotide 3.812 3.824
so_lists 0.854 0.876
so_mandelbrot 13.081 13.742
so_matrix 0.997 1.014
so_meteor_contest 14.278 14.269
so_nbody 9.369 10.590
so_nested_loop 3.067 3.061
so_nsieve 7.446 6.849
so_nsieve_bits 8.297 8.183
so_object 2.272 2.238
so_partial_sums 12.288 12.358
so_pidigits 3.317 3.311
so_random 0.808 0.850
so_reverse_complement 3.596 3.420
so_sieve 0.211 0.264
so_spectralnorm 11.595 8.725
vm1_block* 4.135 4.208
vm1_const* 2.050 2.176
vm1_ensure* 0.326 1.420
vm1_ivar* 2.275 2.938
vm1_ivar_set* 2.280 2.827
vm1_length* 1.588 2.262
vm1_neq* 1.184 1.194
vm1_not* 0.987 1.457
vm1_rescue* 0.422 0.336
vm1_simplereturn* 2.753 2.958
vm1_swap* 0.784 1.144
vm2_array* 1.802 1.917
vm2_case* 0.467 0.328
vm2_eval* 44.158 48.817
vm2_method* 4.541 4.400
vm2_mutex* 3.076 3.464
vm2_poly_method* 6.382 6.475
vm2_poly_method_ov* 0.881 0.856
vm2_proc* 1.595 1.432
vm2_regexp* 3.122 3.466
vm2_send* 1.030 0.910
vm2_super* 1.317 1.074
vm2_unif1* 0.904 0.579
vm2_zsuper* 1.277 1.357
vm3_gc 1.784 1.758
vm3_thread_create_join 5.890 6.038
vm3_thread_mutex 6.216 3.074
r28028に対するパッチを添付しておきます。
githubでforkして開発しています。¶
http://github.com/authorNari/ruby¶
Attachment: gc_simple_lazy_sweep_r28028.diff
=end
Updated by kosaki (Motohiro KOSAKI) over 14 years ago
=begin
kosakiです
個人的意見ですが
nariです。
make test-rubyspec、check、benchmarkが通るようなりました。
また、make、make benchmark、test-all、test-rubyspecの実行速度も調べてみ
ました。極端に遅くなったものはなさそうです。そもそもプログラム実行時間
が早くなるたぐいの修正ではないので、目立ってに遅くなければOKだろうと思っ
ています。
すでにまつもとさんからコミット許可もでているようだし、コミットしちゃえば
いいんじゃないですかね。
こういう変更大きいやつはブランチきってすぐの、今のような時期が一番
リスク低いんじゃないかなー的な意味で
=end
Updated by matz (Yukihiro Matsumoto) over 14 years ago
=begin
まつもと ゆきひろです
In message "Re: [ruby-dev:41443] Re: [Feature #3203] LazySweepGC patch"
on Fri, 28 May 2010 05:15:09 +0900, Narihiro Nakamura authornari@gmail.com writes:
|make test-rubyspec、check、benchmarkが通るようなりました。
|
|また、make、make benchmark、test-all、test-rubyspecの実行速度も調べてみ
|ました。極端に遅くなったものはなさそうです。そもそもプログラム実行時間
|が早くなるたぐいの修正ではないので、目立ってに遅くなければOKだろうと思っ
|ています。
コミットしちゃって。
=end
Updated by akr (Akira Tanaka) over 14 years ago
=begin
2010年5月28日5:15 Narihiro Nakamura authornari@gmail.com:
make test-rubyspec、check、benchmarkが通るようなりました。
思い立って、GC.stress を true にしてテストを動かしてみました。
つまり、
for f in test/test_* test/*(/)
do
echo $f
./ruby -e 'GC.stress = true; load "test/runner.rb"' $f
done
のようなかんじです。
まだ終わってませんが、いくつも問題を発生させられるようです。
コンパイラなどによっても違うでしょうから私だけでなく、他の人もやってみるといいかもしれません。
とりあえず、発生した問題の一つは以下のようなものです。
% ./ruby -e 'GC.stress = true; load "test/runner.rb"' test/cgi
Loaded suite -e
Started
......................................
Finished in 597.027141 seconds.
38 tests, 524 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 55933
-e: [BUG] Segmentation fault
ruby 1.9.3dev (2010-05-29 trunk 28057) [i686-linux]
-- control frame ----------
c:0001 p:0000 s:0002 b:0002 l:00236c d:00236c TOP
-- C level backtrace information -------------------------------------------
./ruby(rb_vm_bugreport+0x73) [0x815803e]
./ruby [0x818d07b]
./ruby(rb_bug+0x36) [0x818d0d6]
./ruby [0x80eecb7]
[0xb7fbc410]
./ruby [0x806813d]
./ruby(rb_gc_call_finalizer_at_exit+0x19) [0x806806a]
./ruby [0x805e98a]
./ruby(ruby_cleanup+0x1de) [0x805eb7c]
./ruby(ruby_run_node+0x43) [0x805ee2d]
./ruby(main+0x74) [0x805d898]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7ddc455]
./ruby [0x805d791]
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html
lazy sweep 以前からあった問題かも知れませんけれど。¶
[田中 哲][たなか あきら][Tanaka Akira]
=end
Updated by authorNari (Narihiro Nakamura) over 14 years ago
=begin
2010年5月29日18:28 Tanaka Akira akr@fsij.org:
2010年5月28日5:15 Narihiro Nakamura authornari@gmail.com:
make test-rubyspec、check、benchmarkが通るようなりました。
思い立って、GC.stress を true にしてテストを動かしてみました。
つまり、
for f in test/test_* test/*(/)
do
echo $f
./ruby -e 'GC.stress = true; load "test/runner.rb"' $f
doneのようなかんじです。
まだ終わってませんが、いくつも問題を発生させられるようです。
コンパイラなどによっても違うでしょうから私だけでなく、他の人もやってみるといいかもしれません。とりあえず、発生した問題の一つは以下のようなものです。
% ./ruby -e 'GC.stress = true; load "test/runner.rb"' test/cgi
Loaded suite -e
Started
......................................
Finished in 597.027141 seconds.38 tests, 524 assertions, 0 failures, 0 errors, 0 skips
Test run options: --seed 55933
-e: [BUG] Segmentation fault
ruby 1.9.3dev (2010-05-29 trunk 28057) [i686-linux]-- control frame ----------
c:0001 p:0000 s:0002 b:0002 l:00236c d:00236c TOP-- C level backtrace information -------------------------------------------
./ruby(rb_vm_bugreport+0x73) [0x815803e]
./ruby [0x818d07b]
./ruby(rb_bug+0x36) [0x818d0d6]
./ruby [0x80eecb7]
[0xb7fbc410]
./ruby [0x806813d]
./ruby(rb_gc_call_finalizer_at_exit+0x19) [0x806806a]
./ruby [0x805e98a]
./ruby(ruby_cleanup+0x1de) [0x805eb7c]
./ruby(ruby_run_node+0x43) [0x805ee2d]
./ruby(main+0x74) [0x805d898]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7ddc455]
./ruby [0x805d791][NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.htmllazy sweep 以前からあった問題かも知れませんけれど。
ご指摘ありがとうございます。
調べてみます。
--
[田中 哲][たなか あきら][Tanaka Akira]
--
Narihiro Nakamura (nari)
=end
Updated by mame (Yusuke Endoh) over 14 years ago
=begin
遠藤です。
2010年5月29日18:28 Tanaka Akira akr@fsij.org:
思い立って、GC.stress を true にしてテストを動かしてみました。
ということを考えると、テストフレームワークは極限まで単純な方がいいですねえ。
% ./ruby -e 'GC.stress = true; load "test/runner.rb"' test/cgi
sniplazy sweep 以前からあった問題かも知れませんけれど。
これに関しては、lazy sweep 以前からあった問題のようです。
diff --git a/string.c b/string.c
index f2f49ab..ae42893 100644
--- a/string.c
+++ b/string.c
@@ -613,8 +613,8 @@ str_replace_shared(VALUE str2, VALUE str)
STR_SET_EMBED_LEN(str2, RSTRING_LEN(str));
}
else {
- FL_SET(str2, STR_NOEMBED);
str = rb_str_new_frozen(str);
- FL_SET(str2, STR_NOEMBED);
RSTRING(str2)->as.heap.len = RSTRING_LEN(str);
RSTRING(str2)->as.heap.ptr = RSTRING_PTR(str);
RSTRING(str2)->as.heap.aux.shared = str;
--
Yusuke Endoh mame@tsg.ne.jp
=end
Updated by mame (Yusuke Endoh) over 14 years ago
=begin
遠藤です。
2010年5月29日23:02 Narihiro Nakamura authornari@gmail.com:
ご指摘ありがとうございます。
調べてみます。
akr さんの件は無実でした (というか [Bug #3241] でパッチ作成済み
だったのに私がコミットし忘れてました。すみません) が、以下は Lazy
Sweep コミット後から SEGV するようになったようです。
ご確認ください。
$ ./ruby -e '1000.times { ObjectSpace.define_finalizer("foo".dup, proc
{ GC.start }) }'
-e:1: [BUG] gc_sweep(): unknown data type 0x1e(0x822c574)
ruby 1.9.3dev (2010-05-28 trunk 28063) [i686-linux]
-- control frame ----------
c:0005 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :start
c:0004 p:0015 s:0008 b:0008 l:002054 d:000007 BLOCK -e:1
c:0003 p:---- s:0006 b:0006 l:000005 d:000005 FINISH
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 CFUNC :call
c:0001 p:0000 s:0002 b:0002 l:002054 d:002054 TOP
-- Ruby level backtrace information ----------------------------------------
-e:0:in call' -e:1:in
block (2 levels) in '
-e:1:in `start'
-- C level backtrace information -------------------------------------------
./ruby(rb_vm_bugreport+0xbd) [0x815903d]
./ruby [0x81968ae]
./ruby(rb_bug+0x28) [0x8196968]
./ruby [0x8063641]
./ruby [0x8067597]
./ruby(rb_gc_start+0x19) [0x8067c79]
./ruby [0x814fab0]
./ruby [0x8151e88]
./ruby [0x815576b]
./ruby(rb_vm_invoke_proc+0x76) [0x8149696]
./ruby [0x8061434]
./ruby [0x8144c1d]
./ruby [0x8149ba9]
./ruby [0x814b1e8]
./ruby(rb_eval_cmd+0xe6) [0x8156736]
./ruby [0x8063961]
./ruby(rb_protect+0x128) [0x805b358]
./ruby [0x8063900]
./ruby [0x8064b3b]
./ruby [0x8064c02]
./ruby(ruby_cleanup+0x1a4) [0x805ccd4]
./ruby(ruby_run_node+0x3a) [0x805ceea]
./ruby(main+0x5a) [0x805a95a]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe5) [0xb7e11455]
./ruby [0x805a861]
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html
アボートしました
--
Yusuke Endoh mame@tsg.ne.jp
=end
Updated by akr (Akira Tanaka) over 14 years ago
=begin
2010年5月30日0:23 Yusuke ENDOH mame@tsg.ne.jp:
akr さんの件は無実でした (というか [Bug #3241] でパッチ作成済み
だったのに私がコミットし忘れてました。すみません) が、以下は Lazy
そうでしたか。
まぁ、それはそれとしていくつも出るのでもうひとつ。
もちろん lazy sweep と関係あるかどうかは不明です。
% ./ruby -ve 'GC.stress = true; load "test/runner.rb"' test/test_delegate.rb
ruby 1.9.3dev (2010-05-30 trunk 28074) [x86_64-linux]
Loaded suite -e
Started
....E../home/akr/chkbuild/tmp/build/ruby-trunk/20100530T001915/lib/ruby/1.9.1/minitest/unit.rb:302:
warning: too many arguments for format string
E..
Finished in 1.676947 seconds.
-
Error:
test_instance_method(TestDelegateClass):
TypeError: can't convert Hash into String
/home/akr/chkbuild/tmp/build/ruby-trunk/20100530T001915/ruby/test/test_delegate.rb:111:in
`test_instance_method' -
Error:
test_private_method(TestDelegateClass):
TypeError: can't convert Array into String
/home/akr/chkbuild/tmp/build/ruby-trunk/20100530T001915/ruby/test/test_delegate.rb:126:in
`test_private_method'
10 tests, 24 assertions, 0 failures, 2 errors, 0 skips
Test run options: --seed 37501¶
[田中 哲][たなか あきら][Tanaka Akira]
=end
Updated by metanest (Makoto Kishimoto) over 14 years ago
=begin
きしもとです
手元の環境だと以下のエラーが出てます。
test-all すると(動き出すまでにえらい時間がかかったあと)同じところで to_str が
無限に再帰して? core を吐きます。
$ ../tool/runruby.rb --extout=.ext -- -e 'GC.stress = true; load "../test/runner.rb"' ../test/cgi/test_cgi_core.rb
Loaded suite -e
Started
..E......
Finished in 1.831383 seconds.
- Error:
test_cgi_core_htmltype(CGICoreTest):
TypeError: can't convert NoMethodError into String
/export/home/ksmakoto/ruby-trunk/test/cgi/test_cgi_core.rb:339:in `test_cgi_core_htmltype'
9 tests, 75 assertions, 0 failures, 1 errors, 0 skips
Test run options: --seed 49582
=end
Updated by akr (Akira Tanaka) over 14 years ago
=begin
2010年6月1日10:55 KISHIMOTO, Makoto ksmakoto@dd.iij4u.or.jp:
- Error:
test_cgi_core_htmltype(CGICoreTest):
TypeError: can't convert NoMethodError into String
/export/home/ksmakoto/ruby-trunk/test/cgi/test_cgi_core.rb:339:in `test_cgi_core_htmltype'9 tests, 75 assertions, 0 failures, 1 errors, 0 skips
Test run options: --seed 49582
これ、いろんなところで出ますねぇ。
現時点で、以下が観測できました。
TypeError: can't convert Array into String
test/rake/test_fileutils.rb:130:in test_fileutils_method TypeError: can't convert Array into String test/ruby/test_basicinstructions.rb:208:in
set_lvar_in_another_method'
TypeError: can't convert Array into String
test/test_delegate.rb:111:in test_instance_method' TypeError: can't convert Array into String test/test_syslog.rb:13:in
test_new'
TypeError: can't convert NoMethodError into String
test/cgi/test_cgi_core.rb:339:in test_cgi_core_htmltype' TypeError: can't convert NoMethodError into String test/date/test_date_arith.rb:87:in
test_prev'
TypeError: can't convert NoMethodError into String
test/rake/test_fileutils.rb:130:in test_fileutils_methods_dont_leak' TypeError: can't convert NoMethodError into String test/ruby/test_alias.rb:44:in
test_alias'
TypeError: can't convert NoMethodError into String
test/ruby/test_clone.rb:24:in test_clone' TypeError: can't convert NoMethodError into String test/ruby/test_complex.rb:1070:in
test_ruby19'
TypeError: can't convert NoMethodError into String
test/ruby/test_complexrational.rb:104:in test_comp_srat' TypeError: can't convert NoMethodError into String test/ruby/test_exception.rb:312:in
test_nomethoderror'
TypeError: can't convert NoMethodError into String
test/test_delegate.rb:111:in test_instance_method' TypeError: can't convert NoMethodError into String test/test_delegate.rb:124:in
test_private_method'
それぞれどんなコードかと思って調べると...
test/rake/test_fileutils.rb:130
assert_raise(NoMethodError) { obj.copy } # from FileUtils
test/ruby/test_basicinstructions.rb:208
assert_raise(NameError) { a }
test/test_delegate.rb:111
assert_raise(NoMethodError, '[ruby-dev:40314]#3') {m.call}
test/test_syslog.rb:13
assert_raises(NoMethodError) {
test/cgi/test_cgi_core.rb:339
assert_raise(NoMethodError) do cgi.doctype end
test/date/test_date_arith.rb:87
assert_raise(NoMethodError) do
test/rake/test_fileutils.rb:130
assert_raise(NoMethodError) { obj.copy } # from FileUtils
test/ruby/test_alias.rb:44
assert_raise(NoMethodError) { x.foo }
test/ruby/test_clone.rb:24
assert_raise(NoMethodError) {foo.test2}
test/ruby/test_complex.rb:1070
assert_raise(NoMethodError){ Complex.new(1) }
test/ruby/test_complexrational.rb:104
assert_raise(NoMethodError){c <=> 2}
test/ruby/test_exception.rb:312
e = assert_raise(NoMethodError) {str.send(id)}
test/test_delegate.rb:111
assert_raise(NoMethodError, '[ruby-dev:40314]#3') {m.call}
test/test_delegate.rb:124
assert_raise(NoMethodError) {foo.delegate_test_private}
みごとにすべて assert_raise (と assert_raises) ですな。¶
[田中 哲][たなか あきら][Tanaka Akira]
=end