public
Created

Benchmark require #7158

  • Download Gist
0000-bench_require_empty.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#!/usr/bin/env ruby
require "benchmark"
 
in_dir = File.expand_path('input/empty_files', File.dirname(__FILE__))
 
200.times do |i|
$LOAD_PATH.push File.expand_path(i.to_s)
end
$LOAD_PATH.push in_dir
 
Benchmark.bm do |x|
x.report do
1000.times do |i|
require "empty#{i}"
end
end
end
 
puts "LOAD_PATH SIZE = #{$:.size}"
puts "LOADED_FEATURES SIZE = #{$".size}"
0000-bench_require_empty_relative.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#!/usr/bin/env ruby
require "benchmark"
 
in_dir = File.expand_path('input/empty_files', File.dirname(__FILE__))
 
200.times do |i|
$LOAD_PATH.push i.to_s
end
$LOAD_PATH.push in_dir
 
Benchmark.bm do |x|
x.report do
1000.times do |i|
require "empty#{i}"
end
end
end
 
puts "LOAD_PATH SIZE = #{$:.size}"
puts "LOADED_FEATURES SIZE = #{$".size}"
0000-result.md
Markdown

Best of 5 trials

LOAD_PATH SIZE = 209

LOADED_FEATURES SIZE = 1010

# trunk
ruby 2.0.0dev (2012-10-27 trunk 37341) [x86_64-darwin12.2.0]
       user     system      total        real
   0.620000   0.390000   1.010000 (  1.022564)

# Greg's patch
ruby 2.0.0dev (2012-10-27 trunk 37341) [x86_64-darwin12.2.0]
       user     system      total        real
   0.380000   0.350000   0.730000 (  0.729237)

# Greg's patch + my patch 1 and 2
ruby 2.0.0dev (2012-10-27 trunk 37341) [x86_64-darwin12.2.0]
       user     system      total        real
   0.380000   0.350000   0.730000 (  0.736977)

# Greg's patch + my patch 1, 2 and 3
ruby 2.0.0dev (2012-10-27 trunk 37341) [x86_64-darwin12.2.0]
       user     system      total        real
   0.380000   0.350000   0.730000 (  0.727115)

bench

0000-result2.md
Markdown

patched contains all my patches.

# trunk bench_require_empty.rb
ruby 2.0.0dev (2012-11-01 trunk 37415) [x86_64-darwin12.2.0]
       user     system      total        real
   0.610000   0.390000   1.000000 (  1.002916)
LOAD_PATH SIZE = 209 
LOADED_FEATURES SIZE = 1010

# patched bench_require_empty.rb
ruby 2.0.0dev (2012-11-01 trunk 37415) [x86_64-darwin12.2.0]
       user     system      total        real
   0.390000   0.350000   0.740000 (  0.735971)
LOAD_PATH SIZE = 209 
LOADED_FEATURES SIZE = 1010


# trunk bench_require_empty_relative.rb
ruby 2.0.0dev (2012-11-01 trunk 37415) [x86_64-darwin12.2.0]
       user     system      total        real
   1.600000   2.470000   4.070000 (  4.068619)
LOAD_PATH SIZE = 209 
LOADED_FEATURES SIZE = 1010

# patched bench_require_empty_relative.rb
ruby 2.0.0dev (2012-11-01 trunk 37415) [x86_64-darwin12.2.0]
       user     system      total        real
   0.420000   0.360000   0.780000 (  0.787250)
LOAD_PATH SIZE = 209 
LOADED_FEATURES SIZE = 1010
0001-Expand-relative-load-path-always.patch
Diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
From 1245d796305be72b80a8c623faf3195ee92fb1f3 Mon Sep 17 00:00:00 2001
From: Hiroshi Shirosaki <h.shirosaki@gmail.com>
Date: Sat, 27 Oct 2012 18:39:01 +0900
Subject: [PATCH 1/3] Expand relative load path always
 
* load.c (rb_construct_expanded_load_path): add a option for expanding
only relative load paths.
* load.c (rb_get_expanded_load_path): expand relative load path always.
---
load.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
 
