Age | Commit message (Collapse) | Author |
|
[Feature #14045]
* insns.def (getblockparam, setblockparam): add special access
instructions for block parameters.
getblockparam checks VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM and
if it is not set this instruction creates a Proc object from
a given blcok and set VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.
setblockparam is similar to setlocal, but set
VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM.
* compile.c: use get/setblockparm instead get/setlocal instructions.
Note that they are used for method local block parameters (def m(&b)),
not for block local method parameters (iter{|&b|).
* proc.c (get_local_variable_ptr): creates Proc object for
Binding#local_variable_get/set.
* safe.c (safe_setter): we need to create Proc objects for postponed
block parameters when $SAFE is changed.
* vm_args.c (args_setup_block_parameter): used only for block local blcok
parameters.
* vm_args.c (vm_caller_setup_arg_block): if called with
VM_CALL_ARGS_BLOCKARG_BLOCKPARAM flag then passed block values should be
a block handler.
* test/ruby/test_optimization.rb: add tests.
* benchmark/bm_vm1_blockparam*: added.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60397 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
This means File.chmod, File.lchmod, File.chown, File.lchown,
File.unlink, and File.utime operations on slow filesystems
no longer hold up other threads.
The platform-specific utime_failed changes is compile-tested
using a new UTIME_EINVAL macro
This hurts performance on fast filesystem, but these methods
are unlikely to be performance bottlenecks and (IMHO) avoiding
pathological slowdowns and stalls are more important.
benchmark results:
minimum results in each 3 measurements.
Execution time (sec)
name trunk built
file_chmod 0.591 0.801
Speedup ratio: compare with the result of `trunk' (greater is better)
name built
file_chmod 0.737
* file.c (UTIME_EINVAL): new macro to ease compile-testing
* file.c (struct apply_arg): new struct
* file.c (no_gvl_apply2files): new function
* file.c (apply2files): release GVL
* file.c (chmod_internal): adjust for apply2files changes
* file.c (lchmod_internal): ditto
* file.c (chown_internal): ditto
* file.c (lchown_internal): ditto
* file.c (utime_failed): ditto
* file.c (utime_internal): ditto
* file.c (unlink_internal): ditto
[ruby-core:83200] [Feature #13996]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60386 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60301 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
[close GH-1724]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60299 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
This converts all slow syscalls in the Dir.empty? implementation
to release GVL. We avoid unnecessarily GVL release and
reacquire for each slow call (opendir, readdir, closedir) and
instead only release and acquire the GVL once in the common
case.
Benchmark results show a small degradation in single-threaded
performance:
Execution time (sec)
name trunk built
dir_empty_p 0.689 0.758
Speedup ratio: compare with the result of `trunk' (greater is better)
name built
dir_empty_p 0.909
* dir.c (rb_gc_for_fd_with_gvl): new function
(nogvl_dir_empty_p): ditto
(dir_s_empty_p): use new functions to release GVL
* benchmark/bm_dir_empty_p.rb: new benchmark
[ruby-core:83071] [Feature #13958]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60111 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
rename(2) requires two pathname resolution operations which can
take considerable time on slow filesystems, release the GVL so
operations on other threads may proceed.
On fast, local filesystems, this change results in some slowdown
as shown by the new benchmark. I consider the performance trade
off acceptable as cases are avoided.
benchmark results:
minimum results in each 3 measurements.
Execution time (sec)
name trunk built
file_rename 2.648 2.804
Speedup ratio: compare with the result of `trunk' (greater is better)
name built
file_rename 0.944
* file.c (no_gvl_rename): new function
(rb_file_s_rename): release GVL for renames
* benchmark/bm_file_rename.rb: new benchmark
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60088 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* string.c (rb_strseq_index): refactor and avoid
call of str_strlen() when offset == 0.
it will improve performance of String#index and #include?
* benchmark/bm_string_index.rb: benchmark for this change
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60086 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
[Feature #13884]
Reduce number of memory allocations for "and", "or" and "diff"
operations on small arrays
Very often, arrays are used to filter parameters and to select
interesting items from 2 collections and very often these
collections are small enough, for example:
```ruby
SAFE_COLUMNS = [:id, :title, :created_at]
def columns
@all_columns & SAFE_COLUMNS
end
```
In this patch, I got rid of unnecessary memory allocations for
small arrays when "and", "or" and "diff" operations are performed.
name | HEAD | PATCH
-----------------+------:+------:
array_small_and | 0.615 | 0.263
array_small_diff | 0.676 | 0.282
array_small_or | 0.953 | 0.463
name | PATCH
-----------------+------:
array_small_and | 2.343
array_small_diff | 2.392
array_small_or | 2.056
name | HEAD | PATCH
-----------------+------:+------:
array_small_and | 1.429 | 1.005
array_small_diff | 1.493 | 0.878
array_small_or | 1.672 | 1.152
name | PATCH
-----------------+------:
array_small_and | 1.422
array_small_diff | 1.700
array_small_or | 1.452
Author: Dmitry Bochkarev <dimabochkarev@gmail.com>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60057 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59494 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
from bm_app_erb_render.rb.
I'm told from ko1 that bm_app_* is namespace for Ruby applications,
not for ERB and we should use bm_erb_* for ERB benchmark instead.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58915 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
to skip object allocation for static string.
We can't always enable frozen_string_literal pragma because we can't
freeze string literals embedded by user for backward compatibility.
So we need to use fstring for each static string.
Since adding ".freeze" to string literals in #content_dump is slow
on compiling, I used unary "-" operator instead.
benchmark/bm_app_erb_render.rb: Added rendering-only benchmark to
test rendering performance on production environment.
This benchmark is created to reproduce the behavior on Sinatra (Tilt).
Thus it doesn't use ERB#result to skip parsing compiled code.
It doesn't use ERB#def_method too to regard `title` and `content` as
local variables. If we use #def_method, `title` and `content` needs
to be method call. I wanted to avoid it.
This patch's benchmark results is:
* Before
app_erb_render 1.250
app_erb 0.704
* After
app_erb_render 1.066
app_erb 0.686
This patch optimizes rendering performance (app_erb_render) without
spoiling (total of rendering +) compiling performance (app_erb).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58905 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
There are currently no benchmarks for Fiber performance, I
should've committed this years ago when [Feature #10341] was
implemented.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58606 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
I was about to write off this benchmark while working on GVL
improvements on multi-core systems.
However I noticed it exposes a weakness in my work-in-progress
code when I tested on an old single CPU system. Further testing
reveals setting CPU affinity ("schedtool -a 0x1" on Linux) on a
modern multi-core system is enough to reproduce the problem
exposed by this benchmark.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58571 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
"lazy_sweep" does not appear to have ever been a valid kwarg
for GC.start, however the opposite of "lazy_sweep" appears
to be "immediate_sweep". So use immediate_sweep, and flip
the boolean value of each arg.
I guess this only started failing with r56981 in Dec 2016
("class.c: missing unknown_keyword_error",
commit e3f0cca2f26ba44c810ac980cdff7dda129ae533)
* benchmark/bm_vm1_gc_wb_ary.rb: "lazy_sweep: false" => "immediate_sweep: true"
* benchmark/bm_vm1_gc_wb_ary_promoted.rb: ditto
* benchmark/bm_vm1_gc_wb_obj.rb: ditto
* benchmark/bm_vm1_gc_wb_obj_promoted.rb: ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58565 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
This is currently for testing GVL performance in the uncontended
case: IO#write and IO#read unconditionally release GVL for
blocking I/O with pipe.
It will also be interesting to see how this changes if we switch
to M:N threading model.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58556 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
I'm working on patches to improve everything in thread_sync.c,
add these to track progress.
* benchmark/bm_vm_thread_sized_queue.rb: add description
* benchmark/bm_vm_thread_condvar1.rb: new benchmark
* benchmark/bm_vm_thread_condvar2.rb: ditto
* benchmark/bm_vm_thread_sized_queue2.rb: ditto
* benchmark/bm_vm_thread_sized_queue3.rb: ditto
* benchmark/bm_vm_thread_sized_queue4.rb: ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58535 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
The performance of SizedQueue is a bit more complex than
regular Queue, so it deserves a separate benchmark.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58509 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* object.c: Add to_r in conv_method_tbl.
* defs/id.def: add to_r.
* benchmark/bm_int_quo.rb: added.
* benchmark/bm_time_subsec.rb: added.
[Bug #13426]
[ruby-core:80665]
[Fix GH-1582]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58347 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* array.c (sort_1): improve performance of Array#sort with block
* benchmark/bm_array_sort_block.rb: added for Array#sort with block
[Bug #13344]
[ruby-dev:50027]
[Fix GH-1544]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58339 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
[Bug #13340]
[ruby-dev:50023]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58337 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57379 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
For testing Linux socket-only workaround for
https://bugs.ruby-lang.org/issues/13085
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57364 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/driver.rb (BenchmarkDriver.load): restore
measure_target option from the loaded results.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57288 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/driver.rb: default output file is not used when
loading rawdata.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57287 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/driver.rb (BenchmarkDriver.load): extract loop times
from the loaded results to adjust the results.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57286 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/driver.rb (show_results): count adjusted result marks
as the name width.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57285 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57283 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
I will attempt to reduce garbage in proposed fix
for https://bugs.ruby-lang.org/issues/13085
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57237 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56937 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56161 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
This helps hit inline method caches more frequently. Before this
commit:
```
[aaron@TC ruby (trunk)]$ time ./ruby -v benchmark/bm_vm2_poly_singleton.rb
ruby 2.4.0dev (2016-09-12 trunk 56141) [x86_64-darwin15]
real 0m3.679s
user 0m3.632s
sys 0m0.022s
```
After this commit:
```
[aaron@TC ruby (trunk)]$ time ./ruby -v benchmark/bm_vm2_poly_singleton.rb
ruby 2.4.0dev (2016-09-12 trunk 56141) [x86_64-darwin15]
last_commit=Copy the serial number from the super class to the singleton class
real 0m2.246s
user 0m2.203s
sys 0m0.020s
```
[Feature #12364]
[ruby-core:75425]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56144 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56037 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
[fix GH-1330][ci skip] Patch by @sachin21
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54667 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/driver.rb (BenchmarkDriver.load): remove unused
variable.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54064 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/memory_wrapper.rb: use respond_to? because
member? does not work well.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54062 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
use `--measure-target=[target]'.
Now, we can use the following targets:
* real (default): real time which returns process time in sec.
* peak: peak memory usage (physical memory) in bytes.
* size: last memory usage (physical memory) in bytes.
* benchmark/memory_wrapper.rb: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54060 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/bm_vm3_gc_old_immediate.rb: ditto.
* benchmark/bm_vm3_gc_old_lazy.rb: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54053 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
receives signals.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54052 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
[ci skip][fix GH-1140] Patch by @jutaz
* benchmark/bm_vm_thread_pipe.rb: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53101 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
The OR-ing itself is bad for a hash function, and shifting 3 bits
left was not enough to undo the damage done by shifting
(RUBY_SPECIAL_SHIFT+3) bits right. Experimentally, shifting 16-17
bits seemed to work well in preparing the number for murmur hash.
Add a few more benchmarks to based on bm_hash_shift to ensure
we don't hurt performance too much with tweaks.
I'm pretty confident about this change and commiting it now;
especially since we're still using Murmur behind it (but perhaps
we can update to a newer hash from Murmur...)
[ruby-core:72028] [Feature #11405]
target 0: a (ruby 2.3.0dev (2015-12-11 trunk 53027) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-11 master 53027) [x86_64-linux]) at "/home/ew/ruby/b/ruby"
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
hash_aref_dsym 0.279 0.276
hash_aref_dsym_long 4.951 4.936
hash_aref_fix 0.281 0.283
hash_aref_flo 0.060 0.060
hash_aref_miss 0.409 0.410
hash_aref_str 0.387 0.385
hash_aref_sym 0.275 0.270
hash_aref_sym_long 0.410 0.411
hash_flatten 0.252 0.237
hash_ident_flo 0.035 0.032
hash_ident_num 0.254 0.251
hash_ident_obj 0.252 0.256
hash_ident_str 0.250 0.252
hash_ident_sym 0.259 0.270
hash_keys 0.267 0.267
hash_shift 0.016 0.015
hash_shift_u16 0.074 0.072
hash_shift_u24 0.071 0.071
hash_shift_u32 0.073 0.072
hash_to_proc 0.008 0.008
hash_values 0.263 0.264
Speedup ratio: compare with the result of `a' (greater is better)
name b
hash_aref_dsym 1.009
hash_aref_dsym_long 1.003
hash_aref_fix 0.993
hash_aref_flo 1.001
hash_aref_miss 0.996
hash_aref_str 1.006
hash_aref_sym 1.017
hash_aref_sym_long 0.998
hash_flatten 1.061
hash_ident_flo 1.072
hash_ident_num 1.012
hash_ident_obj 0.987
hash_ident_str 0.993
hash_ident_sym 0.959
hash_keys 0.997
hash_shift 1.036
hash_shift_u16 1.039
hash_shift_u24 1.001
hash_shift_u32 1.017
hash_to_proc 1.001
hash_values 0.995
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53037 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.
target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549
Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017
* benchmark/bm_vm2_case_lit.rb: new benchmark
* compile.c (case_when_optimizable_literal): add nil/true/false
* insns.def (opt_case_dispatch): ditto
* vm.c (vm_redefinition_check_flag): ditto
* vm.c (vm_init_redefined_flag): ditto
* vm_core.h: ditto
* object.c (InitVM_Object): define === explicitly for nil/true/false
* test/ruby/test_case.rb (test_deoptimize_nil): new test
* test/ruby/test_optimization.rb (test_opt_case_dispatch): update
(test_eqq): new test
[ruby-core:71923] [Feature #11769]
Original patch by Aaron Patterson <tenderlove@ruby-lang.org>
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52931 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/bm_io_nonblock_noex2.rb: new benchmark based
on bm_io_nonblock_noex.rb
* io.c (io_read_nonblock): move documentation to prelude.rb
(io_write_nonblock): ditto
(Init_io): private, internal methods for prelude.rb use only
* prelude.rb (IO#read_nonblock): wrapper + documentation
(IO#write_nonblock): ditto
[ruby-core:71439] [Feature #11339]
rb_scan_args and hash lookups for kwargs in the C API are clumsy and
slow. Instead of improving the C API for performance, use Ruby
instead :)
Implement IO#read_nonblock and IO#write_nonblock in prelude.rb
to avoid argument parsing via rb_scan_args and hash lookups.
This speeds up IO#write_nonblock and IO#read_nonblock benchmarks
in both cases, including the original non-idiomatic case where
the `exception: false' hash is pre-allocated to avoid GC pressure.
Now, writing the kwargs in natural, idiomatic Ruby is fastest.
I've added the noex2 benchmark to show this.
2015-11-12 01:41:12 +0000
target 0: a (ruby 2.3.0dev (2015-11-11 trunk 52540) [x86_64-linux])
target 1: b (ruby 2.3.0dev (2015-11-11 avoid-kwarg-capi 52540)
-----------------------------------------------------------
benchmark results:
minimum results in each 10 measurements.
Execution time (sec)
name a b
io_nonblock_noex 2.508 2.382
io_nonblock_noex2 2.950 1.882
Speedup ratio: compare with the result of `a' (greater is better)
name b
io_nonblock_noex 1.053
io_nonblock_noex2 1.567
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52541 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/bm_hash_to_proc.rb: benchmark for Hash#to_proc.
[Feature #11653]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52522 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
exist. Suggested by ko1.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52086 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/bm_require_thread.rb: new benchmark for conflicting
require vs thread. like [Bug #11559]
* prepare_require.rb: new file for preparing above tests.
* prepare_require.rb: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52083 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* string.c (rb_str_resurrect): fix resurrection of short enough to
be embedded but not embedded string.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52073 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
* benchmark/bm_vm3_gc.rb: remove unnecessary shebang line.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51973 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51969 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51968 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|