Skip to content

Commit 4b4fb83

Browse files
committed
net: reduce allocation size in ReadFromUDP (experiment)
Switch to concrete types. Bring your own object to fill in. Allocate just enough for the IP byte slice. The allocation is now just 4 bytes, which puts it in the tiny allocator, which is much faster. name old time/op new time/op delta WriteToReadFromUDP-8 5.59µs ±10% 6.03µs ± 9% +7.80% (p=0.004 n=9+10) name old alloc/op new alloc/op delta WriteToReadFromUDP-8 32.0B ± 0% 4.0B ± 0% -87.50% (p=0.000 n=10+10) name old allocs/op new allocs/op delta WriteToReadFromUDP-8 1.00 ± 0% 1.00 ± 0% ~ (all equal) Change-Id: Ief506f891b401d28715d22dce6ebda037941924e
1 parent 1074dae commit 4b4fb83

File tree

4 files changed

+112
-8
lines changed

4 files changed

+112
-8
lines changed

src/internal/poll/fd_unix.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,60 @@ func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
229229
}
230230
}
231231

232+
// ReadFrom wraps the recvfrom network call.
233+
func (fd *FD) ReadFromInet4(p []byte, from *syscall.SockaddrInet4) (int, error) {
234+
if err := fd.readLock(); err != nil {
235+
return 0, err
236+
}
237+
defer fd.readUnlock()
238+
if err := fd.pd.prepareRead(fd.isFile); err != nil {
239+
return 0, err
240+
}
241+
for {
242+
n, err := syscall.RecvfromInet4(fd.Sysfd, p, 0, from)
243+
if err != nil {
244+
if err == syscall.EINTR {
245+
continue
246+
}
247+
n = 0
248+
if err == syscall.EAGAIN && fd.pd.pollable() {
249+
if err = fd.pd.waitRead(fd.isFile); err == nil {
250+
continue
251+
}
252+
}
253+
}
254+
err = fd.eofError(n, err)
255+
return n, err
256+
}
257+
}
258+
259+
// ReadFrom wraps the recvfrom network call.
260+
func (fd *FD) ReadFromInet6(p []byte, from *syscall.SockaddrInet6) (int, error) {
261+
if err := fd.readLock(); err != nil {
262+
return 0, err
263+
}
264+
defer fd.readUnlock()
265+
if err := fd.pd.prepareRead(fd.isFile); err != nil {
266+
return 0, err
267+
}
268+
for {
269+
n, err := syscall.RecvfromInet6(fd.Sysfd, p, 0, from)
270+
if err != nil {
271+
if err == syscall.EINTR {
272+
continue
273+
}
274+
n = 0
275+
if err == syscall.EAGAIN && fd.pd.pollable() {
276+
if err = fd.pd.waitRead(fd.isFile); err == nil {
277+
continue
278+
}
279+
}
280+
}
281+
err = fd.eofError(n, err)
282+
return n, err
283+
}
284+
}
285+
232286
// ReadMsg wraps the recvmsg network call.
233287
func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, error) {
234288
if err := fd.readLock(); err != nil {

src/net/fd_posix.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
6363
return n, sa, wrapSyscallError(readFromSyscallName, err)
6464
}
6565

66+
func (fd *netFD) readFromInet4(p []byte, from *syscall.SockaddrInet4) (n int, err error) {
67+
n, err = fd.pfd.ReadFromInet4(p, from)
68+
runtime.KeepAlive(fd)
69+
return n, wrapSyscallError(readFromSyscallName, err)
70+
}
71+
72+
func (fd *netFD) readFromInet6(p []byte, from *syscall.SockaddrInet6) (n int, err error) {
73+
n, err = fd.pfd.ReadFromInet6(p, from)
74+
runtime.KeepAlive(fd)
75+
return n, wrapSyscallError(readFromSyscallName, err)
76+
}
77+
6678
func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
6779
n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
6880
runtime.KeepAlive(fd)

src/net/udpsock_posix.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,22 @@ func (a *UDPAddr) toLocal(net string) sockaddr {
4242
return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
4343
}
4444

45-
func (c *UDPConn) readFrom(b []byte, addr *UDPAddr) (int, *UDPAddr, error) {
46-
n, sa, err := c.fd.readFrom(b)
47-
switch sa := sa.(type) {
48-
case *syscall.SockaddrInet4:
49-
*addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
50-
case *syscall.SockaddrInet6:
51-
*addr = UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
45+
func (c *UDPConn) readFrom(b []byte, a *UDPAddr) (n int, addr *UDPAddr, err error) {
46+
switch c.fd.family {
47+
case syscall.AF_INET:
48+
var from syscall.SockaddrInet4
49+
n, err = c.fd.readFromInet4(b, &from)
50+
ipbuf := make([]byte, 4)
51+
copy(ipbuf, from.Addr[:])
52+
*a = UDPAddr{IP: ipbuf, Port: from.Port}
53+
case syscall.AF_INET6:
54+
var from syscall.SockaddrInet6
55+
n, err = c.fd.readFromInet6(b, &from)
56+
ipbuf := make([]byte, 16)
57+
copy(ipbuf, from.Addr[:])
58+
*a = UDPAddr{IP: ipbuf, Port: from.Port, Zone: zoneCache.name(int(from.ZoneId))}
5259
}
53-
return n, addr, err
60+
return n, a, err
5461
}
5562

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

src/syscall/syscall_unix.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,37 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
290290
return
291291
}
292292

293+
func RecvfromInet4(fd int, p []byte, flags int, from *SockaddrInet4) (n int, err error) {
294+
var rsa RawSockaddrAny
295+
var socklen _Socklen = SizeofSockaddrAny
296+
if n, err = recvfrom(fd, p, flags, &rsa, &socklen); err != nil {
297+
return
298+
}
299+
pp := (*RawSockaddrInet4)(unsafe.Pointer(&rsa))
300+
port := (*[2]byte)(unsafe.Pointer(&pp.Port))
301+
from.Port = int(port[0])<<8 + int(port[1])
302+
for i := 0; i < len(from.Addr); i++ {
303+
from.Addr[i] = pp.Addr[i]
304+
}
305+
return
306+
}
307+
308+
func RecvfromInet6(fd int, p []byte, flags int, from *SockaddrInet6) (n int, err error) {
309+
var rsa RawSockaddrAny
310+
var socklen _Socklen = SizeofSockaddrAny
311+
if n, err = recvfrom(fd, p, flags, &rsa, &socklen); err != nil {
312+
return
313+
}
314+
pp := (*RawSockaddrInet6)(unsafe.Pointer(&rsa))
315+
port := (*[2]byte)(unsafe.Pointer(&pp.Port))
316+
from.Port = int(port[0])<<8 + int(port[1])
317+
from.ZoneId = pp.Scope_id
318+
for i := 0; i < len(pp.Addr); i++ {
319+
from.Addr[i] = pp.Addr[i]
320+
}
321+
return
322+
}
323+
293324
func SendtoInet4(fd int, p []byte, flags int, to SockaddrInet4) (err error) {
294325
ptr, n, err := to.sockaddr()
295326
if err != nil {

0 commit comments

Comments
 (0)