tailscale/metrics/fds_linux.go
Brad Fitzpatrick db2cc393af util/dirwalk, metrics, portlist: add new package for fast directory walking
This is similar to the golang.org/x/tools/internal/fastwalk I'd
previously written but not recursive and using mem.RO.

The metrics package already had some Linux-specific directory reading
code in it. Move that out to a new general package that can be reused
by portlist too, which helps its scanning of all /proc files:

    name                old time/op    new time/op    delta
    FindProcessNames-8    2.79ms ± 6%    2.45ms ± 7%  -12.11%  (p=0.000 n=10+10)

    name                old alloc/op   new alloc/op   delta
    FindProcessNames-8    62.9kB ± 0%    33.5kB ± 0%  -46.76%  (p=0.000 n=9+10)

    name                old allocs/op  new allocs/op  delta
    FindProcessNames-8     2.25k ± 0%     0.38k ± 0%  -82.98%  (p=0.000 n=9+10)

Change-Id: I75db393032c328f12d95c39f71c9742c375f207a
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-11-05 16:26:51 -07:00

43 lines
907 B
Go

// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package metrics
import (
"io/fs"
"sync"
"go4.org/mem"
"tailscale.com/util/dirwalk"
)
// counter is a reusable counter for counting file descriptors.
type counter struct {
n int
// cb is the (*counter).count method value. Creating it allocates,
// so we have to save it away and use a sync.Pool to keep currentFDs
// amortized alloc-free.
cb func(name mem.RO, de fs.DirEntry) error
}
var counterPool = &sync.Pool{New: func() any {
c := new(counter)
c.cb = c.count
return c
}}
func (c *counter) count(name mem.RO, de fs.DirEntry) error {
c.n++
return nil
}
func currentFDs() int {
c := counterPool.Get().(*counter)
defer counterPool.Put(c)
c.n = 0
dirwalk.WalkShallow(mem.S("/proc/self/fd"), c.cb)
return c.n
}