socket: avoid arg parsing in bsock_sendmsg_internal

* ext/socket/ancdata.c (bsock_sendmsg_internal): avoid arg parsing
  [ruby-core:71439] [Feature #11339]
  (rsock_bsock_sendmsg): make private, adjust for above
  (rsock_bsock_sendmsg_nonblock): ditto
* ext/socket/rubysocket.h: adjust prototypes
  (rsock_opt_false_p): remove
* ext/socket/basicsocket.c (rsock_init_basicsocket):
  define private methods
* ext/socket/lib/socket.rb (BasicSocket#sendmsg): new wrapper
  (BasicSocket#sendmsg_nonblock): ditto

target 0: a (ruby 2.3.0dev (2015-11-12 trunk 52550) [x86_64-linux])
target 1: b (ruby 2.3.0dev (2015-11-12 avoid-kwarg-capi 52550) [x86_64-linux]

-----------------------------------------------------------
sendmsg_nonblock

require 'socket'
nr = 1_000_000
i = 0
msg = '.'
buf = '.'
begin
  r, w = UNIXSocket.pair(:SEQPACKET)
  while i < nr
    i += 1
    w.sendmsg_nonblock(msg, exception: false)
    r.recv(1, 0, buf)
  end
ensure
  r.close
  w.close
end

-----------------------------------------------------------
raw data:

[["sendmsg_nonblock",
  [[1.875997293740511,
    1.8452614955604076,
    1.8449317328631878,
    1.8418389447033405,
    1.869386937469244],
   [1.5175109766423702,
    1.4987873211503029,
    1.4989623799920082,
    1.47918451577425,
    1.5017359890043736]]]]

Elapsed time: 16.775453245 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name             a       b
sendmsg_nonblock   1.842   1.479

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

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52603 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2015-11-17 01:05:30 +00:00
Родитель 416c50f574
Коммит eda2441b53
5 изменённых файлов: 88 добавлений и 78 удалений

Просмотреть файл

@ -1,3 +1,16 @@
Tue Nov 17 09:59:00 2015 Eric Wong <e@80x24.org>
* ext/socket/ancdata.c (bsock_sendmsg_internal): avoid arg parsing
[ruby-core:71439] [Feature #11339]
(rsock_bsock_sendmsg): make private, adjust for above
(rsock_bsock_sendmsg_nonblock): ditto
* ext/socket/rubysocket.h: adjust prototypes
(rsock_opt_false_p): remove
* ext/socket/basicsocket.c (rsock_init_basicsocket):
define private methods
* ext/socket/lib/socket.rb (BasicSocket#sendmsg): new wrapper
(BasicSocket#sendmsg_nonblock): ditto
Tue Nov 17 09:45:18 2015 Eric Wong <e@80x24.org>
* ext/socket/ancdata.c (bsock_recvmsg_internal): avoid arg parsing

Просмотреть файл

@ -3,7 +3,7 @@
#include <time.h>
int rsock_cmsg_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
static VALUE sym_exception, sym_wait_readable, sym_wait_writable;
static VALUE sym_wait_readable, sym_wait_writable;
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
static VALUE rb_cAncillaryData;
@ -1128,14 +1128,13 @@ rb_sendmsg(int fd, const struct msghdr *msg, int flags)
}
static VALUE
bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
bsock_sendmsg_internal(VALUE sock, VALUE data, VALUE vflags,
VALUE dest_sockaddr, VALUE controls, VALUE ex,
int nonblock)
{
rb_io_t *fptr;
VALUE data, vflags, dest_sockaddr;
struct msghdr mh;
struct iovec iov;
VALUE opts = Qnil;
VALUE controls = Qnil;
int controls_num;
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
VALUE controls_str = 0;
@ -1149,15 +1148,11 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
family = rsock_getfamily(fptr);
#endif
data = vflags = dest_sockaddr = Qnil;
if (argc == 0)
rb_raise(rb_eArgError, "mesg argument required");
rb_scan_args(argc, argv, "12*:", &data, &vflags, &dest_sockaddr, &controls,
&opts);
StringValue(data);
if (!RB_TYPE_P(controls, T_ARRAY)) {
controls = rb_ary_new();
}
controls_num = RARRAY_LENINT(controls);
if (controls_num) {
@ -1285,7 +1280,7 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
goto retry;
}
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
if (rsock_opt_false_p(opts, sym_exception)) {
if (ex == Qfalse) {
return sym_wait_writable;
}
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE,
@ -1302,64 +1297,22 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
#endif
#if defined(HAVE_SENDMSG)
/*
* call-seq:
* basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
*
* sendmsg sends a message using sendmsg(2) system call in blocking manner.
*
* _mesg_ is a string to send.
*
* _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
*
* _dest_sockaddr_ is a destination socket address for connection-less socket.
* It should be a sockaddr such as a result of Socket.sockaddr_in.
* An Addrinfo object can be used too.
*
* _controls_ is a list of ancillary data.
* The element of _controls_ should be Socket::AncillaryData or
* 3-elements array.
* The 3-element array should contains cmsg_level, cmsg_type and data.
*
* The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
*
* sendmsg can be used to implement send_io as follows:
*
* # use Socket::AncillaryData.
* ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
* sock.sendmsg("a", 0, nil, ancdata)
*
* # use 3-element array.
* ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
* sock.sendmsg("\0", 0, nil, ancdata)
*
*/
VALUE
rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
rsock_bsock_sendmsg(VALUE sock, VALUE data, VALUE flags, VALUE dest_sockaddr,
VALUE controls)
{
return bsock_sendmsg_internal(argc, argv, sock, 0);
return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr, controls,
Qtrue, 0);
}
#endif
#if defined(HAVE_SENDMSG)
/*
* call-seq:
* basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent
*
* sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
*
* It is similar to BasicSocket#sendmsg
* but the non-blocking flag is set before the system call
* and it doesn't retry the system call.
*
* By specifying `exception: false`, the _opts_ hash allows you to indicate
* that sendmsg_nonblock should not raise an IO::WaitWritable exception, but
* return the symbol :wait_writable instead.
*/
VALUE
rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
rsock_bsock_sendmsg_nonblock(VALUE sock, VALUE data, VALUE flags,
VALUE dest_sockaddr, VALUE controls, VALUE ex)
{
return bsock_sendmsg_internal(argc, argv, sock, 1);
return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr,
controls, ex, 1);
}
#endif
@ -1773,7 +1726,6 @@ rsock_init_ancdata(void)
rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
#endif
#undef rb_intern
sym_exception = ID2SYM(rb_intern("exception"));
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
}

Просмотреть файл

@ -724,10 +724,11 @@ rsock_init_basicsocket(void)
rb_define_private_method(rb_cBasicSocket,
"__recv_nonblock", bsock_recv_nonblock, 4);
rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
/* in ancdata.c */
rb_define_private_method(rb_cBasicSocket, "__sendmsg",
rsock_bsock_sendmsg, 4);
rb_define_private_method(rb_cBasicSocket, "__sendmsg_nonblock",
rsock_bsock_sendmsg_nonblock, 5);
rb_define_private_method(rb_cBasicSocket, "__recvmsg",
rsock_bsock_recvmsg, 4);
rb_define_private_method(rb_cBasicSocket, "__recvmsg_nonblock",

Просмотреть файл

@ -275,6 +275,56 @@ class BasicSocket < IO
addr
end
# call-seq:
# basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
#
# sendmsg sends a message using sendmsg(2) system call in blocking manner.
#
# _mesg_ is a string to send.
#
# _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
#
# _dest_sockaddr_ is a destination socket address for connection-less socket.
# It should be a sockaddr such as a result of Socket.sockaddr_in.
# An Addrinfo object can be used too.
#
# _controls_ is a list of ancillary data.
# The element of _controls_ should be Socket::AncillaryData or
# 3-elements array.
# The 3-element array should contains cmsg_level, cmsg_type and data.
#
# The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
#
# sendmsg can be used to implement send_io as follows:
#
# # use Socket::AncillaryData.
# ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
# sock.sendmsg("a", 0, nil, ancdata)
#
# # use 3-element array.
# ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
# sock.sendmsg("\0", 0, nil, ancdata)
def sendmsg(mesg, flags = 0, dest_sockaddr = nil, *controls)
__sendmsg(mesg, flags, dest_sockaddr, controls)
end
# call-seq:
# basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent
#
# sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
#
# It is similar to BasicSocket#sendmsg
# but the non-blocking flag is set before the system call
# and it doesn't retry the system call.
#
# By specifying `exception: false`, the _opts_ hash allows you to indicate
# that sendmsg_nonblock should not raise an IO::WaitWritable exception, but
# return the symbol :wait_writable instead.
def sendmsg_nonblock(mesg, flags = 0, dest_sockaddr = nil, *controls,
exception: true)
__sendmsg_nonblock(mesg, flags, dest_sockaddr, controls, exception)
end
# call-seq:
# basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
#

Просмотреть файл

@ -361,8 +361,10 @@ VALUE rsock_sock_listen(VALUE sock, VALUE log);
VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data);
#if defined(HAVE_SENDMSG)
VALUE rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock);
VALUE rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock);
VALUE rsock_bsock_sendmsg(VALUE sock, VALUE data, VALUE flags,
VALUE dest_sockaddr, VALUE controls);
VALUE rsock_bsock_sendmsg_nonblock(VALUE sock, VALUE data, VALUE flags,
VALUE dest_sockaddr, VALUE controls, VALUE ex);
#else
#define rsock_bsock_sendmsg rb_f_notimplement
#define rsock_bsock_sendmsg_nonblock rb_f_notimplement
@ -437,12 +439,4 @@ static inline void rsock_maybe_wait_fd(int fd) { }
# define MSG_DONTWAIT_RELIABLE 0
#endif
static inline int
rsock_opt_false_p(VALUE opt, VALUE sym)
{
if (!NIL_P(opt) && Qfalse == rb_hash_lookup2(opt, sym, Qundef))
return 1;
return 0;
}
#endif