1
0
mirror of https://github.com/golang/go synced 2024-11-17 20:04:47 -07:00

net: optimize ReadMsgUDPAddrPort

Instead of implementing ReadMsgUDPAddrPort in terms of ReadMsgUDP,
do it the other way around. This keeps the code minimal while
still avoiding allocs.

We could also rearrange ReadMsgUDP to be mid-stack inlined to avoid
allocating the *UDPAddr, but anyone who's trying to eliminate
allocs should use ReadMsgUDPAddrPort instead anyway,
because ReadMsgUDP will always allocate at least once (the IP slice).

name                       old time/op    new time/op    delta
ReadWriteMsgUDPAddrPort-8    5.26µs ± 3%    5.29µs ± 6%     ~     (p=0.429 n=12+13)

name                       old alloc/op   new alloc/op   delta
ReadWriteMsgUDPAddrPort-8      176B ± 0%      128B ± 0%  -27.27%  (p=0.000 n=15+15)

name                       old allocs/op  new allocs/op  delta
ReadWriteMsgUDPAddrPort-8      5.00 ± 0%      4.00 ± 0%  -20.00%  (p=0.000 n=15+15)

Change-Id: I15228cb4ec4f13f2f390407b6c62c44c228e7201
Reviewed-on: https://go-review.googlesource.com/c/go/+/360596
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Josh Bleecher Snyder 2021-11-01 12:44:43 -07:00
parent b0472aa990
commit 3c61cb3dcd
3 changed files with 19 additions and 19 deletions

View File

@ -168,25 +168,21 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
// The packages golang.org/x/net/ipv4 and golang.org/x/net/ipv6 can be
// used to manipulate IP-level socket options in oob.
func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
if !c.ok() {
return 0, 0, 0, nil, syscall.EINVAL
}
n, oobn, flags, addr, err = c.readMsg(b, oob)
if err != nil {
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
var ap netip.AddrPort
n, oobn, flags, ap, err = c.ReadMsgUDPAddrPort(b, oob)
addr = UDPAddrFromAddrPort(ap)
return
}
// ReadMsgUDPAddrPort is like ReadMsgUDP but returns an netip.AddrPort instead of a UDPAddr.
func (c *UDPConn) ReadMsgUDPAddrPort(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
// TODO(bradfitz): make this efficient, making the internal net package
// type throughout be netip.Addr and only converting to the net.IP slice
// version at the edge. But for now (2021-10-20), this is a wrapper around
// the old way.
var ua *UDPAddr
n, oobn, flags, ua, err = c.ReadMsgUDP(b, oob)
addr = ua.AddrPort()
if !c.ok() {
return 0, 0, 0, netip.AddrPort{}, syscall.EINVAL
}
n, oobn, flags, addr, err = c.readMsg(b, oob)
if err != nil {
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
return
}

View File

@ -7,6 +7,7 @@ package net
import (
"context"
"errors"
"net/netip"
"os"
"syscall"
)
@ -28,8 +29,8 @@ func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
return n, addr, nil
}
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
return 0, 0, 0, nil, syscall.EPLAN9
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
return 0, 0, 0, netip.AddrPort{}, syscall.EPLAN9
}
func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {

View File

@ -8,6 +8,7 @@ package net
import (
"context"
"net/netip"
"syscall"
)
@ -68,14 +69,16 @@ func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
return n, addr, err
}
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr netip.AddrPort, err error) {
var sa syscall.Sockaddr
n, oobn, flags, sa, err = c.fd.readMsg(b, oob, 0)
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
ip := netip.AddrFrom4(sa.Addr)
addr = netip.AddrPortFrom(ip, uint16(sa.Port))
case *syscall.SockaddrInet6:
addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
ip := netip.AddrFrom16(sa.Addr).WithZone(zoneCache.name(int(sa.ZoneId)))
addr = netip.AddrPortFrom(ip, uint16(sa.Port))
}
return
}