Allow to configure socket option SO_BUSY_POLL (#8268)

Motivation:

When using Epoll based transport, allow applications to configure SO_BUSY_POLL socket option:

       SO_BUSY_POLL (since Linux 3.11)
              Sets the approximate time in microseconds to busy poll on a
              blocking receive when there is no data.  Increasing this value
              requires CAP_NET_ADMIN.  The default for this option is con‐
              trolled by the /proc/sys/net/core/busy_read file.

              The value in the /proc/sys/net/core/busy_poll file determines
              how long select(2) and poll(2) will busy poll when they oper‐
              ate on sockets with SO_BUSY_POLL set and no events to report
              are found.

              In both cases, busy polling will only be done when the socket
              last received data from a network device that supports this
              option.

              While busy polling may improve latency of some applications,
              care must be taken when using it since this will increase both
              CPU utilization and power usage.

Modification:

Added SO_BUSY_POLL socket option
Result:

Able to configure SO_BUSY_POLL from Netty
This commit is contained in:
Matteo Merli 2018-09-07 11:50:51 -07:00 committed by Norman Maurer
parent c14efd952d
commit 2a1596a4e9
4 changed files with 59 additions and 1 deletions

View File

@ -50,6 +50,11 @@
#define TCP_NOTSENT_LOWAT 25
#endif
// SO_BUSY_POLL is defined in linux 3.11. We define this here so older kernels can compile.
#ifndef SO_BUSY_POLL
#define SO_BUSY_POLL 46
#endif
static jclass peerCredentialsClass = NULL;
static jmethodID peerCredentialsMethodId = NULL;
@ -111,6 +116,10 @@ static void netty_epoll_linuxsocket_setIpRecvOrigDestAddr(JNIEnv* env, jclass cl
netty_unix_socket_setOption(env, fd, IPPROTO_IP, IP_RECVORIGDSTADDR, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setSoBusyPoll(JNIEnv* env, jclass clazz, jint fd, jint optval) {
netty_unix_socket_setOption(env, fd, SOL_SOCKET, SO_BUSY_POLL, &optval, sizeof(optval));
}
static void netty_epoll_linuxsocket_setTcpMd5Sig(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jbyteArray key) {
struct sockaddr_storage addr;
socklen_t addrSize;
@ -256,6 +265,14 @@ static jint netty_epoll_linuxsocket_isTcpCork(JNIEnv* env, jclass clazz, jint fd
return optval;
}
static jint netty_epoll_linuxsocket_getSoBusyPoll(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, SOL_SOCKET, SO_BUSY_POLL, &optval, sizeof(optval)) == -1) {
return -1;
}
return optval;
}
static jint netty_epoll_linuxsocket_getTcpDeferAccept(JNIEnv* env, jclass clazz, jint fd) {
int optval;
if (netty_unix_socket_getOption(env, fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &optval, sizeof(optval)) == -1) {
@ -341,10 +358,12 @@ static jlong netty_epoll_linuxsocket_sendFile(JNIEnv* env, jclass clazz, jint fd
// JNI Method Registration Table Begin
static const JNINativeMethod fixed_method_table[] = {
{ "setTcpCork", "(II)V", (void *) netty_epoll_linuxsocket_setTcpCork },
{ "setSoBusyPoll", "(II)V", (void *) netty_epoll_linuxsocket_setSoBusyPoll },
{ "setTcpQuickAck", "(II)V", (void *) netty_epoll_linuxsocket_setTcpQuickAck },
{ "setTcpDeferAccept", "(II)V", (void *) netty_epoll_linuxsocket_setTcpDeferAccept },
{ "setTcpNotSentLowAt", "(II)V", (void *) netty_epoll_linuxsocket_setTcpNotSentLowAt },
{ "isTcpCork", "(I)I", (void *) netty_epoll_linuxsocket_isTcpCork },
{ "getSoBusyPoll", "(I)I", (void *) netty_epoll_linuxsocket_getSoBusyPoll },
{ "getTcpDeferAccept", "(I)I", (void *) netty_epoll_linuxsocket_getTcpDeferAccept },
{ "getTcpNotSentLowAt", "(I)I", (void *) netty_epoll_linuxsocket_getTcpNotSentLowAt },
{ "isTcpQuickAck", "(I)I", (void *) netty_epoll_linuxsocket_isTcpQuickAck },

View File

@ -38,6 +38,7 @@ public final class EpollChannelOption<T> extends UnixChannelOption<T> {
public static final ChannelOption<Integer> TCP_DEFER_ACCEPT =
ChannelOption.valueOf(EpollChannelOption.class, "TCP_DEFER_ACCEPT");
public static final ChannelOption<Boolean> TCP_QUICKACK = valueOf(EpollChannelOption.class, "TCP_QUICKACK");
public static final ChannelOption<Integer> SO_BUSY_POLL = valueOf(EpollChannelOption.class, "SO_BUSY_POLL");
public static final ChannelOption<EpollMode> EPOLL_MODE =
ChannelOption.valueOf(EpollChannelOption.class, "EPOLL_MODE");

View File

@ -62,7 +62,7 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
ALLOW_HALF_CLOSURE, EpollChannelOption.TCP_CORK, EpollChannelOption.TCP_NOTSENT_LOWAT,
EpollChannelOption.TCP_KEEPCNT, EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL,
EpollChannelOption.TCP_MD5SIG, EpollChannelOption.TCP_QUICKACK, EpollChannelOption.IP_TRANSPARENT,
EpollChannelOption.TCP_FASTOPEN_CONNECT);
EpollChannelOption.TCP_FASTOPEN_CONNECT, EpollChannelOption.SO_BUSY_POLL);
}
@SuppressWarnings("unchecked")
@ -119,6 +119,9 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
if (option == EpollChannelOption.TCP_FASTOPEN_CONNECT) {
return (T) Boolean.valueOf(isTcpFastOpenConnect());
}
if (option == EpollChannelOption.SO_BUSY_POLL) {
return (T) Integer.valueOf(getSoBusyPoll());
}
return super.getOption(option);
}
@ -164,6 +167,8 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
setTcpQuickAck((Boolean) value);
} else if (option == EpollChannelOption.TCP_FASTOPEN_CONNECT) {
setTcpFastOpenConnect((Boolean) value);
} else if (option == EpollChannelOption.SO_BUSY_POLL) {
setSoBusyPoll((Integer) value);
} else {
return super.setOption(option, value);
}
@ -245,6 +250,17 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
}
}
/**
* Get the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details.
*/
public int getSoBusyPoll() {
try {
return channel.socket.getSoBusyPoll();
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Get the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
* @return value is a uint32_t
@ -380,6 +396,18 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
}
}
/**
* Set the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details.
*/
public EpollSocketChannelConfig setSoBusyPoll(int loopMicros) {
try {
channel.socket.setSoBusyPoll(loopMicros);
return this;
} catch (IOException e) {
throw new ChannelException(e);
}
}
/**
* Set the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
* @param tcpNotSentLowAt is a uint32_t

View File

@ -56,6 +56,10 @@ final class LinuxSocket extends Socket {
setTcpCork(intValue(), tcpCork ? 1 : 0);
}
void setSoBusyPoll(int loopMicros) throws IOException {
setSoBusyPoll(intValue(), loopMicros);
}
void setTcpNotSentLowAt(long tcpNotSentLowAt) throws IOException {
if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) {
throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t");
@ -116,6 +120,10 @@ final class LinuxSocket extends Socket {
return isTcpCork(intValue()) != 0;
}
int getSoBusyPoll() throws IOException {
return getSoBusyPoll(intValue());
}
int getTcpDeferAccept() throws IOException {
return getTcpDeferAccept(intValue());
}
@ -190,6 +198,7 @@ final class LinuxSocket extends Socket {
private static native int getTcpDeferAccept(int fd) throws IOException;
private static native int isTcpQuickAck(int fd) throws IOException;
private static native int isTcpCork(int fd) throws IOException;
private static native int getSoBusyPoll(int fd) throws IOException;
private static native int getTcpNotSentLowAt(int fd) throws IOException;
private static native int getTcpKeepIdle(int fd) throws IOException;
private static native int getTcpKeepIntvl(int fd) throws IOException;
@ -205,6 +214,7 @@ final class LinuxSocket extends Socket {
private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException;
private static native void setTcpQuickAck(int fd, int quickAck) throws IOException;
private static native void setTcpCork(int fd, int tcpCork) throws IOException;
private static native void setSoBusyPoll(int fd, int loopMicros) throws IOException;
private static native void setTcpNotSentLowAt(int fd, int tcpNotSentLowAt) throws IOException;
private static native void setTcpFastOpen(int fd, int tcpFastopenBacklog) throws IOException;
private static native void setTcpFastOpenConnect(int fd, int tcpFastOpenConnect) throws IOException;