[前][次][番号順一覧][スレッド一覧]

ruby-changes:40254

From: normal <ko1@a...>
Date: Thu, 29 Oct 2015 10:14:57 +0900 (JST)
Subject: [ruby-changes:40254] normal:r52335 (trunk): variable.c: reduce heap usage for autoload_data_i

normal	2015-10-29 10:14:45 +0900 (Thu, 29 Oct 2015)

  New Revision: 52335

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52335

  Log:
    variable.c: reduce heap usage for autoload_data_i
    
    For the loader (first thread which hits autoload, it is wasteful
    to have extra elements on the stack.  For the lifetime of the
    process, it is wasteful to waste 2 words for every autoload
    entry.  So this makes full use of existing stack overhead
    while reducing heap overhead for long-lived autoload_data_i
    structs.
    
    * variable.c (struct autoload_state): usable as wait-queue head
      (struct autoload_data_i): remove 2 words of overhead
      (autoload_i_mark): remove marking for thread
      (autoload_reset): adjust for struct changes
      (rb_autoload): ditto
      (rb_autoloading_value): ditto
      (rb_autoload_load): ditto
      (const_update): ditto

  Modified files:
    trunk/ChangeLog
    trunk/variable.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52334)
+++ ChangeLog	(revision 52335)
@@ -1,3 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Oct 29 10:08:33 2015  Eric Wong  <e@8...>
+
+	* variable.c (struct autoload_state): usable as wait-queue head
+	  (struct autoload_data_i): remove 2 words of overhead
+	  (autoload_i_mark): remove marking for thread
+	  (autoload_reset): adjust for struct changes
+	  (rb_autoload): ditto
+	  (rb_autoloading_value): ditto
+	  (rb_autoload_load): ditto
+	  (const_update): ditto
+
 Thu Oct 29 08:48:05 2015  Eric Wong  <e@8...>
 
 	* variable.c (struct autoload_data_i): add waitq_head
Index: variable.c
===================================================================
--- variable.c	(revision 52334)
+++ variable.c	(revision 52335)
@@ -1892,12 +1892,24 @@ autoload_data(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L1892
     return (VALUE)val;
 }
 
+/* always on stack, no need to mark */
+struct autoload_state {
+    struct autoload_data_i *ele;
+    VALUE mod;
+    VALUE result;
+    ID id;
+    VALUE thread;
+    union {
+	struct list_node node;
+	struct list_head head;
+    } waitq;
+};
+
 struct autoload_data_i {
     VALUE feature;
     int safe_level;
-    VALUE thread;
     VALUE value;
-    struct list_head waitq_head; /* links autoload_state.waitq_node */
+    struct autoload_state *state; /* points to on-stack struct */
 };
 
 static void
@@ -1905,7 +1917,6 @@ autoload_i_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/variable.c#L1917
 {
     struct autoload_data_i *p = ptr;
     rb_gc_mark(p->feature);
-    rb_gc_mark(p->thread);
     rb_gc_mark(p->value);
 }
 
@@ -1965,8 +1976,8 @@ rb_autoload(VALUE mod, ID id, const char https://github.com/ruby/ruby/blob/trunk/variable.c#L1976
     ad = TypedData_Make_Struct(0, struct autoload_data_i, &autoload_data_i_type, ele);
     ele->feature = fn;
     ele->safe_level = rb_safe_level();
-    ele->thread = Qnil;
     ele->value = Qundef;
+    ele->state = 0;
     st_insert(tbl, (st_data_t)id, (st_data_t)ad);
 }
 
