mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	io.c: recycle garbage on write
* string.c (STR_IS_SHARED_M): new flag to mark shared mulitple times (STR_SET_SHARED): set STR_IS_SHARED_M (rb_str_tmp_frozen_acquire, rb_str_tmp_frozen_release): new functions (str_new_frozen): set/unset STR_IS_SHARED_M as appropriate * internal.h: declare new functions * io.c (fwrite_arg, fwrite_do, fwrite_end): new (io_fwrite): use new functions Introduce rb_str_tmp_frozen_acquire and rb_str_tmp_frozen_release to manage a hidden, frozen string. Reuse one bit of the embed length for shared strings as STR_IS_SHARED_M to indicate a string has been shared multiple times. In the common case, the string is only shared once so the object slot can be reclaimed immediately. minimum results in each 3 measurements. (time and size) Execution time (sec) name trunk built io_copy_stream_write 0.682 0.254 io_copy_stream_write_socket 1.225 0.751 Speedup ratio: compare with the result of `trunk' (greater is better) name built io_copy_stream_write 2.680 io_copy_stream_write_socket 1.630 Memory usage (last size) (B) name trunk built io_copy_stream_write 95436800.000 6512640.000 io_copy_stream_write_socket 117628928.000 7127040.000 Memory consuming ratio (size) with the result of `trunk' (greater is better) name built io_copy_stream_write 14.654 io_copy_stream_write_socket 16.505 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57469 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									886e8f75ca
								
							
						
					
					
						commit
						9c4ba969a5
					
				
					 3 changed files with 85 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -1475,6 +1475,8 @@ VALUE rb_id_quote_unprintable(ID);
 | 
			
		|||
char *rb_str_fill_terminator(VALUE str, const int termlen);
 | 
			
		||||
void rb_str_change_terminator_length(VALUE str, const int oldtermlen, const int termlen);
 | 
			
		||||
VALUE rb_str_locktmp_ensure(VALUE str, VALUE (*func)(VALUE), VALUE arg);
 | 
			
		||||
VALUE rb_str_tmp_frozen_acquire(VALUE str);
 | 
			
		||||
void rb_str_tmp_frozen_release(VALUE str, VALUE tmp);
 | 
			
		||||
VALUE rb_str_chomp_string(VALUE str, VALUE chomp);
 | 
			
		||||
#ifdef RUBY_ENCODING_H
 | 
			
		||||
VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										40
									
								
								io.c
									
										
									
									
									
								
							
							
						
						
									
										40
									
								
								io.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1419,10 +1419,40 @@ do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
 | 
			
		|||
    return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct fwrite_arg {
 | 
			
		||||
    VALUE orig;
 | 
			
		||||
    VALUE tmp;
 | 
			
		||||
    rb_io_t *fptr;
 | 
			
		||||
    int nosync;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
fwrite_do(VALUE arg)
 | 
			
		||||
{
 | 
			
		||||
    struct fwrite_arg *fa = (struct fwrite_arg *)arg;
 | 
			
		||||
    const char *ptr;
 | 
			
		||||
    long len;
 | 
			
		||||
 | 
			
		||||
    RSTRING_GETMEM(fa->tmp, ptr, len);
 | 
			
		||||
 | 
			
		||||
    return (VALUE)io_binwrite(fa->tmp, ptr, len, fa->fptr, fa->nosync);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
fwrite_end(VALUE arg)
 | 
			
		||||
{
 | 
			
		||||
    struct fwrite_arg *fa = (struct fwrite_arg *)arg;
 | 
			
		||||
 | 
			
		||||
    rb_str_tmp_frozen_release(fa->orig, fa->tmp);
 | 
			
		||||
 | 
			
		||||
    return Qfalse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long
 | 
			
		||||
io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
 | 
			
		||||
{
 | 
			
		||||
    int converted = 0;
 | 
			
		||||
    struct fwrite_arg fa;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    if (fptr->mode & FMODE_TTY) {
 | 
			
		||||
	long len = rb_w32_write_console(str, fptr->fd);
 | 
			
		||||
| 
						 | 
				
			
			@ -1432,11 +1462,13 @@ io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
 | 
			
		|||
    str = do_writeconv(str, fptr, &converted);
 | 
			
		||||
    if (converted)
 | 
			
		||||
	OBJ_FREEZE(str);
 | 
			
		||||
    else
 | 
			
		||||
	str = rb_str_new_frozen(str);
 | 
			
		||||
 | 
			
		||||
    return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str),
 | 
			
		||||
		       fptr, nosync);
 | 
			
		||||
    fa.orig = str;
 | 
			
		||||
    fa.tmp = rb_str_tmp_frozen_acquire(str);
 | 
			
		||||
    fa.fptr = fptr;
 | 
			
		||||
    fa.nosync = nosync;
 | 
			
		||||
 | 
			
		||||
    return (long)rb_ensure(fwrite_do, (VALUE)&fa, fwrite_end, (VALUE)&fa);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								string.c
									
										
									
									
									
								
							
							
						
						
									
										47
									
								
								string.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -70,6 +70,7 @@ VALUE rb_cSymbol;
 | 
			
		|||
 * 1:     RSTRING_NOEMBED
 | 
			
		||||
 * 2:     STR_SHARED (== ELTS_SHARED)
 | 
			
		||||
 * 2-6:   RSTRING_EMBED_LEN (5 bits == 32)
 | 
			
		||||
 * 6:     STR_IS_SHARED_M (shared, when RSTRING_NOEMBED==1 && klass==0)
 | 
			
		||||
 * 7:     STR_TMPLOCK
 | 
			
		||||
 * 8-9:   ENC_CODERANGE (2 bits)
 | 
			
		||||
 * 10-16: ENCODING (7 bits == 128)
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +80,7 @@ VALUE rb_cSymbol;
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
#define RUBY_MAX_CHAR_LEN 16
 | 
			
		||||
#define STR_IS_SHARED_M FL_USER6
 | 
			
		||||
#define STR_TMPLOCK FL_USER7
 | 
			
		||||
#define STR_NOFREE FL_USER18
 | 
			
		||||
#define STR_FAKESTR FL_USER19
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +152,8 @@ VALUE rb_cSymbol;
 | 
			
		|||
    if (!FL_TEST(str, STR_FAKESTR)) { \
 | 
			
		||||
	RB_OBJ_WRITE((str), &RSTRING(str)->as.heap.aux.shared, (shared_str)); \
 | 
			
		||||
	FL_SET((str), STR_SHARED); \
 | 
			
		||||
	if (RBASIC_CLASS((shared_str)) == 0) /* for CoW-friendliness */ \
 | 
			
		||||
	    FL_SET_RAW((shared_str), STR_IS_SHARED_M); \
 | 
			
		||||
    } \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1127,6 +1131,45 @@ rb_str_new_frozen(VALUE orig)
 | 
			
		|||
    return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VALUE
 | 
			
		||||
rb_str_tmp_frozen_acquire(VALUE orig)
 | 
			
		||||
{
 | 
			
		||||
    VALUE tmp;
 | 
			
		||||
 | 
			
		||||
    if (OBJ_FROZEN_RAW(orig)) return orig;
 | 
			
		||||
 | 
			
		||||
    tmp = str_new_frozen(0, orig);
 | 
			
		||||
    OBJ_INFECT(tmp, orig);
 | 
			
		||||
 | 
			
		||||
    return tmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
rb_str_tmp_frozen_release(VALUE orig, VALUE tmp)
 | 
			
		||||
{
 | 
			
		||||
    if (RBASIC_CLASS(tmp) != 0)
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
    if (FL_TEST_RAW(orig, STR_SHARED) &&
 | 
			
		||||
	    !FL_TEST_RAW(orig, STR_TMPLOCK|RUBY_FL_FREEZE)) {
 | 
			
		||||
	VALUE shared = RSTRING(orig)->as.heap.aux.shared;
 | 
			
		||||
 | 
			
		||||
	if (shared == tmp && !FL_TEST_RAW(tmp, STR_IS_SHARED_M)) {
 | 
			
		||||
	    FL_UNSET_RAW(orig, STR_SHARED);
 | 
			
		||||
	    assert(RSTRING(orig)->as.heap.ptr == RSTRING(tmp)->as.heap.ptr);
 | 
			
		||||
	    assert(RSTRING(orig)->as.heap.len == RSTRING(tmp)->as.heap.len);
 | 
			
		||||
	    RSTRING(orig)->as.heap.aux.capa = RSTRING(tmp)->as.heap.aux.capa;
 | 
			
		||||
	    RBASIC(orig)->flags |= RBASIC(tmp)->flags & STR_NOFREE;
 | 
			
		||||
	    assert(OBJ_FROZEN_RAW(tmp));
 | 
			
		||||
	    rb_gc_force_recycle(tmp);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
    else if (STR_EMBED_P(tmp)) {
 | 
			
		||||
	assert(OBJ_FROZEN_RAW(tmp));
 | 
			
		||||
	rb_gc_force_recycle(tmp);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
str_new_frozen(VALUE klass, VALUE orig)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1152,6 +1195,8 @@ str_new_frozen(VALUE klass, VALUE orig)
 | 
			
		|||
		RSTRING(str)->as.heap.len -= ofs + rest;
 | 
			
		||||
	    }
 | 
			
		||||
	    else {
 | 
			
		||||
		if (RBASIC_CLASS(shared) == 0)
 | 
			
		||||
		    FL_SET_RAW(shared, STR_IS_SHARED_M);
 | 
			
		||||
		return shared;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1171,6 +1216,8 @@ str_new_frozen(VALUE klass, VALUE orig)
 | 
			
		|||
	    RBASIC(str)->flags |= RBASIC(orig)->flags & STR_NOFREE;
 | 
			
		||||
	    RBASIC(orig)->flags &= ~STR_NOFREE;
 | 
			
		||||
	    STR_SET_SHARED(orig, str);
 | 
			
		||||
	    if (klass == 0)
 | 
			
		||||
		FL_UNSET_RAW(str, STR_IS_SHARED_M);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue