Add an osImpl interface that can be stateful and thus more efficient
between calls. It will later be implemented by all OSes but for now
this change only adds a Linux implementation.
Remove Port.inode. It was only used by Linux and moves into its osImpl.
Don't reopen /proc/net/* files on each run. Turns out you can just
keep then open and seek to the beginning and reread and the contents
are fresh.
name old time/op new time/op delta
GetListIncremental-8 7.29ms ± 2% 6.53ms ± 1% -10.50% (p=0.000 n=9+9)
name old alloc/op new alloc/op delta
GetListIncremental-8 1.30kB ±13% 0.70kB ± 5% -46.38% (p=0.000 n=9+10)
name old allocs/op new allocs/op delta
GetListIncremental-8 33.2 ±11% 18.0 ± 0% -45.82% (p=0.000 n=9+10)
Updates #5958
Change-Id: I4be83463cbd23c2e2fa5d0bdf38560004f53401b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
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 <bradfitz@tailscale.com>
Make Linux parsePorts also an append-style API and attach it to
caller's provided append base memory.
And add a little string intern pool in front of the []byte to string
for inode names.
name old time/op new time/op delta
GetList-8 11.1ms ± 4% 9.8ms ± 6% -11.68% (p=0.000 n=9+10)
name old alloc/op new alloc/op delta
GetList-8 92.8kB ± 2% 79.7kB ± 0% -14.11% (p=0.000 n=10+9)
name old allocs/op new allocs/op delta
GetList-8 2.94k ± 1% 2.76k ± 0% -6.16% (p=0.000 n=10+10)
More coming. (the bulk of the allocations are in addProcesses and
filesystem operations, most of which we should usually be able to
skip)
Updates #5958
Change-Id: I3f0c03646d314a16fef7f8346aefa7d5c96701e7
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
In prep for reducing garbage, being able to reuse memory. So far this
doesn't actually reuse much. This is just changing signatures around.
But some improvement in any case:
bradfitz@tsdev:~/src/tailscale.com$ ~/go/bin/benchstat before after
name old time/op new time/op delta
GetList-8 11.8ms ± 9% 9.9ms ± 3% -15.98% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
GetList-8 99.5kB ± 2% 91.9kB ± 0% -7.62% (p=0.000 n=9+9)
name old allocs/op new allocs/op delta
GetList-8 3.05k ± 1% 2.93k ± 0% -3.83% (p=0.000 n=8+9)
More later, once parsers can reuse strings from previous parses.
Updates #5958
Change-Id: I76cd5048246dd24d11c4e263d8bb8041747fb2b0
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The io/ioutil package has been deprecated as of Go 1.16 [1]. This commit
replaces the existing io/ioutil functions with their new definitions in
io and os packages.
Reference: https://golang.org/doc/go1.16#ioutil
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
Avoid splitting fields in the common case. Field splitting was 84% of
the overall CPU.
name old time/op new time/op delta
ParsePorts-6 33.3ms ± 2% 6.3ms ± 4% -80.97% (p=0.000 n=9+10)
name old alloc/op new alloc/op delta
ParsePorts-6 520B ±79% 408B ± 0% -21.49% (p=0.046 n=10+8)
name old allocs/op new allocs/op delta
ParsePorts-6 7.00 ± 0% 7.00 ± 0% ~ (all equal)
Updates tailscale/corp#2566
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Notably, it no longer allocates proportional to the number of open
sockets on the machine. Any alloc reduction numbers are a little
contrived with such a reduction but e.g. on a machine with 50,000
connections open:
name old time/op new time/op delta
ParsePorts-6 57.7ms ± 6% 32.8ms ± 3% -43.04% (p=0.000 n=9+10)
name old alloc/op new alloc/op delta
ParsePorts-6 24.0MB ± 0% 0.0MB ± 0% -100.00% (p=0.000 n=10+9)
name old allocs/op new allocs/op delta
ParsePorts-6 100k ± 0% 0k ± 0% -99.99% (p=0.000 n=10+10)
Updates tailscale/corp#2566
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This is important because some of those v6 sockets are actually
dual-stacked sockets, so this is our only chance of discovering
some services.
Fixes#1443.
Signed-off-by: David Anderson <danderson@tailscale.com>
This could happen when a process disappeared while we were reading its
file descriptor list.
I was able to replicate the problem by running this in another
terminal:
while :; do for i in $(seq 10); do
/bin/true & done >&/dev/null; wait >&/dev/null;
done
And then running the portlist tests thousands of times.
Fixes#339.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
staticcheck used to fail on macOS (and presumably windows) due to a
variable declared in a common package that was only used by the Linux
build, which would prevent `redo pr` from passing on Mac. Moved variable
declaration from the common file to the Linux-specific one to resolve
the compiler complaint.
Signed-off-by: Wendi Yu <wendi.yu@yahoo.ca>
I noticed portlist when looking at some profiles and hadn't looked at
the code much before. This is a first pass over it. It allocates a
fair bit. More love remains, but this does a bit:
name old time/op new time/op delta
GetList-8 9.92ms ± 8% 9.64ms ±12% ~ (p=0.247 n=10+10)
name old alloc/op new alloc/op delta
GetList-8 931kB ± 0% 869kB ± 0% -6.70% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
GetList-8 4.59k ± 0% 3.69k ± 1% -19.71% (p=0.000 n=10+10)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>