Support so_busy_poll (#4188)

* Support so_busy_poll.
This commit is contained in:
Chengye Ke 2021-05-15 06:05:56 +08:00 committed by GitHub
parent ceb5fa39fe
commit 04c37982b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 117 additions and 1 deletions

View File

@ -555,6 +555,7 @@ else()
check_cxx_symbol_exists(if_nametoindex net/if.h HAVE_IF_NAMETOINDEX)
check_cxx_symbol_exists(SO_PEERCRED sys/socket.h ZMQ_HAVE_SO_PEERCRED)
check_cxx_symbol_exists(LOCAL_PEERCRED sys/socket.h ZMQ_HAVE_LOCAL_PEERCRED)
check_cxx_symbol_exists(SO_BUSY_POLL sys/socket.h ZMQ_HAVE_BUSY_POLL)
endif()
if(NOT MINGW)

View File

@ -35,6 +35,7 @@
#cmakedefine ZMQ_HAVE_SO_PEERCRED
#cmakedefine ZMQ_HAVE_LOCAL_PEERCRED
#cmakedefine ZMQ_HAVE_BUSY_POLL
#cmakedefine ZMQ_HAVE_O_CLOEXEC

View File

@ -87,6 +87,21 @@ Default value:: not set
Applicable socket types:: all, when using TCP or UDP transports.
ZMQ_BUSY_POLL: This removes delays caused by the interrupt and the resultant context switch.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Busy polling helps reduce latency in the network receive path by allowing socket layer code
to poll the receive queue of a network device, and disabling network interrupts. This removes
delays caused by the interrupt and the resultant context switch. However, it also increases
CPU utilization. Busy polling also prevents the CPU from sleeping, which can incur additional
power consumption.
[horizontal]
Option value type:: int
Option value unit:: 0,1
Default value:: 0
Applicable socket types:: all
ZMQ_CONNECT_RID: Assign the next outbound connection id
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This option name is now deprecated. Use ZMQ_CONNECT_ROUTING_ID instead.

View File

@ -683,6 +683,7 @@ ZMQ_EXPORT void zmq_threadclose (void *thread_);
#define ZMQ_HELLO_MSG 110
#define ZMQ_DISCONNECT_MSG 111
#define ZMQ_PRIORITY 112
#define ZMQ_BUSY_POLL 113
/* DRAFT ZMQ_RECONNECT_STOP options */
#define ZMQ_RECONNECT_STOP_CONN_REFUSED 0x1

View File

@ -254,7 +254,8 @@ zmq::options_t::options_t () :
hello_msg (),
can_send_hello_msg (false),
disconnect_msg (),
can_recv_disconnect_msg (false)
can_recv_disconnect_msg (false),
busy_poll (0)
{
memset (curve_public_key, 0, CURVE_KEYSIZE);
memset (curve_secret_key, 0, CURVE_KEYSIZE);
@ -802,6 +803,12 @@ int zmq::options_t::setsockopt (int option_,
}
break;
case ZMQ_BUSY_POLL:
if (is_int) {
busy_poll = value;
return 0;
}
break;
#ifdef ZMQ_HAVE_WSS
case ZMQ_WSS_KEY_PEM:
// TODO: check if valid certificate
@ -1285,6 +1292,12 @@ int zmq::options_t::getsockopt (int option_,
return 0;
}
break;
case ZMQ_BUSY_POLL:
if (is_int) {
*value = busy_poll;
}
break;
#endif

View File

@ -308,6 +308,9 @@ struct options_t
// Disconnect msg
std::vector<unsigned char> disconnect_msg;
bool can_recv_disconnect_msg;
// This option removes several delays caused by scheduling, interrupts and context switching.
int busy_poll;
};
inline bool get_effective_conflate_option (const options_t &options)

View File

@ -341,6 +341,21 @@ void zmq::tcp_tune_loopback_fast_path (const fd_t socket_)
#endif
}
void zmq::tune_tcp_busy_poll (fd_t socket_, int busy_poll_)
{
#if defined(ZMQ_HAVE_BUSY_POLL)
if (busy_poll_ > 0) {
const int rc =
setsockopt (socket_, SOL_SOCKET, SO_BUSY_POLL,
reinterpret_cast<char *> (&busy_poll_), sizeof (int));
assert_success_or_recoverable (socket_, rc);
}
#else
LIBZMQ_UNUSED (socket_);
LIBZMQ_UNUSED (busy_poll_);
#endif
}
zmq::fd_t zmq::tcp_open_socket (const char *address_,
const zmq::options_t &options_,
bool local_,
@ -398,6 +413,9 @@ zmq::fd_t zmq::tcp_open_socket (const char *address_,
if (options_.rcvbuf >= 0)
set_tcp_receive_buffer (s, options_.rcvbuf);
// This option removes several delays caused by scheduling, interrupts and context switching.
if (options_.busy_poll)
tune_tcp_busy_poll (s, options_.busy_poll);
return s;
setsockopt_error:

View File

@ -68,6 +68,8 @@ int tcp_read (fd_t s_, void *data_, size_t size_);
void tcp_tune_loopback_fast_path (fd_t socket_);
void tune_tcp_busy_poll (fd_t socket_, int busy_poll_);
// Resolves the given address_ string, opens a socket and sets socket options
// according to the passed options_. On success, returns the socket
// descriptor and assigns the resolved address to out_tcp_addr_. In case of

View File

@ -69,6 +69,7 @@
#define ZMQ_HELLO_MSG 110
#define ZMQ_DISCONNECT_MSG 111
#define ZMQ_PRIORITY 112
#define ZMQ_BUSY_POLL 113
/* DRAFT ZMQ_RECONNECT_STOP options */
#define ZMQ_RECONNECT_STOP_CONN_REFUSED 0x1

View File

@ -162,6 +162,9 @@ if(ENABLE_DRAFTS)
test_hello_msg
test_disconnect_msg
)
if(ZMQ_HAVE_BUSY_POLL)
list(APPEND tests test_busy_poll)
endif()
endif()
if(ZMQ_HAVE_WS)

58
tests/test_busy_poll.cpp Normal file
View File

@ -0,0 +1,58 @@
/*
Copyright (c) 2007-2021 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "testutil.hpp"
#include "testutil_unity.hpp"
SETUP_TEARDOWN_TESTCONTEXT
void test_busy_poll ()
{
// Create a socket
void *socket = test_context_socket (ZMQ_DEALER);
// set socket ZMQ_BUSY_POLL options
int busy_poll = 1;
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (socket, ZMQ_BUSY_POLL, &busy_poll, sizeof (int)));
// bind socket
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket, "tcp://127.0.0.1:*"));
// Clean up.
test_context_socket_close (socket);
}
int main ()
{
setup_test_environment ();
UNITY_BEGIN ();
RUN_TEST (test_busy_poll);
return UNITY_END ();
}