ruby-changes:39032
From: normal <ko1@a...>
Date: Fri, 3 Jul 2015 07:23:01 +0900 (JST)
Subject: [ruby-changes:39032] normal:r51113 (trunk): delay `exception: false' checks for minor speedup
normal 2015-07-03 07:22:14 +0900 (Fri, 03 Jul 2015) New Revision: 51113 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51113 Log: delay `exception: false' checks for minor speedup Delay hash lookups until we are about to hit an exception. This gives a minor speedup ratio of 2-3% in the new bm_io_nonblock_noex benchmark as well as reducing code. * benchmark/bm_io_nonblock_noex.rb: new benchmark * ext/openssl/ossl_ssl.c (no_exception_p): new function (ossl_start_ssl): adjust for no_exception_p (ossl_ssl_connect): adjust ossl_start_ssl call (ossl_ssl_connect_nonblock): ditto (ossl_ssl_accept): ditto (ossl_ssl_accept_nonblock): ditto (ossl_ssl_read_internal): adjust for no_exception_p (ossl_ssl_write_internal): ditto (ossl_ssl_write): adjust ossl_write_internal call (ossl_ssl_write_nonblock): ditto * ext/stringio/stringio.c (strio_read_nonblock): delay exception check * io.c (no_exception_p): new function (io_getpartial): call no_exception_p (io_readpartial): adjust for io_getpartial (get_kwargs_exception): remove (io_read_nonblock): adjust for io_getpartial, check no_exception_p on EOF (io_write_nonblock): call no_exception_p (rb_io_write_nonblock): do not check `exception: false' (argf_getpartial): adjust for io_getpartial [ruby-core:69778] [Feature #11318] Added files: trunk/benchmark/bm_io_nonblock_noex.rb Modified files: trunk/ChangeLog trunk/ext/openssl/ossl_ssl.c trunk/ext/stringio/stringio.c trunk/io.c Index: ChangeLog =================================================================== --- ChangeLog (revision 51112) +++ ChangeLog (revision 51113) @@ -1,3 +1,29 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Jul 3 07:21:06 2015 Eric Wong <e@8...> + + * benchmark/bm_io_nonblock_noex.rb: new benchmark + * ext/openssl/ossl_ssl.c (no_exception_p): new function + (ossl_start_ssl): adjust for no_exception_p + (ossl_ssl_connect): adjust ossl_start_ssl call + (ossl_ssl_connect_nonblock): ditto + (ossl_ssl_accept): ditto + (ossl_ssl_accept_nonblock): ditto + (ossl_ssl_read_internal): adjust for no_exception_p + (ossl_ssl_write_internal): ditto + (ossl_ssl_write): adjust ossl_write_internal call + (ossl_ssl_write_nonblock): ditto + * ext/stringio/stringio.c (strio_read_nonblock): + delay exception check + * io.c (no_exception_p): new function + (io_getpartial): call no_exception_p + (io_readpartial): adjust for io_getpartial + (get_kwargs_exception): remove + (io_read_nonblock): adjust for io_getpartial, + check no_exception_p on EOF + (io_write_nonblock): call no_exception_p + (rb_io_write_nonblock): do not check `exception: false' + (argf_getpartial): adjust for io_getpartial + [ruby-core:69778] [Feature #11318] + Fri Jul 3 07:13:11 2015 Nobuyoshi Nakada <nobu@r...> * dir.c (replace_real_basename): Win32 API does not set errno, get Index: io.c =================================================================== --- io.c (revision 51112) +++ io.c (revision 51113) @@ -2482,8 +2482,18 @@ read_internal_call(VALUE arg) https://github.com/ruby/ruby/blob/trunk/io.c#L2482 return Qundef; } +static int +no_exception_p(VALUE opts) +{ + VALUE except; + ID id = id_exception; + + rb_get_kwargs(opts, &id, 0, 1, &except); + return except == Qfalse; +} + static VALUE -io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock, int no_exception) +io_getpartial(int argc, VALUE *argv, VALUE io, VALUE opts, int nonblock) { rb_io_t *fptr; VALUE length, str; @@ -2523,7 +2533,7 @@ io_getpartial(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/io.c#L2533 if (!nonblock && rb_io_wait_readable(fptr->fd)) goto again; if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) { - if (no_exception) + if (no_exception_p(opts)) return sym_wait_readable; else rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block"); @@ -2603,25 +2613,12 @@ io_readpartial(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/io.c#L2613 { VALUE ret; - ret = io_getpartial(argc, argv, io, 0, 0); + ret = io_getpartial(argc, argv, io, Qnil, 0); if (NIL_P(ret)) rb_eof_error(); return ret; } -static VALUE -get_kwargs_exception(VALUE opts) -{ - static ID ids[1]; - VALUE except; - - if (!ids[0]) - ids[0] = id_exception; - - rb_get_kwargs(opts, ids, 0, 1, &except); - return except; -} - /* * call-seq: * ios.read_nonblock(maxlen) -> string @@ -2676,19 +2673,14 @@ get_kwargs_exception(VALUE opts) https://github.com/ruby/ruby/blob/trunk/io.c#L2673 static VALUE io_read_nonblock(int argc, VALUE *argv, VALUE io) { - VALUE ret; - VALUE opts = Qnil; - int no_exception = 0; + VALUE ret, opts; rb_scan_args(argc, argv, "11:", NULL, NULL, &opts); - if (!NIL_P(opts) && Qfalse == get_kwargs_exception(opts)) - no_exception = 1; - - ret = io_getpartial(argc, argv, io, 1, no_exception); + ret = io_getpartial(argc, argv, io, opts, 1); if (NIL_P(ret)) { - if (no_exception) + if (no_exception_p(opts)) return Qnil; else rb_eof_error(); @@ -2697,7 +2689,7 @@ io_read_nonblock(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/io.c#L2689 } static VALUE -io_write_nonblock(VALUE io, VALUE str, int no_exception) +io_write_nonblock(VALUE io, VALUE str, VALUE opts) { rb_io_t *fptr; long n; @@ -2717,7 +2709,7 @@ io_write_nonblock(VALUE io, VALUE str, i https://github.com/ruby/ruby/blob/trunk/io.c#L2709 if (n == -1) { if (errno == EWOULDBLOCK || errno == EAGAIN) { - if (no_exception) { + if (no_exception_p(opts)) { return sym_wait_writable; } else { @@ -2791,16 +2783,11 @@ io_write_nonblock(VALUE io, VALUE str, i https://github.com/ruby/ruby/blob/trunk/io.c#L2783 static VALUE rb_io_write_nonblock(int argc, VALUE *argv, VALUE io) { - VALUE str; - VALUE opts = Qnil; - int no_exceptions = 0; + VALUE str, opts; rb_scan_args(argc, argv, "10:", &str, &opts); - if (!NIL_P(opts) && Qfalse == get_kwargs_exception(opts)) - no_exceptions = 1; - - return io_write_nonblock(io, str, no_exceptions); + return io_write_nonblock(io, str, opts); } /* @@ -11218,7 +11205,7 @@ argf_getpartial(int argc, VALUE *argv, V https://github.com/ruby/ruby/blob/trunk/io.c#L11205 RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0); } else { - tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0); + tmp = io_getpartial(argc, argv, ARGF.current_file, Qnil, nonblock); } if (NIL_P(tmp)) { if (ARGF.next_p == -1) { Index: ext/openssl/ossl_ssl.c =================================================================== --- ext/openssl/ossl_ssl.c (revision 51112) +++ ext/openssl/ossl_ssl.c (revision 51113) @@ -1273,14 +1273,23 @@ read_would_block(int nonblock) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1273 } } +static int +no_exception_p(VALUE opts) +{ + if (RB_TYPE_P(opts, T_HASH) && + rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse) + return 1; + return 0; +} + static VALUE -ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, - int nonblock, int no_exception) +ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) { SSL *ssl; rb_io_t *fptr; int ret, ret2; VALUE cb_state; + int nonblock = opts != Qfalse; rb_ivar_set(self, ID_callback_state, Qnil); @@ -1299,12 +1308,12 @@ ossl_start_ssl(VALUE self, int (*func)() https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1308 switch((ret2 = ssl_get_error(ssl, ret))){ case SSL_ERROR_WANT_WRITE: - if (no_exception) { return sym_wait_writable; } + if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: - if (no_exception) { return sym_wait_readable; } + if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; @@ -1330,15 +1339,8 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1339 ossl_ssl_connect(VALUE self) { ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_connect, "SSL_connect", 0, 0); -} -static int -get_no_exception(VALUE opts) -{ - if (!NIL_P(opts) && Qfalse == rb_hash_lookup2(opts, sym_exception, Qundef)) - return 1; - return 0; + return ossl_start_ssl(self, SSL_connect, "SSL_connect", Qfalse); } /* @@ -1366,14 +1368,12 @@ get_no_exception(VALUE opts) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1368 static VALUE ossl_ssl_connect_nonblock(int argc, VALUE *argv, VALUE self) { - int no_exception; - VALUE opts = Qnil; - + VALUE opts; rb_scan_args(argc, argv, "0:", &opts); - no_exception = get_no_exception(opts); ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_connect, "SSL_connect", 1, no_exception); + + return ossl_start_ssl(self, SSL_connect, "SSL_connect", opts); } /* @@ -1387,7 +1387,8 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1387 ossl_ssl_accept(VALUE self) { ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_accept, "SSL_accept", 0, 0); + + return ossl_start_ssl(self, SSL_accept, "SSL_accept", Qfalse); } /* @@ -1415,14 +1416,12 @@ ossl_ssl_accept(VALUE self) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1416 static VALUE ossl_ssl_accept_nonblock(int argc, VALUE *argv, VALUE self) { - int no_exception; - VALUE opts = Qnil; + VALUE opts; rb_scan_args(argc, argv, "0:", &opts); - no_exception = get_no_exception(opts); - ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_accept, "SSL_accept", 1, no_exception); + + return ossl_start_ssl(self, SSL_accept, "SSL_accept", opts); } static VALUE @@ -1430,14 +1429,12 @@ ossl_ssl_read_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1429 { SSL *ssl; int ilen, nread = 0; - int no_exception = 0; VALUE len, str; rb_io_t *fptr; VALUE opts = Qnil; if (nonblock) { rb_scan_args(argc, argv, "11:", &len, &str, &opts); - no_exception = get_no_exception(opts); } else { rb_scan_args(argc, argv, "11", &len, &str); } @@ -1462,21 +1459,21 @@ ossl_ssl_read_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1459 case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: - if (no_exception) { return Qnil; } + if (no_exception_p(opts)) { return Qnil; } rb_eof_error(); case SSL_ERROR_WANT_WRITE: - if (no_exception) { return sym_wait_writable; } + if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: - if (no_exception) { return sym_wait_readable; } + if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if(ERR_peek_error() == 0 && nread == 0) { - if (no_exception) { return Qnil; } + if (no_exception_p(opts)) { return Qnil; } rb_eof_error(); } rb_sys_fail(0); @@ -1536,11 +1533,12 @@ ossl_ssl_read_nonblock(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1533 } static VALUE -ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception) +ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) { SSL *ssl; int nwrite = 0; rb_io_t *fptr; + int nonblock = opts != Qfalse; StringValue(str); GetSSL(self, ssl); @@ -1553,12 +1551,12 @@ ossl_ssl_write_internal(VALUE self, VALU https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1551 case SSL_ERROR_NONE: goto end; case SSL_ERROR_WANT_WRITE: - if (no_exception) { return sym_wait_writable; } + if (no_exception_p(opts)) { return sym_wait_writable; } write_would_block(nonblock); rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: - if (no_exception) { return sym_wait_readable; } + if (no_exception_p(opts)) { return sym_wait_readable; } read_would_block(nonblock); rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; @@ -1588,7 +1586,7 @@ ossl_ssl_write_internal(VALUE self, VALU https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1586 static VALUE ossl_ssl_write(VALUE self, VALUE str) { - return ossl_ssl_write_internal(self, str, 0, 0); + return ossl_ssl_write_internal(self, str, Qfalse); } /* @@ -1601,14 +1599,11 @@ ossl_ssl_write(VALUE self, VALUE str) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1599 static VALUE ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self) { - VALUE str; - VALUE opts = Qnil; - int no_exception; + VALUE str, opts; rb_scan_args(argc, argv, "1:", &str, &opts); - no_exception = get_no_exception(opts); - return ossl_ssl_write_internal(self, str, 1, no_exception); + return ossl_ssl_write_internal(self, str, opts); } /* Index: ext/stringio/stringio.c =================================================================== --- ext/stringio/stringio.c (revision 51112) +++ ext/stringio/stringio.c (revision 51113) @@ -1359,20 +1359,17 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L1359 strio_read_nonblock(int argc, VALUE *argv, VALUE self) { VALUE opts = Qnil, val; - int no_exception = 0; rb_scan_args(argc, argv, "11:", NULL, NULL, &opts); if (!NIL_P(opts)) { argc--; - - if (Qfalse == rb_hash_aref(opts, sym_exception)) - no_exception = 1; } val = strio_read(argc, argv, self); if (NIL_P(val)) { - if (no_exception) + if (!NIL_P(opts) && + rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse) return Qnil; else rb_eof_error(); Index: benchmark/bm_io_nonblock_noex.rb =================================================================== --- benchmark/bm_io_nonblock_noex.rb (revision 0) +++ benchmark/bm_io_nonblock_noex.rb (revision 51113) @@ -0,0 +1,22 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/bm_io_nonblock_noex.rb#L1 +nr = 1_000_000 +i = 0 +msg = '.' +buf = '.' +noex = { exception: false } +begin + r, w = IO.pipe + while i < nr + i += 1 + w.write_nonblock(msg, noex) + r.read_nonblock(1, buf, noex) + end +rescue ArgumentError # old Rubies + while i < nr + i += 1 + w.write_nonblock(msg) + r.read_nonblock(1, buf) + end +ensure + r.close + w.close +end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/