diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000..c2fdf254 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-21 - Registry Event Loop Optimization +**Learning:** The `handleEvents` loop in `Registry` naively iterated all containers for every `TCPRetransmit` event, causing high CPU/allocations under network stress. +**Action:** Implemented PID-based fast path lookup and slice reuse to optimize the hot path. diff --git a/containers/registry.go b/containers/registry.go index 4e41fad5..79599cb1 100644 --- a/containers/registry.go +++ b/containers/registry.go @@ -168,6 +168,7 @@ func (r *Registry) Close() { func (r *Registry) handleEvents(ch <-chan ebpftracer.Event) { gcTicker := time.NewTicker(gcInterval) defer gcTicker.Stop() + var containerCache []*Container for { select { case now := <-gcTicker.C: @@ -357,15 +358,30 @@ func (r *Registry) handleEvents(ch <-chan ebpftracer.Event) { c.onConnectionClose(e) } case ebpftracer.EventTypeTCPRetransmit: - r.containerLock.RLock() - containers := make([]*Container, 0, len(r.containersById)) - for _, c := range r.containersById { - containers = append(containers, c) + handled := false + if e.Pid != 0 { + r.containerLock.RLock() + c := r.containersByPid[e.Pid] + r.containerLock.RUnlock() + if c != nil && c.onRetransmission(e.SrcAddr, e.DstAddr) { + handled = true + } } - r.containerLock.RUnlock() - for _, c := range containers { - if c.onRetransmission(e.SrcAddr, e.DstAddr) { - break + if !handled { + r.containerLock.RLock() + if cap(containerCache) < len(r.containersById) { + containerCache = make([]*Container, 0, len(r.containersById)) + } else { + containerCache = containerCache[:0] + } + for _, c := range r.containersById { + containerCache = append(containerCache, c) + } + r.containerLock.RUnlock() + for _, c := range containerCache { + if c.onRetransmission(e.SrcAddr, e.DstAddr) { + break + } } } case ebpftracer.EventTypeL7Request: