* [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).