diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2021-05-26 12:55:16 -0700 |
---|---|---|
committer | Damien Neil <dneil@google.com> | 2021-08-16 23:54:32 +0000 |
commit | d9349175ad13ab228d3224c4bff8e3e1b2936b42 (patch) | |
tree | b451b8f1f7a1821aeba031ccd58a0bf00eb10a89 | |
parent | 8ff16c19909e5aecf51c6b993cba36ea51791f34 (diff) | |
download | go-d9349175ad13ab228d3224c4bff8e3e1b2936b42.tar.gz go-d9349175ad13ab228d3224c4bff8e3e1b2936b42.zip |
net: remove allocation from UDPConn.WriteTo
Duplicate some code to avoid an interface.
name old time/op new time/op delta
WriteToReadFromUDP-8 6.38µs ±20% 5.59µs ±10% -12.38% (p=0.001 n=10+9)
name old alloc/op new alloc/op delta
WriteToReadFromUDP-8 64.0B ± 0% 32.0B ± 0% -50.00% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
WriteToReadFromUDP-8 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10)
Windows is temporarily stubbed out.
Updates #43451
Change-Id: Ied15ff92268c652cf445836e0446025eaeb60cc9
Reviewed-on: https://go-review.googlesource.com/c/go/+/331489
Trust: Josh Bleecher Snyder <josharian@gmail.com>
Trust: Damien Neil <dneil@google.com>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
-rw-r--r-- | api/next.txt | 52 | ||||
-rw-r--r-- | src/internal/poll/fd_unix.go | 52 | ||||
-rw-r--r-- | src/internal/poll/fd_windows.go | 10 | ||||
-rw-r--r-- | src/net/fd_posix.go | 12 | ||||
-rw-r--r-- | src/net/ipsock_posix.go | 76 | ||||
-rw-r--r-- | src/net/net_fake.go | 8 | ||||
-rw-r--r-- | src/net/udpsock_posix.go | 20 | ||||
-rw-r--r-- | src/syscall/net_js.go | 8 | ||||
-rw-r--r-- | src/syscall/syscall_unix.go | 16 |
9 files changed, 220 insertions, 34 deletions
diff --git a/api/next.txt b/api/next.txt index e69de29bb2..8d2ee73f79 100644 --- a/api/next.txt +++ b/api/next.txt @@ -0,0 +1,52 @@ +pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (darwin-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (darwin-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (darwin-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (freebsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (freebsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (freebsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (freebsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (freebsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (freebsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (freebsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (freebsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (freebsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (freebsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (freebsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (freebsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (linux-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (linux-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (linux-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (linux-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (linux-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (linux-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (linux-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (linux-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (linux-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (linux-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (linux-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (linux-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-arm64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-arm64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (netbsd-arm64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (netbsd-arm64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (openbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (openbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (openbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (openbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (openbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (openbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error +pkg syscall (openbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error +pkg syscall (openbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go index 3b17cd22b0..51d15f6abc 100644 --- a/src/internal/poll/fd_unix.go +++ b/src/internal/poll/fd_unix.go @@ -327,6 +327,58 @@ func (fd *FD) Pwrite(p []byte, off int64) (int, error) { } } +// WriteToInet4 wraps the sendto network call for IPv4 addresses. +func (fd *FD) WriteToInet4(p []byte, sa syscall.SockaddrInet4) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + if err := fd.pd.prepareWrite(fd.isFile); err != nil { + return 0, err + } + for { + err := syscall.SendtoInet4(fd.Sysfd, p, 0, sa) + if err == syscall.EINTR { + continue + } + if err == syscall.EAGAIN && fd.pd.pollable() { + if err = fd.pd.waitWrite(fd.isFile); err == nil { + continue + } + } + if err != nil { + return 0, err + } + return len(p), nil + } +} + +// WriteToInet6 wraps the sendto network call for IPv6 addresses. +func (fd *FD) WriteToInet6(p []byte, sa syscall.SockaddrInet6) (int, error) { + if err := fd.writeLock(); err != nil { + return 0, err + } + defer fd.writeUnlock() + if err := fd.pd.prepareWrite(fd.isFile); err != nil { + return 0, err + } + for { + err := syscall.SendtoInet6(fd.Sysfd, p, 0, sa) + if err == syscall.EINTR { + continue + } + if err == syscall.EAGAIN && fd.pd.pollable() { + if err = fd.pd.waitWrite(fd.isFile); err == nil { + continue + } + } + if err != nil { + return 0, err + } + return len(p), nil + } +} + // WriteTo wraps the sendto network call. func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) { if err := fd.writeLock(); err != nil { diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go index 4a5169527c..3dada32985 100644 --- a/src/internal/poll/fd_windows.go +++ b/src/internal/poll/fd_windows.go @@ -791,6 +791,16 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) { return ntotal, nil } +// WriteTo wraps the sendto network call for IPv4. +func (fd *FD) WriteToInet4(buf []byte, sa syscall.SockaddrInet4) (int, error) { + return fd.WriteTo(buf, &sa) +} + +// WriteTo wraps the sendto network call for IPv6. +func (fd *FD) WriteToInet6(buf []byte, sa syscall.SockaddrInet6) (int, error) { + return fd.WriteTo(buf, &sa) +} + // Call ConnectEx. This doesn't need any locking, since it is only // called when the descriptor is first created. This is here rather // than in the net package so that it can use fd.wop. diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go index 4703ff33a1..a0675b2072 100644 --- a/src/net/fd_posix.go +++ b/src/net/fd_posix.go @@ -82,6 +82,18 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { return n, wrapSyscallError(writeToSyscallName, err) } +func (fd *netFD) writeToInet4(p []byte, sa syscall.SockaddrInet4) (n int, err error) { + n, err = fd.pfd.WriteToInet4(p, sa) + runtime.KeepAlive(fd) + return n, wrapSyscallError(writeToSyscallName, err) +} + +func (fd *netFD) writeToInet6(p []byte, sa syscall.SockaddrInet6) (n int, err error) { + n, err = fd.pfd.WriteToInet6(p, sa) + runtime.KeepAlive(fd) + return n, wrapSyscallError(writeToSyscallName, err) +} + func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { n, oobn, err = fd.pfd.WriteMsg(p, oob, sa) runtime.KeepAlive(fd) diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go index c51c227401..50003ac446 100644 --- a/src/net/ipsock_posix.go +++ b/src/net/ipsock_posix.go @@ -142,42 +142,58 @@ func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, soty return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr, ctrlFn) } +func ipToSockaddrInet4(ip IP, port int) (syscall.SockaddrInet4, error) { + if len(ip) == 0 { + ip = IPv4zero + } + ip4 := ip.To4() + if ip4 == nil { + return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: ip.String()} + } + sa := syscall.SockaddrInet4{Port: port} + copy(sa.Addr[:], ip4) + return sa, nil +} + +func ipToSockaddrInet6(ip IP, port int, zone string) (syscall.SockaddrInet6, error) { + // In general, an IP wildcard address, which is either + // "0.0.0.0" or "::", means the entire IP addressing + // space. For some historical reason, it is used to + // specify "any available address" on some operations + // of IP node. + // + // When the IP node supports IPv4-mapped IPv6 address, + // we allow a listener to listen to the wildcard + // address of both IP addressing spaces by specifying + // IPv6 wildcard address. + if len(ip) == 0 || ip.Equal(IPv4zero) { + ip = IPv6zero + } + // We accept any IPv6 address including IPv4-mapped + // IPv6 address. + ip6 := ip.To16() + if ip6 == nil { + return syscall.SockaddrInet6{}, &AddrError{Err: "non-IPv6 address", Addr: ip.String()} + } + sa := syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))} + copy(sa.Addr[:], ip6) + return sa, nil +} + func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) { switch family { case syscall.AF_INET: - if len(ip) == 0 { - ip = IPv4zero - } - ip4 := ip.To4() - if ip4 == nil { - return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()} + sa, err := ipToSockaddrInet4(ip, port) + if err != nil { + return nil, err } - sa := &syscall.SockaddrInet4{Port: port} - copy(sa.Addr[:], ip4) - return sa, nil + return &sa, nil case syscall.AF_INET6: - // In general, an IP wildcard address, which is either - // "0.0.0.0" or "::", means the entire IP addressing - // space. For some historical reason, it is used to - // specify "any available address" on some operations - // of IP node. - // - // When the IP node supports IPv4-mapped IPv6 address, - // we allow a listener to listen to the wildcard - // address of both IP addressing spaces by specifying - // IPv6 wildcard address. - if len(ip) == 0 || ip.Equal(IPv4zero) { - ip = IPv6zero - } - // We accept any IPv6 address including IPv4-mapped - // IPv6 address. - ip6 := ip.To16() - if ip6 == nil { - return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()} + sa, err := ipToSockaddrInet6(ip, port, zone) + if err != nil { + return nil, err } - sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))} - copy(sa.Addr[:], ip6) - return sa, nil + return &sa, nil } return nil, &AddrError{Err: "invalid address family", Addr: ip.String()} } diff --git a/src/net/net_fake.go b/src/net/net_fake.go index 74fc1da6fd..feb51968dd 100644 --- a/src/net/net_fake.go +++ b/src/net/net_fake.go @@ -276,6 +276,14 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { return 0, syscall.ENOSYS } +func (fd *netFD) writeToInet4(p []byte, sa syscall.SockaddrInet4) (n int, err error) { + return 0, syscall.ENOSYS +} + +func (fd *netFD) writeToInet6(p []byte, sa syscall.SockaddrInet6) (n int, err error) { + return 0, syscall.ENOSYS +} + func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { return 0, 0, syscall.ENOSYS } diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go index 96fb373ce7..b71be09217 100644 --- a/src/net/udpsock_posix.go +++ b/src/net/udpsock_posix.go @@ -76,11 +76,23 @@ func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) { if addr == nil { return 0, errMissingAddress } - sa, err := addr.sockaddr(c.fd.family) - if err != nil { - return 0, err + + switch c.fd.family { + case syscall.AF_INET: + sa, err := ipToSockaddrInet4(addr.IP, addr.Port) + if err != nil { + return 0, err + } + return c.fd.writeToInet4(b, sa) + case syscall.AF_INET6: + sa, err := ipToSockaddrInet6(addr.IP, addr.Port, addr.Zone) + if err != nil { + return 0, err + } + return c.fd.writeToInet6(b, sa) + default: + return 0, &AddrError{Err: "invalid address family", Addr: addr.IP.String()} } - return c.fd.writeTo(b, sa) } func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { diff --git a/src/syscall/net_js.go b/src/syscall/net_js.go index ed462025bb..17799148bd 100644 --- a/src/syscall/net_js.go +++ b/src/syscall/net_js.go @@ -96,6 +96,14 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) error { return ENOSYS } +func SendtoInet4(fd int, p []byte, flags int, to SockaddrInet4) error { + return ENOSYS +} + +func SendtoInet6(fd int, p []byte, flags int, to SockaddrInet6) error { + return ENOSYS +} + func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) { return 0, 0, 0, nil, ENOSYS } diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go index 5b405b99b4..60aeae14de 100644 --- a/src/syscall/syscall_unix.go +++ b/src/syscall/syscall_unix.go @@ -292,6 +292,22 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { return } +func SendtoInet4(fd int, p []byte, flags int, to SockaddrInet4) (err error) { + ptr, n, err := to.sockaddr() + if err != nil { + return err + } + return sendto(fd, p, flags, ptr, n) +} + +func SendtoInet6(fd int, p []byte, flags int, to SockaddrInet6) (err error) { + ptr, n, err := to.sockaddr() + if err != nil { + return err + } + return sendto(fd, p, flags, ptr, n) +} + func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) { ptr, n, err := to.sockaddr() if err != nil { |