Implement recvmmsg() for Linux to reduce syscalls. (#2046)

Between 5% and 40% speed improvement on Linux, depending on system configuration and load.
This commit is contained in:
Adam Ierymenko 2023-07-20 11:36:37 -04:00 committed by GitHub
parent 50ede37a58
commit f1019dc4ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -988,19 +988,62 @@ public:
break; break;
case ZT_PHY_SOCKET_UDP: case ZT_PHY_SOCKET_UDP:
if (FD_ISSET(s->sock,&rfds)) { if (FD_ISSET(s->sock, &rfds)) {
for(int k=0;k<1024;++k) { #if (defined(__linux__) || defined(linux) || defined(__linux)) && defined(MSG_WAITFORONE)
memset(&ss,0,sizeof(ss)); #define RECVMMSG_WINDOW_SIZE 128
socklen_t slen = sizeof(ss); #define RECVMMSG_BUF_SIZE 1500
long n = (long)::recvfrom(s->sock,buf,sizeof(buf),0,(struct sockaddr *)&ss,&slen); iovec iovs[RECVMMSG_WINDOW_SIZE];
uint8_t bufs[RECVMMSG_WINDOW_SIZE][RECVMMSG_BUF_SIZE];
sockaddr_storage addrs[RECVMMSG_WINDOW_SIZE];
memset(addrs, 0, sizeof(addrs));
mmsghdr mm[RECVMMSG_WINDOW_SIZE];
memset(mm, 0, sizeof(mm));
for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) {
iovs[i].iov_base = (void*)bufs[i];
iovs[i].iov_len = RECVMMSG_BUF_SIZE;
mm[i].msg_hdr.msg_name = (void*)&(addrs[i]);
mm[i].msg_hdr.msg_iov = &(iovs[i]);
mm[i].msg_hdr.msg_iovlen = 1;
}
for (int k = 0; k < 1024; ++k) {
for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) {
mm[i].msg_hdr.msg_namelen = sizeof(sockaddr_storage);
mm[i].msg_len = 0;
}
int received_count = recvmmsg(s->sock, mm, RECVMMSG_WINDOW_SIZE, MSG_WAITFORONE, nullptr);
if (received_count > 0) {
for (int i = 0; i < received_count; ++i) {
long n = (long)mm[i].msg_len;
if (n > 0) { if (n > 0) {
try { try {
_handler->phyOnDatagram((PhySocket *)&(*s),&(s->uptr),(const struct sockaddr *)&(s->saddr),(const struct sockaddr *)&ss,(void *)buf,(unsigned long)n); _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&(addrs[i]), bufs[i], (unsigned long)n);
} catch ( ... ) {} }
} else if (n < 0) catch (...) {
}
}
}
}
else {
break; break;
} }
} }
#else
for (int k = 0; k < 1024; ++k) {
memset(&ss, 0, sizeof(ss));
socklen_t slen = sizeof(ss);
long n = (long)::recvfrom(s->sock, buf, sizeof(buf), 0, (struct sockaddr*)&ss, &slen);
if (n > 0) {
try {
_handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&ss, (void*)buf, (unsigned long)n);
}
catch (...) {
}
}
else if (n < 0)
break;
}
#endif
}
break; break;
case ZT_PHY_SOCKET_UNIX_IN: { case ZT_PHY_SOCKET_UNIX_IN: {