-
Notifications
You must be signed in to change notification settings - Fork 111
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
Reduce BPF memory consumption #620
Changes from 1 commit
adb2beb
afe39c0
c35dd1d
c40a512
fba6865
df25eca
35e9879
2d4b3ed
635b656
8cbbd49
6e38828
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#ifndef KRINGBUF_H | ||
#define KRINGBUF_H | ||
|
||
#include "utils.h" | ||
|
||
// These need to line up with some Go identifiers: | ||
// EventTypeHTTP, EventTypeGRPC, EventTypeHTTPClient, EventTypeGRPCClient, EventTypeSQLClient | ||
#define EVENT_HTTP_REQUEST 1 | ||
#define EVENT_GRPC_REQUEST 2 | ||
#define EVENT_HTTP_CLIENT 3 | ||
#define EVENT_GRPC_CLIENT 4 | ||
#define EVENT_SQL_CLIENT 5 | ||
|
||
// setting here the following map definitions without pinning them to a global namespace | ||
// would lead that services running both HTTP and GRPC server would duplicate | ||
// the events ringbuffer and goroutines map. | ||
// This is an edge inefficiency that allows us avoiding the gotchas of | ||
// pinning maps to the global namespace (e.g. like not cleaning them up when | ||
// the autoinstrumenter ends abruptly) | ||
// https://ants-gitlab.inf.um.es/jorgegm/xdp-tutorial/-/blob/master/basic04-pinning-maps/README.org | ||
// we can share them later if we find is worth not including code per duplicate | ||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 1 << 24); | ||
} events SEC(".maps"); | ||
|
||
// To be Injected from the user space during the eBPF program load & initialization | ||
volatile const u32 wakeup_data_bytes; | ||
|
||
// get_flags prevents waking the userspace process up on each ringbuf message. | ||
// If wakeup_data_bytes > 0, it will wait until wakeup_data_bytes are accumulated | ||
// into the buffer before waking the userspace. | ||
static __always_inline long get_flags() | ||
{ | ||
long sz; | ||
|
||
if (!wakeup_data_bytes) | ||
return 0; | ||
|
||
sz = bpf_ringbuf_query(&events, BPF_RB_AVAIL_DATA); | ||
return sz >= wakeup_data_bytes ? BPF_RB_FORCE_WAKEUP : BPF_RB_NO_WAKEUP; | ||
} | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ const watch_info_t *unused_2 __attribute__((unused)); | |
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
__uint(max_entries, 1 << 24); | ||
__uint(max_entries, 1 << 8); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The minimum size should be multiple of 4096, according to this: https://stackoverflow.com/questions/63415220/bpf-ring-buffer-invalid-argument-22 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. I will increase it, although even with 256 I see the events flowing... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok! So maybe the reference link is wrong. The documentation doesn't say anything but "must be power of 2". |
||
} watch_events SEC(".maps"); | ||
|
||
SEC("kprobe/sys_bind") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,6 @@ import ( | |
"github.com/grafana/beyla/pkg/beyla" | ||
"github.com/grafana/beyla/pkg/internal/ebpf" | ||
"github.com/grafana/beyla/pkg/internal/ebpf/goruntime" | ||
"github.com/grafana/beyla/pkg/internal/ebpf/gosql" | ||
"github.com/grafana/beyla/pkg/internal/ebpf/grpc" | ||
"github.com/grafana/beyla/pkg/internal/ebpf/httpfltr" | ||
"github.com/grafana/beyla/pkg/internal/ebpf/httpssl" | ||
|
@@ -81,7 +80,6 @@ func newGoTracersGroup(cfg *beyla.Config, metrics imetrics.Reporter) []ebpf.Trac | |
&nethttp.GinTracer{Tracer: *nethttp.New(&cfg.EBPF, metrics)}, | ||
grpc.New(&cfg.EBPF, metrics), | ||
goruntime.New(&cfg.EBPF, metrics), | ||
gosql.New(&cfg.EBPF, metrics), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you forget to re-add gosql? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed it temporarily, the whole separate file and EBPF program, because it required more headers refactor in the BPF side, so we don't include collections we don't need twice. I'm going to follow-up with a PR to split that off again after I clean up the headers more. |
||
} | ||
} | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As max_entries are allocated dynamically as long as more space is needed, this should not affect in terms of memory (unless we end up having more than 2^16 events in the queue).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I printed BPF metrics, I see the whole ring buffer pre-allocated in locked memory.
Before:
After:
There are more issues with what we do. One example is that we'll load two separate programs when we have
gin
. Once for thegin
functions, but we'll load the go http too, because it's there in the binary. So in a sense, we'll duplicate the memory and have 2 ring buffers when we instrument withgin
.Another issue is grpc,
golang.org/x/net/http2/hpack.(*Encoder).WriteField
belongs to the gosdk, so we load both http and grpc for grpc only applications, again two ring buffers, all maps are duplicate :(.