diff --git a/load.c b/load.c
index dfea0ef..b3e316c 100644
--- a/load.c
+++ b/load.c
@@ -34,10 +34,11 @@ rb_get_load_path(void)
}
static void
-rb_construct_expanded_load_path(void)
+rb_construct_expanded_load_path(int only_relative)
{
rb_vm_t *vm = GET_VM();
VALUE load_path = vm->load_path;
+ VALUE expanded_load_path = vm->expanded_load_path;
VALUE ary;
long i;
@@ -46,6 +47,10 @@ rb_construct_expanded_load_path(void)
VALUE path, as_str, expanded_path;
as_str = path = RARRAY_PTR(load_path)[i];
StringValue(as_str);
+ if (only_relative && rb_is_absolute_path(StringValuePtr(as_str))) {
+ rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
+ continue;
+ }
if (as_str != path)
rb_ary_store(load_path, i, as_str);
rb_str_freeze(as_str);
@@ -63,8 +68,12 @@ rb_get_expanded_load_path(void)
{
rb_vm_t *vm = GET_VM();
if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
- /* The load path was modified. Rebuild the expanded load path. */
- rb_construct_expanded_load_path();
+ /* The load path was modified. Rebuild the expanded load path. */
+ rb_construct_expanded_load_path(0);
+ }
+ else {
+ /* Expand only relative load path. */
+ rb_construct_expanded_load_path(1);
}
return vm->expanded_load_path;
}
--
1.7.10.2 (Apple Git-33)
0002-Cache-expanded-relative-load-path.patch
Diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
From f0a7f264e53b64b0493c8de3b2d592bd5003bc0c Mon Sep 17 00:00:00 2001
From: Hiroshi Shirosaki <h.shirosaki@gmail.com>
Date: Sat, 27 Oct 2012 20:50:41 +0900
Subject: [PATCH 2/3] Cache expanded relative load path
 
* load.c (rb_construct_expanded_load_path): check relative path.
We call getcwd() only if load path has relative path, to avoid getcwd() failure.
 
* load.c (load_path_getcwd): add a function to get current working directory.
 
* load.c (rb_get_expanded_load_path): check if current working directory is changed
and rebuild expanded load path cache.
 
* load.c (Init_load): initialize vm->load_path_cwd.
 
