speed improvements during ruby_init
From:
Jamie Herre <jfh@...>
Date:
2002-07-14 00:39:32 UTC
List:
ruby-core #227
Hi,
Messing around with gprof after being agitated by a recent thread
regarding ruby IO, I found that the init phase is taking longer than
necessary due to the following:
1) rb_clear_cache_by_id( ) is called many times during ruby init and
parsing. each call entails 0x800 comparisons. Proposed solution is to
disable the method cache until ruby_run( ).
2) Although it may be necessary to rb_gc( ) after load_file( ), it is
not always so for small scripts. Proposed solution is to trigger gc
based on malloc_memories.
These two changes can make short scripts run noticeably faster:
$ time ../ruby172/ruby hello_world.rb > /dev/null
real 0m0.028s
user 0m0.023s
sys 0m0.000s
$ time ../ruby_dev/ruby hello_world.rb > /dev/null
real 0m0.011s
user 0m0.008s
sys 0m0.000s
$ time ../ruby172/ruby lib/cgi.rb
real 0m0.061s
user 0m0.055s
sys 0m0.000s
$ time ../ruby_dev/ruby lib/cgi.rb
real 0m0.034s
user 0m0.031s
sys 0m0.000s
-J
Would anyone care to check this? Is this adding extraneous overhead to
the method cache?
Jamie Herre
Gettys Group Software, Inc.
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.303
diff -u -r1.303 eval.c
--- eval.c 2002/06/24 07:20:42 1.303
+++ eval.c 2002/07/14 00:10:18
@@ -189,6 +189,8 @@
};
static struct cache_entry cache[CACHE_SIZE];
+static int cache_enabled = 0;
+/* must call rb_clear_cache when set cache_enabled = 1 */
void
rb_clear_cache()
@@ -246,7 +248,7 @@
rb_raise(rb_eSecurityError, "Insecure: can't define method");
}
if (OBJ_FROZEN(klass)) rb_error_frozen("class/module");
- rb_clear_cache_by_id(mid);
+ if (cache_enabled) rb_clear_cache_by_id(mid);
body = NEW_METHOD(node, noex);
st_insert(RCLASS(klass)->m_tbl, mid, body);
}
@@ -280,6 +282,7 @@
NODE * volatile body;
struct cache_entry *ent;
+ /* purposely ignoring cache_enabled here for simplicity */
if ((body = search_method(klass, id, &origin)) == 0 ||
!body->nd_body) {
/* store empty info in cache */
ent = cache + EXPR1(klass, id);
@@ -333,7 +336,7 @@
rb_name_error(mid, "method `%s' not defined in %s",
rb_id2name(mid), rb_class2name(klass));
}
- rb_clear_cache_by_id(mid);
+ if (cache_enabled) rb_clear_cache_by_id(mid);
if (FL_TEST(klass, FL_SINGLETON)) {
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
ID2SYM(mid));
}
@@ -440,7 +443,7 @@
/* is it in the method cache? */
ent = cache + EXPR1(klass, id);
- if (ent->mid == id && ent->klass == klass) {
+ if (ent->mid == id && ent->klass == klass && cache_enabled) {
if (ex && (ent->noex & NOEX_PRIVATE))
return Qfalse;
if (!ent->method) return Qfalse;
@@ -1228,6 +1231,10 @@
if (ruby_nerrs > 0) exit(ruby_nerrs);
+ /* enable method caching */
+ rb_clear_cache();
+ cache_enabled = 1;
+
Init_stack((void*)&tmp);
PUSH_TAG(PROT_NONE);
PUSH_ITER(ITER_NOT);
@@ -1684,7 +1691,7 @@
body = body->nd_head;
}
- rb_clear_cache_by_id(name);
+ if (cache_enabled) rb_clear_cache_by_id(name);
st_insert(RCLASS(klass)->m_tbl, name,
NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
if (FL_TEST(klass, FL_SINGLETON)) {
@@ -4698,7 +4705,7 @@
}
/* is it in the method cache? */
ent = cache + EXPR1(klass, mid);
- if (ent->mid == mid && ent->klass == klass) {
+ if (ent->mid == mid && ent->klass == klass && cache_enabled) {
if (!ent->method)
return rb_undefined(recv, mid, argc, argv,
scope==2?CSTAT_VCALL:0);
klass = ent->origin;
@@ -5650,7 +5657,7 @@
for (i=0; i<argc; i++) {
rb_export_method(self, rb_to_id(argv[i]), ex);
}
- rb_clear_cache_by_class(self);
+ if (cache_enabled) rb_clear_cache_by_class(self);
}
static VALUE
Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.94
diff -u -r1.94 gc.c
--- gc.c 2002/05/14 06:22:26 1.94
+++ gc.c 2002/07/14 00:10:19
@@ -1199,6 +1199,13 @@
gc_sweep();
}
+void
+rb_gc_ifneeded()
+{
+ /* This is just an arbitrary guess for the value to cause a real gc */
+ if (malloc_memories > (GC_MALLOC_LIMIT/2)) rb_gc();
+}
+
VALUE
rb_gc_start()
{
Index: ruby.c
===================================================================
RCS file: /src/ruby/ruby.c,v
retrieving revision 1.62
diff -u -r1.62 ruby.c
--- ruby.c 2002/05/29 05:20:33 1.62
+++ ruby.c 2002/07/14 00:10:20
@@ -854,7 +854,7 @@
else if (f != rb_stdin) {
rb_io_close(f);
}
- rb_gc();
+ rb_gc_ifneeded();
}
void