wgengine/userspace: reduce allocations in getStatus

Two optimizations.

Use values instead of pointers.
We were using pointers to make track the "peer in progress" easier.
It's not too hard to do it manually, though.

Make two passes through the data, so that we can size our
return value accurately from the beginning.
This is cheap enough compared to the allocation,
which grows linearly in the number of peers,
that it is worth doing.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
pull/2687/head
Josh Bleecher Snyder 3 years ago committed by Josh Bleecher Snyder
parent af30897f0d
commit adf696172d

@ -921,8 +921,8 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
errc <- err
}()
pp := make(map[wgkey.Key]*ipnstate.PeerStatusLite)
p := &ipnstate.PeerStatusLite{}
pp := make(map[wgkey.Key]ipnstate.PeerStatusLite)
var p ipnstate.PeerStatusLite
var hst1, hst2, n int64
@ -954,11 +954,10 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
if err != nil {
return nil, fmt.Errorf("IpcGetOperation: invalid key in line %q", line)
}
p = &ipnstate.PeerStatusLite{}
pp[wgkey.Key(pk)] = p
key := tailcfg.NodeKey(pk)
p.NodeKey = key
if !p.NodeKey.IsZero() {
pp[wgkey.Key(p.NodeKey)] = p
}
p = ipnstate.PeerStatusLite{NodeKey: tailcfg.NodeKey(pk)}
case "rx_bytes":
n, err = mem.ParseInt(v, 10, 64)
p.RxBytes = n
@ -986,6 +985,9 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
} // else leave at time.IsZero()
}
}
if !p.NodeKey.IsZero() {
pp[wgkey.Key(p.NodeKey)] = p
}
if err := <-errc; err != nil {
return nil, fmt.Errorf("IpcGetOperation: %v", err)
}
@ -993,10 +995,19 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
e.mu.Lock()
defer e.mu.Unlock()
var peers []ipnstate.PeerStatusLite
// Do two passes, one to calculate size and the other to populate.
// This code is sensitive to allocations.
npeers := 0
for _, pk := range e.peerSequence {
if _, ok := pp[pk]; ok { // ignore idle ones not in wireguard-go's config
npeers++
}
}
peers := make([]ipnstate.PeerStatusLite, 0, npeers)
for _, pk := range e.peerSequence {
if p, ok := pp[pk]; ok { // ignore idle ones not in wireguard-go's config
peers = append(peers, *p)
peers = append(peers, p)
}
}

Loading…
Cancel
Save