OTP 29 adds socket:recvmmsg and socket:sendmmsg, which move multiple UDP datagrams across the user/kernel boundary in a single syscall (wrapping Linux's recvmmsg(2)/sendmmsg(2)). On nquic's hot path, where per-packet send/recv dominates, this amortizes syscall overhead and should improve packets-per-second. It pairs naturally with the existing SO_REUSEPORT receiver loops and connected-UDP dispatch.
The proposal is to use recvmmsg to drain a batch of datagrams per call on the receive loop, and sendmmsg to coalesce queued outbound packets (e.g. a congestion-controlled flush burst). This should be gated at runtime (e.g. erlang:function_exported(socket, recvmmsg, 3)) with a fallback to the current single-message path, so OTP 27/28 keep working and it stays an auto-detected optimization rather than a version bump.
OTP 29 adds
socket:recvmmsgandsocket:sendmmsg, which move multiple UDP datagrams across the user/kernel boundary in a single syscall (wrapping Linux'srecvmmsg(2)/sendmmsg(2)). On nquic's hot path, where per-packet send/recv dominates, this amortizes syscall overhead and should improve packets-per-second. It pairs naturally with the existingSO_REUSEPORTreceiver loops and connected-UDP dispatch.The proposal is to use
recvmmsgto drain a batch of datagrams per call on the receive loop, andsendmmsgto coalesce queued outbound packets (e.g. a congestion-controlled flush burst). This should be gated at runtime (e.g.erlang:function_exported(socket, recvmmsg, 3)) with a fallback to the current single-message path, so OTP 27/28 keep working and it stays an auto-detected optimization rather than a version bump.