Skip to content

Commit d934917

Browse files
josharianneild
authored andcommitted
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>
1 parent 8ff16c1 commit d934917

File tree

9 files changed

+220
-34
lines changed

9 files changed

+220
-34
lines changed

api/next.txt

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
2+
pkg syscall (darwin-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
3+
pkg syscall (darwin-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
4+
pkg syscall (darwin-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
5+
pkg syscall (freebsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
6+
pkg syscall (freebsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
7+
pkg syscall (freebsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
8+
pkg syscall (freebsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
9+
pkg syscall (freebsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
10+
pkg syscall (freebsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
11+
pkg syscall (freebsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
12+
pkg syscall (freebsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
13+
pkg syscall (freebsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
14+
pkg syscall (freebsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
15+
pkg syscall (freebsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
16+
pkg syscall (freebsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
17+
pkg syscall (linux-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
18+
pkg syscall (linux-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
19+
pkg syscall (linux-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
20+
pkg syscall (linux-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
21+
pkg syscall (linux-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
22+
pkg syscall (linux-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
23+
pkg syscall (linux-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
24+
pkg syscall (linux-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
25+
pkg syscall (linux-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
26+
pkg syscall (linux-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
27+
pkg syscall (linux-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
28+
pkg syscall (linux-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
29+
pkg syscall (netbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
30+
pkg syscall (netbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
31+
pkg syscall (netbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
32+
pkg syscall (netbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
33+
pkg syscall (netbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
34+
pkg syscall (netbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
35+
pkg syscall (netbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
36+
pkg syscall (netbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
37+
pkg syscall (netbsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
38+
pkg syscall (netbsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
39+
pkg syscall (netbsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
40+
pkg syscall (netbsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
41+
pkg syscall (netbsd-arm64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
42+
pkg syscall (netbsd-arm64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
43+
pkg syscall (netbsd-arm64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
44+
pkg syscall (netbsd-arm64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
45+
pkg syscall (openbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
46+
pkg syscall (openbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
47+
pkg syscall (openbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
48+
pkg syscall (openbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
49+
pkg syscall (openbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
50+
pkg syscall (openbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
51+
pkg syscall (openbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
52+
pkg syscall (openbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error

src/internal/poll/fd_unix.go

+52
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,58 @@ func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
327327
}
328328
}
329329

330+
// WriteToInet4 wraps the sendto network call for IPv4 addresses.
331+
func (fd *FD) WriteToInet4(p []byte, sa syscall.SockaddrInet4) (int, error) {
332+
if err := fd.writeLock(); err != nil {
333+
return 0, err
334+
}
335+
defer fd.writeUnlock()
336+
if err := fd.pd.prepareWrite(fd.isFile); err != nil {
337+
return 0, err
338+
}
339+
for {
340+
err := syscall.SendtoInet4(fd.Sysfd, p, 0, sa)
341+
if err == syscall.EINTR {
342+
continue
343+
}
344+
if err == syscall.EAGAIN && fd.pd.pollable() {
345+
if err = fd.pd.waitWrite(fd.isFile); err == nil {
346+
continue
347+
}
348+
}
349+
if err != nil {
350+
return 0, err
351+
}
352+
return len(p), nil
353+
}
354+
}
355+
356+
// WriteToInet6 wraps the sendto network call for IPv6 addresses.
357+
func (fd *FD) WriteToInet6(p []byte, sa syscall.SockaddrInet6) (int, error) {
358+
if err := fd.writeLock(); err != nil {
359+
return 0, err
360+
}
361+
defer fd.writeUnlock()
362+
if err := fd.pd.prepareWrite(fd.isFile); err != nil {
363+
return 0, err
364+
}
365+
for {
366+
err := syscall.SendtoInet6(fd.Sysfd, p, 0, sa)
367+
if err == syscall.EINTR {
368+
continue
369+
}
370+
if err == syscall.EAGAIN && fd.pd.pollable() {
371+
if err = fd.pd.waitWrite(fd.isFile); err == nil {
372+
continue
373+
}
374+
}
375+
if err != nil {
376+
return 0, err
377+
}
378+
return len(p), nil
379+
}
380+
}
381+
330382
// WriteTo wraps the sendto network call.
331383
func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
332384
if err := fd.writeLock(); err != nil {

src/internal/poll/fd_windows.go

+10
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,16 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
791791
return ntotal, nil
792792
}
793793

794+
// WriteTo wraps the sendto network call for IPv4.
795+
func (fd *FD) WriteToInet4(buf []byte, sa syscall.SockaddrInet4) (int, error) {
796+
return fd.WriteTo(buf, &sa)
797+
}
798+
799+
// WriteTo wraps the sendto network call for IPv6.
800+
func (fd *FD) WriteToInet6(buf []byte, sa syscall.SockaddrInet6) (int, error) {
801+
return fd.WriteTo(buf, &sa)
802+
}
803+
794804
// Call ConnectEx. This doesn't need any locking, since it is only
795805
// called when the descriptor is first created. This is here rather
796806
// than in the net package so that it can use fd.wop.

src/net/fd_posix.go

+12
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
8282
return n, wrapSyscallError(writeToSyscallName, err)
8383
}
8484

85+
func (fd *netFD) writeToInet4(p []byte, sa syscall.SockaddrInet4) (n int, err error) {
86+
n, err = fd.pfd.WriteToInet4(p, sa)
87+
runtime.KeepAlive(fd)
88+
return n, wrapSyscallError(writeToSyscallName, err)
89+
}
90+
91+
func (fd *netFD) writeToInet6(p []byte, sa syscall.SockaddrInet6) (n int, err error) {
92+
n, err = fd.pfd.WriteToInet6(p, sa)
93+
runtime.KeepAlive(fd)
94+
return n, wrapSyscallError(writeToSyscallName, err)
95+
}
96+
8597
func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
8698
n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
8799
runtime.KeepAlive(fd)

src/net/ipsock_posix.go

+46-30
Original file line numberDiff line numberDiff line change
@@ -142,42 +142,58 @@ func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, soty
142142
return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr, ctrlFn)
143143
}
144144

145+
func ipToSockaddrInet4(ip IP, port int) (syscall.SockaddrInet4, error) {
146+
if len(ip) == 0 {
147+
ip = IPv4zero
148+
}
149+
ip4 := ip.To4()
150+
if ip4 == nil {
151+
return syscall.SockaddrInet4{}, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
152+
}
153+
sa := syscall.SockaddrInet4{Port: port}
154+
copy(sa.Addr[:], ip4)
155+
return sa, nil
156+
}
157+
158+
func ipToSockaddrInet6(ip IP, port int, zone string) (syscall.SockaddrInet6, error) {
159+
// In general, an IP wildcard address, which is either
160+
// "0.0.0.0" or "::", means the entire IP addressing
161+
// space. For some historical reason, it is used to
162+
// specify "any available address" on some operations
163+
// of IP node.
164+
//
165+
// When the IP node supports IPv4-mapped IPv6 address,
166+
// we allow a listener to listen to the wildcard
167+
// address of both IP addressing spaces by specifying
168+
// IPv6 wildcard address.
169+
if len(ip) == 0 || ip.Equal(IPv4zero) {
170+
ip = IPv6zero
171+
}
172+
// We accept any IPv6 address including IPv4-mapped
173+
// IPv6 address.
174+
ip6 := ip.To16()
175+
if ip6 == nil {
176+
return syscall.SockaddrInet6{}, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
177+
}
178+
sa := syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))}
179+
copy(sa.Addr[:], ip6)
180+
return sa, nil
181+
}
182+
145183
func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
146184
switch family {
147185
case syscall.AF_INET:
148-
if len(ip) == 0 {
149-
ip = IPv4zero
150-
}
151-
ip4 := ip.To4()
152-
if ip4 == nil {
153-
return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
186+
sa, err := ipToSockaddrInet4(ip, port)
187+
if err != nil {
188+
return nil, err
154189
}
155-
sa := &syscall.SockaddrInet4{Port: port}
156-
copy(sa.Addr[:], ip4)
157-
return sa, nil
190+
return &sa, nil
158191
case syscall.AF_INET6:
159-
// In general, an IP wildcard address, which is either
160-
// "0.0.0.0" or "::", means the entire IP addressing
161-
// space. For some historical reason, it is used to
162-
// specify "any available address" on some operations
163-
// of IP node.
164-
//
165-
// When the IP node supports IPv4-mapped IPv6 address,
166-
// we allow a listener to listen to the wildcard
167-
// address of both IP addressing spaces by specifying
168-
// IPv6 wildcard address.
169-
if len(ip) == 0 || ip.Equal(IPv4zero) {
170-
ip = IPv6zero
171-
}
172-
// We accept any IPv6 address including IPv4-mapped
173-
// IPv6 address.
174-
ip6 := ip.To16()
175-
if ip6 == nil {
176-
return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
192+
sa, err := ipToSockaddrInet6(ip, port, zone)
193+
if err != nil {
194+
return nil, err
177195
}
178-
sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneCache.index(zone))}
179-
copy(sa.Addr[:], ip6)
180-
return sa, nil
196+
return &sa, nil
181197
}
182198
return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
183199
}

src/net/net_fake.go

+8
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,14 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
276276
return 0, syscall.ENOSYS
277277
}
278278

279+
func (fd *netFD) writeToInet4(p []byte, sa syscall.SockaddrInet4) (n int, err error) {
280+
return 0, syscall.ENOSYS
281+
}
282+
283+
func (fd *netFD) writeToInet6(p []byte, sa syscall.SockaddrInet6) (n int, err error) {
284+
return 0, syscall.ENOSYS
285+
}
286+
279287
func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
280288
return 0, 0, syscall.ENOSYS
281289
}

src/net/udpsock_posix.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,23 @@ func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
7676
if addr == nil {
7777
return 0, errMissingAddress
7878
}
79-
sa, err := addr.sockaddr(c.fd.family)
80-
if err != nil {
81-
return 0, err
79+
80+
switch c.fd.family {
81+
case syscall.AF_INET:
82+
sa, err := ipToSockaddrInet4(addr.IP, addr.Port)
83+
if err != nil {
84+
return 0, err
85+
}
86+
return c.fd.writeToInet4(b, sa)
87+
case syscall.AF_INET6:
88+
sa, err := ipToSockaddrInet6(addr.IP, addr.Port, addr.Zone)
89+
if err != nil {
90+
return 0, err
91+
}
92+
return c.fd.writeToInet6(b, sa)
93+
default:
94+
return 0, &AddrError{Err: "invalid address family", Addr: addr.IP.String()}
8295
}
83-
return c.fd.writeTo(b, sa)
8496
}
8597

8698
func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {

src/syscall/net_js.go

+8
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
9696
return ENOSYS
9797
}
9898

99+
func SendtoInet4(fd int, p []byte, flags int, to SockaddrInet4) error {
100+
return ENOSYS
101+
}
102+
103+
func SendtoInet6(fd int, p []byte, flags int, to SockaddrInet6) error {
104+
return ENOSYS
105+
}
106+
99107
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
100108
return 0, 0, 0, nil, ENOSYS
101109
}

src/syscall/syscall_unix.go

+16
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,22 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
292292
return
293293
}
294294

295+
func SendtoInet4(fd int, p []byte, flags int, to SockaddrInet4) (err error) {
296+
ptr, n, err := to.sockaddr()
297+
if err != nil {
298+
return err
299+
}
300+
return sendto(fd, p, flags, ptr, n)
301+
}
302+
303+
func SendtoInet6(fd int, p []byte, flags int, to SockaddrInet6) (err error) {
304+
ptr, n, err := to.sockaddr()
305+
if err != nil {
306+
return err
307+
}
308+
return sendto(fd, p, flags, ptr, n)
309+
}
310+
295311
func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
296312
ptr, n, err := to.sockaddr()
297313
if err != nil {

0 commit comments

Comments
 (0)