Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ gotests/go_tester
gotests/gotests
.local_libbpf/bpf
.local_libbpf/pkgconfig

.codex
TODO*.md
119 changes: 110 additions & 9 deletions gotests/cgo_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ struct netdata_ringbuf_stats {
uint64_t bytes;
};

struct netdata_socket_ringbuf_ctx {
struct netdata_ringbuf_stats *stats;
uint64_t handle;
};

extern void socketRingbufSample(uint64_t handle, void *data, size_t size);

#ifdef LIBBPF_MAJOR_VERSION
static int netdata_libbpf_probe_bpf_map_type(unsigned int map_type)
{
Expand All @@ -48,6 +55,11 @@ static int netdata_libbpf_num_possible_cpus(void)
return libbpf_num_possible_cpus();
}

static long netdata_sc_pagesize(void)
{
return sysconf(_SC_PAGESIZE);
}

static int netdata_open_capture_socket(int program_fd)
{
struct sockaddr_ll bind_addr = { 0 };
Expand Down Expand Up @@ -132,37 +144,75 @@ static int netdata_ring_buffer_sample_cb(void *ctx, void *data, size_t size)
return 0;
}

static struct netdata_ringbuf_stats *netdata_ringbuf_stats_new(void)
static int netdata_socket_ring_buffer_sample_cb(void *ctx, void *data, size_t size)
{
struct netdata_socket_ringbuf_ctx *socket_ctx = ctx;

if (socket_ctx) {
if (socket_ctx->stats) {
socket_ctx->stats->samples++;
socket_ctx->stats->bytes += size;
}
socketRingbufSample(socket_ctx->handle, data, size);
}

return 0;
}

struct netdata_ringbuf_stats *netdata_ringbuf_stats_new(void)
{
return calloc(1, sizeof(struct netdata_ringbuf_stats));
}

static void netdata_ringbuf_stats_free(struct netdata_ringbuf_stats *stats)
void netdata_ringbuf_stats_free(struct netdata_ringbuf_stats *stats)
{
free(stats);
}

static uint64_t netdata_ringbuf_stats_samples(const struct netdata_ringbuf_stats *stats)
uint64_t netdata_ringbuf_stats_samples(const struct netdata_ringbuf_stats *stats)
{
return stats ? stats->samples : 0;
}

static uint64_t netdata_ringbuf_stats_bytes(const struct netdata_ringbuf_stats *stats)
uint64_t netdata_ringbuf_stats_bytes(const struct netdata_ringbuf_stats *stats)
{
return stats ? stats->bytes : 0;
}

static struct ring_buffer *netdata_ring_buffer_new(int map_fd, struct netdata_ringbuf_stats *stats)
struct ring_buffer *netdata_ring_buffer_new(int map_fd, struct netdata_ringbuf_stats *stats)
{
return ring_buffer__new(map_fd, netdata_ring_buffer_sample_cb, stats, NULL);
}

static int netdata_ring_buffer_poll(struct ring_buffer *rb, int timeout_ms)
struct netdata_socket_ringbuf_ctx *netdata_socket_ringbuf_ctx_new(struct netdata_ringbuf_stats *stats, uint64_t handle)
{
struct netdata_socket_ringbuf_ctx *ctx = calloc(1, sizeof(*ctx));

if (!ctx)
return NULL;

ctx->stats = stats;
ctx->handle = handle;

return ctx;
}

void netdata_socket_ringbuf_ctx_free(struct netdata_socket_ringbuf_ctx *ctx)
{
free(ctx);
}

struct ring_buffer *netdata_socket_ring_buffer_new(int map_fd, struct netdata_socket_ringbuf_ctx *ctx)
{
return ring_buffer__new(map_fd, netdata_socket_ring_buffer_sample_cb, ctx, NULL);
}

int netdata_ring_buffer_poll(struct ring_buffer *rb, int timeout_ms)
{
return ring_buffer__poll(rb, timeout_ms);
}

