Skip to content

Commit

Permalink
perf(controlplane): introduce signal pool
Browse files Browse the repository at this point in the history
It helps to reduce the stack dynamic growth and the number of
allocations, which is good for performance.
  • Loading branch information
geyslan committed Jan 17, 2025
1 parent b1c5d24 commit 5e3ad59
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
34 changes: 31 additions & 3 deletions pkg/ebpf/controlplane/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controlplane
import (
"context"
"fmt"
"sync"
"time"

"github.com/aquasecurity/libbpfgo"
Expand All @@ -25,6 +26,7 @@ type Controller struct {
lostSignalChan chan uint64
bpfModule *libbpfgo.Module
signalBuffer *libbpfgo.PerfBuffer
signalPool *sync.Pool
cgroupManager *containers.Containers
processTree *proctree.ProcessTree
enrichDisabled bool
Expand All @@ -43,6 +45,11 @@ func NewController(
signalChan: make(chan []byte, 100),
lostSignalChan: make(chan uint64),
bpfModule: bpfModule,
signalPool: &sync.Pool{
New: func() interface{} {
return &signal{}
},
},
cgroupManager: cgroupManager,
processTree: procTree,
enrichDisabled: enrichDisabled,
Expand All @@ -69,16 +76,22 @@ func (ctrl *Controller) Run(ctx context.Context) {
for {
select {
case signalData := <-ctrl.signalChan:
signal := signal{}
signal := ctrl.getSignalFromPool()

// NOTE: override all the fields of the signal, to avoid any previous data.
err := signal.Unmarshal(signalData)
if err != nil {
logger.Errorw("error unmarshaling signal ebpf buffer", "error", err)
ctrl.putSignalInPool(signal)
continue
}

err = ctrl.processSignal(signal)
if err != nil {
logger.Errorw("error processing control plane signal", "error", err)
}

ctrl.putSignalInPool(signal)
case lost := <-ctrl.lostSignalChan:
logger.Warnw(fmt.Sprintf("Lost %d control plane signals", lost))
case <-ctrl.ctx.Done():
Expand All @@ -93,8 +106,10 @@ func (ctrl *Controller) Stop() error {
return nil
}

// Private

// processSignal processes a signal from the control plane.
func (ctrl *Controller) processSignal(signal signal) error {
func (ctrl *Controller) processSignal(signal *signal) error {
switch signal.id {
case events.SignalCgroupMkdir:
return ctrl.processCgroupMkdir(signal.args)
Expand All @@ -111,7 +126,20 @@ func (ctrl *Controller) processSignal(signal signal) error {
return nil
}

// Private
// getSignalFromPool gets a signal from the pool.
// signal certainly contains old data, so it must be updated before use.
func (ctrl *Controller) getSignalFromPool() *signal {
// revive:disable:unchecked-type-assertion
sig := ctrl.signalPool.Get().(*signal)
// revive:enable:unchecked-type-assertion

return sig
}

// putSignalInPool puts a signal back in the pool.
func (ctrl *Controller) putSignalInPool(sig *signal) {
ctrl.signalPool.Put(sig)
}

// debug prints the process tree every 5 seconds (for debugging purposes).
func (ctrl *Controller) debug(enable bool) {
Expand Down
4 changes: 4 additions & 0 deletions pkg/ebpf/controlplane/signal.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ func (sig *signal) Unmarshal(buffer []byte) error {
if err != nil {
return errfmt.Errorf("failed to decode signal event ID: %v", err)
}

sig.id = events.ID(eventIdUint32)

var argnum uint8
err = ebpfDecoder.DecodeUint8(&argnum)
if err != nil {
Expand All @@ -33,7 +35,9 @@ func (sig *signal) Unmarshal(buffer []byte) error {

evtFields := eventDefinition.GetFields()
evtName := eventDefinition.GetName()

sig.args = make([]trace.Argument, len(evtFields))

err = ebpfDecoder.DecodeArguments(sig.args, int(argnum), evtFields, evtName, sig.id)
if err != nil {
return errfmt.Errorf("failed to decode signal arguments: %v", err)
Expand Down

0 comments on commit 5e3ad59

Please sign in to comment.