Use atomic.Value for Stack.tcpProbeFunc.
b/166980357#comment56 shows: - 837 goroutines blocked in: gvisor/pkg/sync/sync.(*RWMutex).Lock gvisor/pkg/tcpip/stack/stack.(*Stack).StartTransportEndpointCleanup gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).cleanupLocked gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).completeWorkerLocked gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).protocolMainLoop.func1 gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).protocolMainLoop - 695 goroutines blocked in: gvisor/pkg/sync/sync.(*RWMutex).Lock gvisor/pkg/tcpip/stack/stack.(*Stack).CompleteTransportEndpointCleanup gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).cleanupLocked gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).completeWorkerLocked gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).protocolMainLoop.func1 gvisor/pkg/tcpip/transport/tcp/tcp.(*endpoint).protocolMainLoop - 3882 goroutines blocked in: gvisor/pkg/sync/sync.(*RWMutex).Lock gvisor/pkg/tcpip/stack/stack.(*Stack).GetTCPProbe gvisor/pkg/tcpip/transport/tcp/tcp.newEndpoint gvisor/pkg/tcpip/transport/tcp/tcp.(*protocol).NewEndpoint gvisor/pkg/tcpip/stack/stack.(*Stack).NewEndpoint All of these are contending on Stack.mu. Stack.StartTransportEndpointCleanup() and Stack.CompleteTransportEndpointCleanup() insert/delete TransportEndpoints in a map (Stack.cleanupEndpoints), and the former also does endpoint unregistration while holding Stack.mu, so it's not immediately clear how feasible it is to replace the map with a mutex-less implementation or how much doing so would help. However, Stack.GetTCPProbe() just reads a function object (Stack.tcpProbeFunc) that is almost always nil (as far as I can tell, Stack.AddTCPProbe() is only called in tests), and it's called for every new TCP endpoint. So converting it to an atomic.Value should significantly reduce contention on Stack.mu, improving TCP endpoint creation latency and allowing TCP endpoint cleanup to proceed. PiperOrigin-RevId: 330004140
This commit is contained in:
parent
30c20df76f
commit
76e51c8b9a
|
@ -429,7 +429,7 @@ type Stack struct {
|
||||||
|
|
||||||
// If not nil, then any new endpoints will have this probe function
|
// If not nil, then any new endpoints will have this probe function
|
||||||
// invoked everytime they receive a TCP segment.
|
// invoked everytime they receive a TCP segment.
|
||||||
tcpProbeFunc TCPProbeFunc
|
tcpProbeFunc atomic.Value // TCPProbeFunc
|
||||||
|
|
||||||
// clock is used to generate user-visible times.
|
// clock is used to generate user-visible times.
|
||||||
clock tcpip.Clock
|
clock tcpip.Clock
|
||||||
|
@ -1795,18 +1795,17 @@ func (s *Stack) TransportProtocolInstance(num tcpip.TransportProtocolNumber) Tra
|
||||||
// guarantee provided on which probe will be invoked. Ideally this should only
|
// guarantee provided on which probe will be invoked. Ideally this should only
|
||||||
// be called once per stack.
|
// be called once per stack.
|
||||||
func (s *Stack) AddTCPProbe(probe TCPProbeFunc) {
|
func (s *Stack) AddTCPProbe(probe TCPProbeFunc) {
|
||||||
s.mu.Lock()
|
s.tcpProbeFunc.Store(probe)
|
||||||
s.tcpProbeFunc = probe
|
|
||||||
s.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTCPProbe returns the TCPProbeFunc if installed with AddTCPProbe, nil
|
// GetTCPProbe returns the TCPProbeFunc if installed with AddTCPProbe, nil
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func (s *Stack) GetTCPProbe() TCPProbeFunc {
|
func (s *Stack) GetTCPProbe() TCPProbeFunc {
|
||||||
s.mu.Lock()
|
p := s.tcpProbeFunc.Load()
|
||||||
p := s.tcpProbeFunc
|
if p == nil {
|
||||||
s.mu.Unlock()
|
return nil
|
||||||
return p
|
}
|
||||||
|
return p.(TCPProbeFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTCPProbe removes an installed TCP probe.
|
// RemoveTCPProbe removes an installed TCP probe.
|
||||||
|
@ -1815,9 +1814,8 @@ func (s *Stack) GetTCPProbe() TCPProbeFunc {
|
||||||
// have a probe attached. Endpoints already created will continue to invoke
|
// have a probe attached. Endpoints already created will continue to invoke
|
||||||
// TCP probe.
|
// TCP probe.
|
||||||
func (s *Stack) RemoveTCPProbe() {
|
func (s *Stack) RemoveTCPProbe() {
|
||||||
s.mu.Lock()
|
// This must be TCPProbeFunc(nil) because atomic.Value.Store(nil) panics.
|
||||||
s.tcpProbeFunc = nil
|
s.tcpProbeFunc.Store(TCPProbeFunc(nil))
|
||||||
s.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinGroup joins the given multicast group on the given NIC.
|
// JoinGroup joins the given multicast group on the given NIC.
|
||||||
|
|
Loading…
Reference in New Issue