static uint64_t netdata_ring_buffer_avail_data(const struct ring_buffer *rb)
uint64_t netdata_ring_buffer_avail_data(const struct ring_buffer *rb)
{
struct ring *ring = ring_buffer__ring((struct ring_buffer *)rb, 0);

Expand All @@ -172,7 +222,7 @@ static uint64_t netdata_ring_buffer_avail_data(const struct ring_buffer *rb)
return (uint64_t)ring__avail_data_size(ring);
}

static uint64_t netdata_ring_buffer_size(const struct ring_buffer *rb)
uint64_t netdata_ring_buffer_size(const struct ring_buffer *rb)
{
struct ring *ring = ring_buffer__ring((struct ring_buffer *)rb, 0);

Expand All @@ -182,7 +232,7 @@ static uint64_t netdata_ring_buffer_size(const struct ring_buffer *rb)
return (uint64_t)ring__size(ring);
}

static void netdata_ring_buffer_free(struct ring_buffer *rb)
void netdata_ring_buffer_free(struct ring_buffer *rb)
{
ring_buffer__free(rb);
}
Expand Down Expand Up @@ -229,6 +279,7 @@ const (
bpfMapTypePerCPUArray = uint32(C.BPF_MAP_TYPE_PERCPU_ARRAY)
bpfMapTypeRingBuf = uint32(C.BPF_MAP_TYPE_RINGBUF)
bpfMapTypeUserRingBuf = uint32(C.BPF_MAP_TYPE_USER_RINGBUF)
bpfMapTypeArena = uint32(C.BPF_MAP_TYPE_ARENA)
)

type bpfObject struct {
Expand Down Expand Up @@ -426,6 +477,56 @@ func (m *bpfMap) name() string {
return C.GoString(C.bpf_map__name(m.ptr))
}

// arenaInfo holds the intermediate values computed when locating an arena data section.
type arenaInfo struct {
RawBase unsafe.Pointer // raw return value of bpf_map__initial_value
DataSize uintptr // data section size reported by libbpf (isize)
PageSize uintptr
TotalSize uintptr // max_entries * page_size
DataOffset uintptr // byte offset from RawBase to the data section
StatePtr unsafe.Pointer // final pointer: RawBase + DataOffset
}

// initialValueInfo returns the arena state pointer together with diagnostic fields.
// libbpf places the data section at the END of the arena mmap when
// FEAT_LDIMM64_FULL_RANGE_OFF is supported:
//
// state = base + (total_sz - roundup(data_sz, PAGE_SIZE))
//
// The caller must NOT munmap the returned pointer; libbpf owns the mapping.
func (m *bpfMap) initialValueInfo() (unsafe.Pointer, arenaInfo) {
var size C.size_t
base := unsafe.Pointer(C.bpf_map__initial_value(m.ptr, &size))
pageSize := uintptr(C.netdata_sc_pagesize())
totalSz := uintptr(C.bpf_map__max_entries(m.ptr)) * pageSize

info := arenaInfo{
RawBase: base,
DataSize: uintptr(size),
PageSize: pageSize,
TotalSize: totalSz,
}

if base == nil || size == 0 {
return nil, info
}

roundedDataSz := (info.DataSize + pageSize - 1) &^ (pageSize - 1)
if roundedDataSz > totalSz {
return nil, info
}

info.DataOffset = totalSz - roundedDataSz
info.StatePtr = unsafe.Add(base, info.DataOffset)
return info.StatePtr, info
}

// initialValue is a convenience wrapper around initialValueInfo.
func (m *bpfMap) initialValue() unsafe.Pointer {
ptr, _ := m.initialValueInfo()
return ptr
}

func probeMapTypeSupport(mapType uint32) int {
return int(C.netdata_libbpf_probe_bpf_map_type(C.uint(mapType)))
}
Expand Down
28 changes: 21 additions & 7 deletions gotests/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ var (
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagMDFlush, name: "mdflush"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagMount, name: "mount"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSync, name: "msync"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagSocket, name: "socket", ctrlTable: "socket_ctrl"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagSocket, name: "socket", ctrlTable: "socket_ctrl"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, bufferKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, arenaKernels: netdataV510 | netdataV511 | netdataV514 | netdataV515 | netdataV516 | netdataV68 | netdataV612, flags: flagDNS, name: "dns"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagNFS, name: "nfs", ctrlTable: "nfs_ctrl"},
{kernels: netdataV310 | netdataV414 | netdataV416 | netdataV418 | netdataV54 | netdataV514, flags: flagNetworkViewer, name: "network_viewer", ctrlTable: "nv_ctrl"},
Expand Down Expand Up @@ -483,8 +483,8 @@ func helpText(exe string) string {
"--content Test content stored inside hash tables.\n"+
"--iteration Number of iterations when content is read, default value is 1.\n"+
"--pid Specify the number that identifies PID that will be monitored: 0 - Real Parent PID (Default), 1 - Parent PID, 2 - All PID, and 3 - Ignore PID (ring buffer mode).\n"+
"--buffer Test ring buffer versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n"+
"--arena Test arena versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns).\n\n"+
"--buffer Test ring buffer versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns, socket).\n"+
"--arena Test arena versions of collectors (cachestat, dc, fd, oomkill, process, shm, swap, vfs, dns, socket).\n\n"+
"You can also specify an unique eBPF program developed by Netdata with the following\n"+
"options:\n"+
"--btrfs Latency for btrfs.\n"+
Expand Down Expand Up @@ -839,6 +839,8 @@ func mapTypeName(mapType uint32) string {
return "ringbuf"
case bpfMapTypeUserRingBuf:
return "user_ringbuf"
case bpfMapTypeArena:
return "arena"
default:
return fmt.Sprintf("type_%d", mapType)
}
Expand Down Expand Up @@ -1025,6 +1027,7 @@ func moduleHasBuffer(name string) bool {
"swap": true,
"vfs": true,
"dns": true,
"socket": true,
}
return bufferModules[name]
}
Expand All @@ -1040,6 +1043,7 @@ func moduleHasArena(name string) bool {
"swap": true,
"vfs": true,
"dns": true,
"socket": true,
}
return arenaModules[name]
}
Expand Down Expand Up @@ -1223,10 +1227,14 @@ func ebpfTester(w io.Writer, filename string, names *[]specifyName, maps bool, c
}

