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:
parent
b0472aa990
commit
3c61cb3dcd
@ -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
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user