From 9c4ba969a567450bee08211cc3ed1d2fa4655831 Mon Sep 17 00:00:00 2001 From: normal Date: Mon, 30 Jan 2017 20:40:18 +0000 Subject: 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 --- string.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'string.c') diff --git a/string.c b/string.c index b5aae67e81..a65a423b8f 100644 --- a/string.c +++ b/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); } } -- cgit v1.2.3