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
baced22
chore(bufferdecode): add DecodeArguments benchmark
geyslan Jan 13, 2025
e3e2e67
chore(bufferdecoder): set zero from def fields
geyslan Jan 13, 2025
db87a1a
perf: reduce events.Core lock contention
geyslan Jan 13, 2025
b28a532
chore(ebpf): add Benchmark_procTreeForkProcessor
geyslan Jan 14, 2025
e7c490c
perf(ebpf): improve procTreeForkProcessor
geyslan Jan 14, 2025
f3f7fa4
chore(controlplane): add procTreeForkProcessor bench
geyslan Jan 14, 2025
6dfc496
perf(controlplane): improve procTreeForkProcessor
geyslan Jan 14, 2025
7f7a34c
chore(ebpf): add Benchmark_procTreeExecProcessor
geyslan Jan 14, 2025
54ec91d
perf(ebpf): improve procTreeExecProcessor
geyslan Jan 14, 2025
32464dc
chore(controlplane): add Benchmark_procTreeExecProcessor
geyslan Jan 14, 2025
6eba0fd
perf(controlplane): improve procTreeExecProcessor
geyslan Jan 14, 2025
adad405
perf: remove unused ExecFeed interpreter fields
geyslan Jan 14, 2025
56e011d
chore: add Benchmark_procTreeExitProcessor
geyslan Jan 14, 2025
c585dcb
perf: improve procTreeExitProcessor
geyslan Jan 14, 2025
b2638f6
chore(events): add BenchmarkArgVal
geyslan Jan 14, 2025
e10c562
perf(events): improve ArgVal
geyslan Jan 14, 2025
e120838
perf(proctree): move functions from FeedFromFork
geyslan Jan 14, 2025
6bd9461
perf(proctree): introduce feed pools
geyslan Jan 14, 2025
6fd5d10
chore/perf(proctree): comment out exit fields
geyslan Jan 15, 2025
3c9b20e
chore(proctree): remove leftover
geyslan Jan 16, 2025
dbb0bd0
perf(proctree): reduce lock contention
geyslan Jan 16, 2025
a90089f
perf(proctree): change Thread concurrency control
geyslan Jan 16, 2025
6c255f3
perf(proctree): improve Process concurrency ctrl
geyslan Jan 16, 2025
aa98b6c
perf(controlplane): introduce signal pool
geyslan Jan 17, 2025
c1dd27e
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