[前][次][番号順一覧][スレッド一覧]

ruby-changes:40522

From: normal <ko1@a...>
Date: Tue, 17 Nov 2015 10:05:48 +0900 (JST)
Subject: [ruby-changes:40522] normal:r52603 (trunk): socket: avoid arg parsing in bsock_sendmsg_internal

normal	2015-11-17 10:05:30 +0900 (Tue, 17 Nov 2015)

  New Revision: 52603

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52603

  Log:
    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

  Modified files:
    trunk/ChangeLog
    trunk/ext/socket/ancdata.c
    trunk/ext/socket/basicsocket.c
    trunk/ext/socket/lib/socket.rb
    trunk/ext/socket/rubysocket.h
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52602)
+++ ChangeLog	(revision 52603)
@@ -1,3 +1,16 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Nov 17 09:59:00 2015  Eric Wong  <e@8...>
+
+	* 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@8...>
 
 	* ext/socket/ancdata.c (bsock_recvmsg_internal): avoid arg parsing
Index: ext/socket/rubysocket.h
===================================================================
--- ext/socket/rubysocket.h	(revision 52602)
+++ ext/socket/rubysocket.h	(revision 52603)
@@ -361,8 +361,10 @@ VALUE rsock_sock_listen(VALUE sock, VALU https://github.com/ruby/ruby/blob/trunk/ext/socket/rubysocket.h#L361
 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(i https://github.com/ruby/ruby/blob/trunk/ext/socket/rubysocket.h#L439
 #  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
Index: ext/socket/lib/socket.rb
===================================================================
--- ext/socket/lib/socket.rb	(revision 52602)
+++ ext/socket/lib/socket.rb	(revision 52603)
@@ -276,6 +276,56 @@ class BasicSocket < IO https://github.com/ruby/ruby/blob/trunk/ext/socket/lib/socket.rb#L276
   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
   #
   # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
Index: ext/socket/basicsocket.c
===================================================================
--- ext/socket/basicsocket.c	(revision 52602)
+++ ext/socket/basicsocket.c	(revision 52603)
@@ -724,10 +724,11 @@ rsock_init_basicsocket(void) https://github.com/ruby/ruby/blob/trunk/ext/socket/basicsocket.c#L724
     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",
Index: ext/socket/ancdata.c
===================================================================
--- ext/socket/ancdata.c	(revision 52602)
+++ ext/socket/ancdata.c	(revision 52603)
@@ -3,7 +3,7 @@ https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L3
 #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 * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1128
 }
 
 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 * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1148
     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 * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1280
             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 * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1297
 #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) https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1726
     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"));
 }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]