Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve cpu/memory (proctree wise) #4503

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
34f4950
chore(bufferdecode): add DecodeArguments benchmark
geyslan Jan 13, 2025
76902b5
chore(bufferdecoder): set zero from def fields
geyslan Jan 13, 2025
000e122
perf: reduce events.Core lock contention
geyslan Jan 13, 2025
d87ed62
chore(ebpf): add Benchmark_procTreeForkProcessor
geyslan Jan 14, 2025
d9de86e
perf(ebpf): improve procTreeForkProcessor
geyslan Jan 14, 2025
34fe1de
chore(controlplane): add procTreeForkProcessor bench
geyslan Jan 14, 2025
91d7df0
perf(controlplane): improve procTreeForkProcessor
geyslan Jan 14, 2025
597171c
chore(ebpf): add Benchmark_procTreeExecProcessor
geyslan Jan 14, 2025
8d28c34
perf(ebpf): improve procTreeExecProcessor
geyslan Jan 14, 2025
3830a32
chore(controlplane): add Benchmark_procTreeExecProcessor
geyslan Jan 14, 2025
dd32475
perf(controlplane): improve procTreeExecProcessor
geyslan Jan 14, 2025
edf331a
perf: remove unused ExecFeed interpreter fields
geyslan Jan 14, 2025
861103c
chore: add Benchmark_procTreeExitProcessor
geyslan Jan 14, 2025
d40a345
perf: improve procTreeExitProcessor
geyslan Jan 14, 2025
572343c
chore(events): add BenchmarkArgVal
geyslan Jan 14, 2025
b25ac63
perf(events): improve ArgVal
geyslan Jan 14, 2025
ad5532e
perf(proctree): move functions from FeedFromFork
geyslan Jan 14, 2025
e9bb176
perf(proctree): introduce feed pools
geyslan Jan 14, 2025
3e6473d
chore/perf(proctree): comment out exit fields
geyslan Jan 15, 2025
f6d324d
chore(proctree): remove leftover
geyslan Jan 16, 2025
c3447a6
perf(proctree): reduce lock contention
geyslan Jan 16, 2025
5f326d5
perf(proctree): change Thread concurrency control
geyslan Jan 16, 2025
b1c5d24
perf(proctree): improve Process concurrency ctrl
geyslan Jan 16, 2025
5e3ad59
perf(controlplane): introduce signal pool
geyslan Jan 17, 2025
314326e
chore(cmd): add proctree disable-procfs
geyslan Jan 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/docs/advanced/data-sources/builtin/process-tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ Example:
--proctree thread-cache=16384 | will cache up to 16384 threads in the tree (LRU cache).
--proctree process-cache-ttl=60 | will set the process cache element TTL to 60 seconds.
--proctree thread-cache-ttl=60 | will set the thread cache element TTL to 60 seconds.
--proctree disable-procfs-query | Will disable procfs quering during runtime
--proctree disable-procfs | will disable procfs entirely.
--proctree disable-procfs-query | will disable procfs quering during runtime.

Use comma OR use the flag multiple times to choose multiple options:
--proctree source=A,process-cache=B,thread-cache=C
Expand Down
2 changes: 1 addition & 1 deletion pkg/bufferdecoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (decoder *EbpfDecoder) DecodeArguments(args []trace.Argument, argnum int, e
for i := 0; i < len(evtFields); i++ {
if args[i].Value == nil {
args[i].ArgMeta = evtFields[i]
args[i].Value = args[i].Zero
args[i].Value = evtFields[i].Zero
}
}
return nil
Expand Down
78 changes: 78 additions & 0 deletions pkg/bufferdecoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/stretchr/testify/assert"

"github.com/aquasecurity/tracee/pkg/events"
"github.com/aquasecurity/tracee/types/trace"
)

Expand Down Expand Up @@ -1005,3 +1006,80 @@ func BenchmarkBinaryMprotectWriteMeta(*testing.B) {
binary.Read(binBuf, binary.LittleEndian, &s)
}
}

func BenchmarkDecodeArguments(b *testing.B) {
/*
args := []trace.Argument{
{
Name: "arg1",
Type: "u64",
Value: 1,
},
{
Name: "arg2",
Type: "u64",
Value: 2,
},
{
Name: "arg3",
Type: "u64",
Value: 3,
},
...
}
******************
buffer is the []byte representation of args instance
******************
*/

buffer := []byte{
0, 1, 0, 0, 0, 0, 0, 0, 0, // arg1
1, 2, 0, 0, 0, 0, 0, 0, 0, // arg2
2, 3, 0, 0, 0, 0, 0, 0, 0, // arg3
3, 4, 0, 0, 0, 0, 0, 0, 0, // arg4
4, 5, 0, 0, 0, 0, 0, 0, 0, // arg5
5, 6, 0, 0, 0, 0, 0, 0, 0, // arg6
6, 7, 0, 0, 0, 0, 0, 0, 0, // arg7
7, 8, 0, 0, 0, 0, 0, 0, 0, // arg8
}
evtFields := []trace.ArgMeta{
{Name: "arg1", Type: "u64", Zero: 0},
{Name: "arg2", Type: "u64", Zero: 0},
{Name: "arg3", Type: "u64", Zero: 0},
{Name: "arg4", Type: "u64", Zero: 0},
{Name: "arg5", Type: "u64", Zero: 0},
{Name: "arg6", Type: "u64", Zero: 0},
{Name: "arg7", Type: "u64", Zero: 0},
{Name: "arg8", Type: "u64", Zero: 0},
}

// decode half of the arguments leaving the rest to be populated as zero values
argnum := len(evtFields) / 2

evtVersion := events.NewVersion(1, 0, 0)
evtName := "test"
eventId := events.ID(0)
evtDef := events.NewDefinition(
eventId,
eventId+1000,
evtName,
evtVersion,
"",
"",
false,
false,
[]string{},
events.Dependencies{},
evtFields, // fields
nil,
)

events.Core.AddBatch(map[events.ID]events.Definition{eventId: evtDef})

b.ResetTimer()
for i := 0; i < b.N; i++ {
decoder := New(buffer)
args := make([]trace.Argument, len(evtFields))
_ = decoder.DecodeArguments(args, argnum, evtFields, evtName, eventId)
}
}
10 changes: 8 additions & 2 deletions pkg/cmd/flags/proctree.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ Example:
both | process tree is built from both events and signals.
--proctree process-cache=8192 | will cache up to 8192 processes in the tree (LRU cache).
--proctree thread-cache=4096 | will cache up to 4096 threads in the tree (LRU cache).
--proctree disable-procfs-query | Will disable procfs queries during runtime
--proctree disable-procfs | will disable procfs entirely.
--proctree disable-procfs-query | will disable procfs quering during runtime.

Use comma OR use the flag multiple times to choose multiple options:
--proctree source=A,process-cache=B,thread-cache=C
Expand Down Expand Up @@ -93,7 +94,12 @@ func PrepareProcTree(cacheSlice []string) (proctree.ProcTreeConfig, error) {
cacheSet = true
continue
}
if strings.HasPrefix(value, "disable-procfs-query") {
if value == "disable-procfs" {
config.ProcfsInitialization = false
config.ProcfsQuerying = false
continue
}
if value == "disable-procfs-query" {
config.ProcfsQuerying = false
continue
}
Expand Down
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
Loading
Loading