* test/ruby/test_require.rb (TestRequire#test_require_): add a test for require
when changeing current working directory.
 
* vm.c (rb_vm_mark): mark vm->load_path_cwd.
 
* vm_core.h (rb_vm_struct): add vm->load_path_cwd to store current working directory
to check if expanded load path cache is invalid.
---
load.c | 33 +++++++++++++++++++++++++++------
test/ruby/test_require.rb | 22 ++++++++++++++++++++++
vm.c | 1 +
vm_core.h | 1 +
4 files changed, 51 insertions(+), 6 deletions(-)
 
diff --git a/load.c b/load.c
index b3e316c..53dc58c 100644
--- a/load.c
+++ b/load.c
@@ -34,7 +34,7 @@ rb_get_load_path(void)
}
static void
-rb_construct_expanded_load_path(int only_relative)
+rb_construct_expanded_load_path(int only_relative, int *has_relative)
{
rb_vm_t *vm = GET_VM();
VALUE load_path = vm->load_path;
@@ -51,6 +51,8 @@ rb_construct_expanded_load_path(int only_relative)
rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
continue;
}
+ if (!*has_relative && !rb_is_absolute_path(StringValuePtr(as_str)))
+ *has_relative = 1;
if (as_str != path)
rb_ary_store(load_path, i, as_str);
rb_str_freeze(as_str);
@@ -64,16 +66,34 @@ rb_construct_expanded_load_path(int only_relative)
}
static VALUE
+load_path_getcwd(void)
+{
+ char *cwd = my_getcwd();
+ VALUE cwd_str = rb_filesystem_str_new_cstr(cwd);
+ xfree(cwd);
+ return cwd_str;
+}
+
+static VALUE
rb_get_expanded_load_path(void)
{
rb_vm_t *vm = GET_VM();
+
if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
/* The load path was modified. Rebuild the expanded load path. */
- rb_construct_expanded_load_path(0);
- }
- else {
- /* Expand only relative load path. */
- rb_construct_expanded_load_path(1);
+ int has_relative = 0;
+ rb_construct_expanded_load_path(0, &has_relative);
+ vm->load_path_cwd = has_relative ? load_path_getcwd() : 0;
+ }
+ else if (vm->load_path_cwd) {
+ VALUE cwd = load_path_getcwd();
+ if (!rb_str_equal(vm->load_path_cwd, cwd)) {
+ /* Current working directory or filesystem encoding was changed.
+ Expand relative load path again. */
+ int has_relative = 1;
+ vm->load_path_cwd = cwd;
+ rb_construct_expanded_load_path(1, &has_relative);
+ }
}
return vm->expanded_load_path;
}
@@ -971,6 +991,7 @@ Init_load()
vm->load_path = rb_ary_new();
vm->expanded_load_path = rb_ary_new();
vm->load_path_snapshot = rb_ary_new();
+ vm->load_path_cwd = 0;
rb_define_virtual_variable("$\"", get_loaded_features, 0);
rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index a7c75d0..8c72571 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -435,4 +435,26 @@ class TestRequire < Test::Unit::TestCase
$:.replace(loadpath)
$".replace(features)
end
+
+ def test_require_changed_current_dir
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ Dir.mkdir("a")
+ Dir.mkdir("b")
+ open(File.join("a", "foo.rb"), "w") {}
+ open(File.join("b", "bar.rb"), "w") {|f|
+ f.puts "p :ok"
+ }
+ assert_in_out_err([], <<-INPUT, %w(:ok), [])
+ $: << "."
+ Dir.chdir("a")
+ require "foo"
+ Dir.chdir("../b")
+ p :ng unless require "bar"
+ Dir.chdir("..")
+ p :ng if require "b/bar"
+ INPUT
+ }
+ }
+ end
end
diff --git a/vm.c b/vm.c
index 9a8ebef..03cc79d 100644
--- a/vm.c
+++ b/vm.c
@@ -1508,6 +1508,7 @@ rb_vm_mark(void *ptr)
RUBY_MARK_UNLESS_NULL(vm->mark_object_ary);
RUBY_MARK_UNLESS_NULL(vm->load_path);
RUBY_MARK_UNLESS_NULL(vm->load_path_snapshot);
+ RUBY_MARK_UNLESS_NULL(vm->load_path_cwd);
RUBY_MARK_UNLESS_NULL(vm->expanded_load_path);
RUBY_MARK_UNLESS_NULL(vm->loaded_features);
RUBY_MARK_UNLESS_NULL(vm->loaded_features_snapshot);
diff --git a/vm_core.h b/vm_core.h
index b315fe4..3874231 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -355,6 +355,7 @@ typedef struct rb_vm_struct {
VALUE top_self;
VALUE load_path;
VALUE load_path_snapshot;
+ VALUE load_path_cwd;
VALUE expanded_load_path;
VALUE loaded_features;
VALUE loaded_features_snapshot;
--
1.7.10.2 (Apple Git-33)
0003-Use-rb_get_expanded_load_path-in-find-file.patch
Diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
From 6522cc9cf8b8ac918e09705342f5ad9d5a5c31f6 Mon Sep 17 00:00:00 2001
From: Hiroshi Shirosaki <h.shirosaki@gmail.com>
Date: Sat, 27 Oct 2012 21:46:59 +0900
Subject: [PATCH 3/3] Use rb_get_expanded_load_path() in find file
 
* file.c (rb_find_file_ext_safe): use rb_get_expanded_load_path() to reduce
expand cost.
* file.c (rb_find_file_safe): ditto.
* internal.h (rb_get_expanded_load_path): add a declaration.
* load.c (rb_get_expanded_load_path): make it accesible from other source
files.
---
file.c | 4 ++--
internal.h | 1 +
load.c | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
 
diff --git a/file.c b/file.c
index 5951d7b..7b22dcf 100644
--- a/file.c
+++ b/file.c
@@ -5258,7 +5258,7 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
}
- RB_GC_GUARD(load_path) = rb_get_load_path();
+ RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
if (!load_path) return 0;
fname = rb_str_dup(*filep);
@@ -5323,7 +5323,7 @@ rb_find_file_safe(VALUE path, int safe_level)
rb_raise(rb_eSecurityError, "loading from non-absolute path %s", f);
}
- RB_GC_GUARD(load_path) = rb_get_load_path();
+ RB_GC_GUARD(load_path) = rb_get_expanded_load_path();
if (load_path) {
long i;
diff --git a/internal.h b/internal.h
index e538de4..104539b 100644
--- a/internal.h
+++ b/internal.h
@@ -133,6 +133,7 @@ VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
/* load.c */
VALUE rb_get_load_path(void);
+VALUE rb_get_expanded_load_path(void);
NORETURN(void rb_load_fail(VALUE, const char*));
/* math.c */
diff --git a/load.c b/load.c
index 53dc58c..22d3532 100644
--- a/load.c
+++ b/load.c
@@ -74,7 +74,7 @@ load_path_getcwd(void)
return cwd_str;
}
-static VALUE
+VALUE
rb_get_expanded_load_path(void)
{
rb_vm_t *vm = GET_VM();
--
1.7.10.2 (Apple Git-33)
0004-Fix-compatibility-of-require.patch
Diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
From f21777810c1dac501749218fe89d567dff39369b Mon Sep 17 00:00:00 2001
From: Hiroshi Shirosaki <h.shirosaki@gmail.com>
Date: Mon, 29 Oct 2012 23:22:01 +0900
Subject: [PATCH] Fix compatibility of require
 
* load.c (rb_construct_expanded_load_path): don't replace $LOAD_PATH.
We just freeze contents of $LOAD_PATH. We add an argument for home
directory expansion.
 
* load.c (rb_get_expanded_load_path): expand path which starts with ~
always for compatibility.
 
* test/ruby/test_require.rb (TestRequire): add tests for require
compatibility.
- not modify load path contents
- require when ENV['HOME'] is changed
---
load.c | 26 +++++++++++++++++---------
test/ruby/test_require.rb | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+), 9 deletions(-)
 