if maps {
if ctrl != "" {
fillCtrl(obj, ctrl, opts.mapLevel, nprocesses)
if hasSocketTable(obj) {
runSocketTableTester(w, obj, opts.iterations)
} else {
if ctrl != "" {
fillCtrl(obj, ctrl, opts.mapLevel, nprocesses)
}
testMaps(w, obj, ctrl, opts.iterations, nprocesses)
}
testMaps(w, obj, ctrl, opts.iterations, nprocesses)
}

for _, link := range summary.links {
Expand Down Expand Up @@ -1338,7 +1346,7 @@ func isPerCPUMapType(mapType uint32) bool {
}

func isRingBufferMapType(mapType uint32) bool {
return mapType == bpfMapTypeRingBuf || mapType == bpfMapTypeUserRingBuf
return mapType == bpfMapTypeRingBuf || mapType == bpfMapTypeUserRingBuf || mapType == bpfMapTypeArena
}

func isUserRingBufferMapType(mapType uint32) bool {
Expand Down Expand Up @@ -1540,6 +1548,12 @@ func testMaps(w io.Writer, obj *bpfObject, ctrl string, iterations int, nprocess
tables := 0
for m := obj.firstMap(); m != nil; m = obj.nextMap(m) {
meta := m.meta()
if meta.Name == "socket_events" {
runSocketRingBufferTester(w, obj, iterations)
fmt.Fprint(w, " ]\n }\n },\n")
tables++
continue
}
if !supportsMapKeyValueIO(meta.Type) {
testRingBufferMap(w, meta, iterations)
fmt.Fprint(w, " ]\n }\n },\n")
Expand Down
Loading