ruby-changes:47972
From: normal <ko1@a...>
Date: Mon, 2 Oct 2017 06:19:29 +0900 (JST)
Subject: [ruby-changes:47972] normal:r60088 (trunk): File#rename releases GVL
normal 2017-10-02 06:19:24 +0900 (Mon, 02 Oct 2017) New Revision: 60088 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60088 Log: File#rename releases GVL 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 Added files: trunk/benchmark/bm_file_rename.rb Modified files: trunk/file.c Index: benchmark/bm_file_rename.rb =================================================================== --- benchmark/bm_file_rename.rb (nonexistent) +++ benchmark/bm_file_rename.rb (revision 60088) @@ -0,0 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/bm_file_rename.rb#L1 +# rename file +require 'tempfile' + +max = 100_000 +tmp = [ Tempfile.new('rename-a'), Tempfile.new('rename-b') ] +a, b = tmp.map { |x| x.path } +max.times do + File.rename(a, b) + File.rename(b, a) +end +tmp.each { |t| t.close! } Index: file.c =================================================================== --- file.c (revision 60087) +++ file.c (revision 60088) @@ -2873,6 +2873,19 @@ rb_file_s_unlink(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/file.c#L2873 return apply2files(unlink_internal, argc, argv, 0); } +struct rename_args { + const char *src; + const char *dst; +}; + +static void * +no_gvl_rename(void *ptr) +{ + struct rename_args *ra = ptr; + + return (void *)(VALUE)rename(ra->src, ra->dst); +} + /* * call-seq: * File.rename(old_name, new_name) -> 0 @@ -2886,19 +2899,20 @@ rb_file_s_unlink(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/file.c#L2899 static VALUE rb_file_s_rename(VALUE klass, VALUE from, VALUE to) { - const char *src, *dst; + struct rename_args ra; VALUE f, t; FilePathValue(from); FilePathValue(to); f = rb_str_encode_ospath(from); t = rb_str_encode_ospath(to); - src = StringValueCStr(f); - dst = StringValueCStr(t); + ra.src = StringValueCStr(f); + ra.dst = StringValueCStr(t); #if defined __CYGWIN__ errno = 0; #endif - if (rename(src, dst) < 0) { + if ((int)(VALUE)rb_thread_call_without_gvl(no_gvl_rename, &ra, + RUBY_UBF_IO, 0) < 0) { int e = errno; #if defined DOSISH switch (e) { -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/