Skip to content

Commit 17c11ce

Browse files
committed
[tailscale1.16] 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 golang#43451 (cherry picked from golang.org/cl/331489) Change-Id: Ied15ff92268c652cf445836e0446025eaeb60cc9
1 parent a36b6d3 commit 17c11ce

10 files changed

+220
-34
lines changed

api/go1.tailscale.txt

+52
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,55 @@ pkg net/http, type Transport struct, OnProxyConnectResponse func(context.Context
22
pkg reflect, method (*MapIter) SetKey(Value)
33
pkg reflect, method (*MapIter) SetValue(Value)
44
pkg reflect, method (*MapIter) Reset(Value)
5+
pkg syscall (darwin-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
6+
pkg syscall (darwin-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
7+
pkg syscall (darwin-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
8+
pkg syscall (darwin-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
9+
pkg syscall (freebsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
10+
pkg syscall (freebsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
11+
pkg syscall (freebsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
12+
pkg syscall (freebsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
13+
pkg syscall (freebsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
14+
pkg syscall (freebsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
15+
pkg syscall (freebsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
16+
pkg syscall (freebsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
17+
pkg syscall (freebsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
18+
pkg syscall (freebsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
19+
pkg syscall (freebsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
20+
pkg syscall (freebsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
21+
pkg syscall (linux-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
22+
pkg syscall (linux-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
23+
pkg syscall (linux-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
24+
pkg syscall (linux-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
25+
pkg syscall (linux-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
26+
pkg syscall (linux-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
27+
pkg syscall (linux-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
28+
pkg syscall (linux-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
29+
pkg syscall (linux-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
30+
pkg syscall (linux-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
31+
pkg syscall (linux-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
32+
pkg syscall (linux-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
33+
pkg syscall (netbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
34+
pkg syscall (netbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
35+
pkg syscall (netbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
36+
pkg syscall (netbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
37+
pkg syscall (netbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
38+
pkg syscall (netbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
39+
pkg syscall (netbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
40+
pkg syscall (netbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
41+
pkg syscall (netbsd-arm), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
42+
pkg syscall (netbsd-arm), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
43+
pkg syscall (netbsd-arm-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
44+
pkg syscall (netbsd-arm-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
45+
pkg syscall (netbsd-arm64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
46+
pkg syscall (netbsd-arm64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
47+
pkg syscall (netbsd-arm64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
48+
pkg syscall (netbsd-arm64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
49+
pkg syscall (openbsd-386), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
50+
pkg syscall (openbsd-386), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
51+
pkg syscall (openbsd-386-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
52+
pkg syscall (openbsd-386-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
53+
pkg syscall (openbsd-amd64), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
54+
pkg syscall (openbsd-amd64), func SendtoInet6(int, []uint8, int, SockaddrInet6) error
55+
pkg syscall (openbsd-amd64-cgo), func SendtoInet4(int, []uint8, int, SockaddrInet4) error
56+
pkg syscall (openbsd-amd64-cgo), func SendtoInet6(int, []uint8, int, SockaddrInet6) error

api/next.txt

Whitespace-only changes.

src/internal/poll/fd_unix.go

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

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

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

src/net/ipsock_posix.go

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

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

src/net/net_fake.go

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

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

src/net/udpsock_posix.go

+16-4
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,23 @@ func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
7272
if addr == nil {
7373
return 0, errMissingAddress
7474
}
75-
sa, err := addr.sockaddr(c.fd.family)
76-
if err != nil {
77-
return 0, err
75+
76+
switch c.fd.family {
77+
case syscall.AF_INET:
78+
sa, err := ipToSockaddrInet4(addr.IP, addr.Port)
79+
if err != nil {
80+
return 0, err
81+
}
82+
return c.fd.writeToInet4(b, sa)
83+
case syscall.AF_INET6:
84+
sa, err := ipToSockaddrInet6(addr.IP, addr.Port, addr.Zone)
85+
if err != nil {
86+
return 0, err
87+
}
88+
return c.fd.writeToInet6(b, sa)
89+
default:
90+
return 0, &AddrError{Err: "invalid address family", Addr: addr.IP.String()}
7891
}
79-
return c.fd.writeTo(b, sa)
8092
}
8193

8294
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
@@ -95,6 +95,14 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
9595
return ENOSYS
9696
}
9797

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

src/syscall/syscall_unix.go

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

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

0 commit comments

Comments
 (0)