dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH] io.c (io_fwrite): temporarily freeze string when writing
@ 2016-12-31  0:58 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2016-12-31  0:58 UTC (permalink / raw)
  To: spew

This avoids garbage from IO#write for [Bug #13085].
Memory usage from benchmark/bm_io_copy_stream_write.rb
is reduced greatly:

  target 0: a (ruby 2.5.0dev (2016-12-30 trunk 57236) [x86_64-linux])
  target 1: b (ruby 2.5.0dev (2016-12-30) [x86_64-linux])

  Memory usage (last size) (B)
  name	a	b
  io_copy_stream_write	82235392.000	6651904.000

  Memory consuming ratio (size) with the result of `a' (greater is better)
  name	b
  io_copy_stream_write	12.363

There is also a speedup in execution time:

  Execution time (sec)
  name	a	b
  io_copy_stream_write	0.380	0.143

  Speedup ratio: compare with the result of `a' (greater is better)
  name	b
  io_copy_stream_write	2.651

Caveat, there is one potential race condition:

If another thread calls String#freeze on the string we are
currently writing; we will blindly unfreeze it during
fwrite_unfreeze from ensure.  However, I do not expect this to
be a real-world case.

Ideally, Ruby should have a way of detecting threads which
are not visible to other threads.
---
 io.c | 43 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/io.c b/io.c
index 1074689..77bcbac 100644
--- a/io.c
+++ b/io.c
@@ -1419,6 +1419,37 @@ do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
     return str;
 }
 
+struct fwrite_tmp_freeze {
+    VALUE str;
+    union {
+	rb_io_t *fptr;
+	long written;
+    } as;
+    int nosync;
+};
+
+static VALUE
+fwrite_freeze(VALUE p)
+{
+    struct fwrite_tmp_freeze *x = (struct fwrite_tmp_freeze *)p;
+    const char *ptr;
+    long len;
+
+    OBJ_FREEZE_RAW(x->str);
+    RSTRING_GETMEM(x->str, ptr, len);
+    x->as.written = io_binwrite(x->str, ptr, len, x->as.fptr, x->nosync);
+
+    return Qfalse;
+}
+
+static VALUE
+fwrite_unfreeze(VALUE str)
+{
+    FL_UNSET_RAW(str, FL_FREEZE);
+
+    return Qfalse;
+}
+
 static long
 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
 {
@@ -1432,8 +1463,16 @@ 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);
+    else if (!OBJ_FROZEN_RAW(str)) {
+	struct fwrite_tmp_freeze x;
+
+	x.str = str;
+	x.as.fptr = fptr;
+	x.nosync = nosync;
+	rb_ensure(fwrite_freeze, (VALUE)&x, fwrite_unfreeze, str);
+
+	return x.as.written;
+    }
 
     return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str),
 		       fptr, nosync);
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2016-12-31  0:58 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-31  0:58 [PATCH] io.c (io_fwrite): temporarily freeze string when writing Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).