diff --git a/load.c b/load.c
index 22d3532..9f707a7 100644
--- a/load.c
+++ b/load.c
@@ -34,7 +34,7 @@ rb_get_load_path(void)
}
static void
-rb_construct_expanded_load_path(int only_relative, int *has_relative)
+rb_construct_expanded_load_path(int only_tilde, int only_relative, int *has_relative)
{
rb_vm_t *vm = GET_VM();
VALUE load_path = vm->load_path;
@@ -45,17 +45,21 @@ rb_construct_expanded_load_path(int only_relative, int *has_relative)
ary = rb_ary_new2(RARRAY_LEN(load_path));
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
VALUE path, as_str, expanded_path;
+ char *as_cstr;
as_str = path = RARRAY_PTR(load_path)[i];
StringValue(as_str);
- if (only_relative && rb_is_absolute_path(StringValuePtr(as_str))) {
+ as_cstr = StringValuePtr(as_str);
+ if (only_relative && rb_is_absolute_path(as_cstr)) {
rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
continue;
}
- if (!*has_relative && !rb_is_absolute_path(StringValuePtr(as_str)))
+ else if (only_tilde && (!as_cstr[0] || as_cstr[0] != '~')) {
+ rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
+ continue;
+ }
+ if (!*has_relative && !rb_is_absolute_path(as_cstr))
*has_relative = 1;
- if (as_str != path)
- rb_ary_store(load_path, i, as_str);
- rb_str_freeze(as_str);
+ rb_obj_freeze(path);
expanded_path = rb_file_expand_path_fast(as_str, Qnil);
rb_str_freeze(expanded_path);
rb_ary_push(ary, expanded_path);
@@ -82,17 +86,21 @@ rb_get_expanded_load_path(void)
if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
/* The load path was modified. Rebuild the expanded load path. */
int has_relative = 0;
- rb_construct_expanded_load_path(0, &has_relative);
+ rb_construct_expanded_load_path(0, 0, &has_relative);
vm->load_path_cwd = has_relative ? load_path_getcwd() : 0;
}
else if (vm->load_path_cwd) {
VALUE cwd = load_path_getcwd();
+ int has_relative = 1;
if (!rb_str_equal(vm->load_path_cwd, cwd)) {
/* Current working directory or filesystem encoding was changed.
Expand relative load path again. */
- int has_relative = 1;
vm->load_path_cwd = cwd;
- rb_construct_expanded_load_path(1, &has_relative);
+ rb_construct_expanded_load_path(0, 1, &has_relative);
+ }
+ else {
+ /* Expand only tilde (User HOME) */
+ rb_construct_expanded_load_path(1, 0, &has_relative);
}
}
return vm->expanded_load_path;
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index 8c72571..ec7f2aa 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -457,4 +457,42 @@ class TestRequire < Test::Unit::TestCase
}
}
end
+
+ def test_require_unmodified_lood_path
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ assert_in_out_err([], <<-INPUT, %w(:ok), [])
+ $: << "#{tmp}"
+ a = 123
+ $: << a
+ begin
+ require "foo"
+ rescue TypeError
+ end
+ p :ok if $:.pop == a
+ INPUT
+ }
+ }
+ end
+
+ def test_require_changed_home
+ home = ENV['HOME']
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ open("foo.rb", "w") {}
+ Dir.mkdir("a")
+ open(File.join("a", "bar.rb"), "w") {}
+ assert_in_out_err([], <<-INPUT, %w(:ok), [])
+ $: << '~'
+ ENV['HOME'] = "#{tmp}"
+ require "foo"
+ ENV['HOME'] = "#{tmp}/a"
+ p :ok if require "bar"
+ INPUT
+ }
+ }
+ ensure
+ ENV['HOME'] = home
+ end
end
--
1.7.10.2 (Apple Git-33)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.