[go] net: optimize ReadMsgUDPAddrPort

9 views
Skip to first unread message

Josh Bleecher Snyder (Gerrit)

unread,
Nov 1, 2021, 11:54:29 PM11/1/21
to Josh Bleecher Snyder, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Brad Fitzpatrick, Go Bot, golang-co...@googlegroups.com

Josh Bleecher Snyder submitted this change.

View Change


Approvals: Brad Fitzpatrick: Looks good to me, approved Josh Bleecher Snyder: Trusted; Run TryBots Go Bot: TryBots succeeded
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 <josh...@gmail.com>
Run-TryBot: Josh Bleecher Snyder <josh...@gmail.com>
TryBot-Result: Go Bot <go...@golang.org>
Reviewed-by: Brad Fitzpatrick <brad...@golang.org>
---
M src/net/udpsock_posix.go
M src/net/udpsock.go
M src/net/udpsock_plan9.go
3 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 95ffa85..8c97ca7 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -168,25 +168,21 @@
// 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
}

diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 1df293d..c18af23 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -7,6 +7,7 @@
import (
"context"
"errors"
+ "net/netip"
"os"
"syscall"
)
@@ -28,8 +29,8 @@
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) {
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index c3f7ddb..b200251 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -8,6 +8,7 @@

import (
"context"
+ "net/netip"
"syscall"
)

@@ -68,14 +69,16 @@
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
}

To view, visit change 360596. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I15228cb4ec4f13f2f390407b6c62c44c228e7201
Gerrit-Change-Number: 360596
Gerrit-PatchSet: 2
Gerrit-Owner: Josh Bleecher Snyder <josh...@gmail.com>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Go Bot <go...@golang.org>
Gerrit-Reviewer: Josh Bleecher Snyder <josh...@gmail.com>
Gerrit-MessageType: merged
Reply all
Reply to author
Forward
0 new messages