From 3697609aaa1f18b918080f1557b65022e94564be Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sat, 22 Oct 2022 11:21:10 -0700 Subject: [PATCH] portlist: remove unix.Readlink allocs on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta GetList-8 11.2ms ± 5% 11.1ms ± 3% ~ (p=0.661 n=10+9) name old alloc/op new alloc/op delta GetList-8 83.3kB ± 1% 67.4kB ± 1% -19.05% (p=0.000 n=10+10) name old allocs/op new allocs/op delta GetList-8 2.89k ± 2% 2.19k ± 1% -24.24% (p=0.000 n=10+10) (real issue is we're calling this code as much as we are, but easy enough to make it efficient because it'll still need to be called sometimes in any case) Updates #5958 Change-Id: I90c20278d73e80315a840aed1397d24faa308d93 Signed-off-by: Brad Fitzpatrick --- cmd/tailscaled/depaware.txt | 2 +- portlist/portlist_linux.go | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index d9f7bd5e6..6dfd22671 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -243,7 +243,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/net/tunstats from tailscale.com/net/tstun+ tailscale.com/net/wsconn from tailscale.com/control/controlhttp+ tailscale.com/paths from tailscale.com/ipn/ipnlocal+ - tailscale.com/portlist from tailscale.com/ipn/ipnlocal + 💣 tailscale.com/portlist from tailscale.com/ipn/ipnlocal tailscale.com/safesocket from tailscale.com/client/tailscale+ tailscale.com/smallzstd from tailscale.com/ipn/ipnserver+ LD 💣 tailscale.com/ssh/tailssh from tailscale.com/cmd/tailscaled diff --git a/portlist/portlist_linux.go b/portlist/portlist_linux.go index a40fb9909..4d5faabbf 100644 --- a/portlist/portlist_linux.go +++ b/portlist/portlist_linux.go @@ -18,6 +18,7 @@ import ( "sync/atomic" "syscall" "time" + "unsafe" "go4.org/mem" "golang.org/x/sys/unix" @@ -215,6 +216,8 @@ func addProcesses(pl []Port) ([]Port, error) { pm[pl[i].inode] = &pl[i] } + var pathBuf []byte + err := foreachPID(func(pid string) error { fdPath := fmt.Sprintf("/proc/%s/fd", pid) @@ -251,8 +254,9 @@ func addProcesses(pl []Port) ([]Port, error) { return fmt.Errorf("addProcesses.readDir: %w", err) } for _, fd := range fds { - n, err := unix.Readlink(fmt.Sprintf("/proc/%s/fd/%s", pid, fd), targetBuf) - if err != nil { + pathBuf = fmt.Appendf(pathBuf[:0], "/proc/%s/fd/%s\x00", pid, fd) + n, ok := readlink(pathBuf, targetBuf) + if !ok { // Not a symlink or no permission. // Skip it. continue @@ -337,3 +341,22 @@ func fieldIndex(line []byte, n int) int { } return skip } + +// path must be null terminated. +func readlink(path, buf []byte) (n int, ok bool) { + if len(buf) == 0 || len(path) < 2 || path[len(path)-1] != 0 { + return 0, false + } + var dirfd int = unix.AT_FDCWD + r0, _, e1 := unix.Syscall6(unix.SYS_READLINKAT, + uintptr(dirfd), + uintptr(unsafe.Pointer(&path[0])), + uintptr(unsafe.Pointer(&buf[0])), + uintptr(len(buf)), + 0, 0) + n = int(r0) + if e1 != 0 { + return 0, false + } + return n, true +}