@@ -2039,7 +2050,7 @@ rb_autoloading_value(VALUE mod, ID id, V https://github.com/ruby/ruby/blob/trunk/variable.c#L2050
     if (!(load = autoload_data(mod, id)) || !(ele = check_autoload_data(load))) {
 	return 0;
     }
-    if (ele->thread == rb_thread_current()) {
+    if (ele->state && ele->state->thread == rb_thread_current()) {
 	if (ele->value != Qundef) {
 	    if (value) {
 		*value = ele->value;
@@ -2079,16 +2090,6 @@ autoload_const_set(VALUE arg) https://github.com/ruby/ruby/blob/trunk/variable.c#L2090
     return 0;			/* ignored */
 }
 
-/* this is on the thread stack, not heap */
-struct autoload_state {
-    struct autoload_data_i *ele;
-    VALUE mod;
-    VALUE result;
-    ID id;
-    struct list_node waitq_node; /* links autoload_data_i.waitq_head */
-    VALUE waiting_th;
-};
-
 static VALUE
 autoload_require(VALUE arg)
 {
@@ -2107,9 +2108,9 @@ autoload_reset(VALUE arg) https://github.com/ruby/ruby/blob/trunk/variable.c#L2108
     struct autoload_state *state = (struct autoload_state *)arg;
     int need_wakeups = 0;
 
-    if (state->ele->thread == rb_thread_current()) {
+    if (state->ele->state == state) {
 	need_wakeups = 1;
-	state->ele->thread = Qnil;
+	state->ele->state = 0;
     }
 
     /* At the last, move a value defined in autoload to constant table */
@@ -2130,11 +2131,11 @@ autoload_reset(VALUE arg) https://github.com/ruby/ruby/blob/trunk/variable.c#L2131
     if (need_wakeups) {
 	struct autoload_state *cur, *nxt;
 
-	list_for_each_safe(&state->ele->waitq_head, cur, nxt, waitq_node) {
-	    VALUE th = cur->waiting_th;
+	list_for_each_safe(&state->waitq.head, cur, nxt, waitq.node) {
+	    VALUE th = cur->thread;
 
-	    cur->waiting_th = Qfalse;
-	    list_del(&cur->waitq_node);
+	    cur->thread = Qfalse;
+	    list_del(&cur->waitq.node);
 
 	    /*
 	     * cur is stored on the stack of cur->waiting_th,
@@ -2161,7 +2162,7 @@ rb_autoload_load(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2162
     src = rb_sourcefile();
     if (src && loading && strcmp(src, loading) == 0) return Qfalse;
 
-    /* set ele->thread for a marker of autoloading thread */
+    /* set ele->state for a marker of autoloading thread */
     if (!(ele = check_autoload_data(load))) {
 	return Qfalse;
     }
@@ -2169,25 +2170,25 @@ rb_autoload_load(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2170
     state.ele = ele;
     state.mod = mod;
     state.id = id;
-    if (ele->thread == Qnil) {
-	ele->thread = rb_thread_current();
+    state.thread = rb_thread_current();
+    if (!ele->state) {
+	ele->state = &state;
 
 	/*
 	 * autoload_reset will wake up any threads added to this
 	 * iff the GVL is released during autoload_require
 	 */
-	list_head_init(&ele->waitq_head);
+	list_head_init(&state.waitq.head);
     }
     else {
-	state.waiting_th = rb_thread_current();
-	list_add_tail(&ele->waitq_head, &state.waitq_node);
+	list_add_tail(&ele->state->waitq.head, &state.waitq.node);
 	/*
 	 * autoload_reset in other thread will resume us and remove us
 	 * from the waitq list
 	 */
 	do {
 	    rb_thread_sleep_deadly();
-	} while (state.waiting_th != Qfalse);
+	} while (state.thread != Qfalse);
     }
 
     /* autoload_data_i can be deleted by another thread while require */
@@ -2594,8 +2595,8 @@ const_update(st_data_t *key, st_data_t * https://github.com/ruby/ruby/blob/trunk/variable.c#L2595
 
 		load = autoload_data(klass, id);
 		/* for autoloading thread, keep the defined value to autoloading storage */
-		if (load && (ele = check_autoload_data(load)) &&
-			    (ele->thread == rb_thread_current())) {
+		if (load && (ele = check_autoload_data(load)) && ele->state &&
+			    (ele->state->thread == rb_thread_current())) {
 		    rb_clear_constant_cache();
 
 		    ele->value = val; /* autoload_i is non-WB-protected */

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]