Implementing bpftrace histogram in libbpf

113 Views Asked by At

I am implementing bpftrace's histogram in libbpf.

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u64);
    __type(value, u64);
} latency_map SEC(".maps");

u64 bin = log2(latency);

void *read = bpf_map_lookup_elem(&indent_map, &bin);
u64 count = (read) ? (*(u64*)(read) + 1) : 1;

bpf_map_update_elem(&latency_map, &bin, &count, BPF_ANY);

This is Map: LatencyGroup -> Frequency

Now I want to make this a keyed histogram Map: String -> LatencyGroup -> Frequency, as in

@ns[comm] = hist(nsecs - @start[tid]); delete(@start[tid]);

BPF_MAP_TYPE_HASH_OF_MAPS seems a good fit for this but I am stuck at this.

struct InnerLatencyMap {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u64); // bin
    __type(value, u64); // count
};

struct {
    __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
    __uint(max_entries, 1024);
    __type(key, struct Key);
    __array(values, struct InnerLatencyMap);
    //_array(values, struct InnerLatencyMap);
} latency_map SEC(".maps");

void increment(struct Key key, u64 bin) {
    void *read = bpf_map_lookup_elem(&latency_map, &key);
    struct bpf_map* inner_latency_map;
    if (read) {
        inner_latency_map = (struct bpf_map*)read;
        read = bpf_map_lookup_elem(inner_latency_map, &bin);
        u64 count = (read) ? (*(u64*)read + 1) : 1;
        bpf_map_update_elem(inner_latency_map, &bin, &count, BPF_ANY);
    } else {
        struct bpf_map* inner_latency_map = bpf_map_create(
            BPF_MAP_TYPE_HASH,
            NULL,
            sizeof(struct Key),
            sizeof(u64),
            512,
            NULL,
        );
        bpf_map_update_elem(&latency_map, &function_key, inner_latency_map, BPF_NOEXIST);
        u64 count = 1;
        bpf_map_update_elem(&inner_latency_map, &bin, &count, BPF_NOEXIST);
    }
}

libbpf-rs couldn't find bpf_map_create but #include <bpf/bpf.h> causes the compile error.

#include "vmlinux.h"
#include <bpf/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/usdt.bpf.h>
In file included from src/bpf/python.bpf.c:5:
In file included from /tmp/.tmpHfkjYT/bpf/src/bpf/bpf.h:26:
In file included from /usr/include/linux/bpf.h:11:
In file included from /usr/include/linux/types.h:9:
/usr/include/linux/posix_types.h:27:3: error: typedef redefinition with different types ('struct __kernel_fd_set' vs 'struct __kernel_fd_set')
} __kernel_fd_set;
  ^
src/bpf/vmlinux.h:41117:3: note: previous definition is here
} __kernel_fd_set;
  ^
In file included from src/bpf/python.bpf.c:5:
In file included from /tmp/.tmpHfkjYT/bpf/src/bpf/bpf.h:26:
In file included from /usr/include/linux/bpf.h:11:
In file included from /usr/include/linux/types.h:9:
In file included from /usr/include/linux/posix_types.h:36:
In file included from /usr/include/asm/posix_types.h:7:
In file included from /usr/include/asm/posix_types_64.h:18:
/usr/include/asm-generic/posix_types.h:68:22: error: typedef redefinition with different types ('unsigned int' vs '__kernel_ulong_t' (aka 'unsigned long'))
typedef unsigned int    __kernel_size_t;
                        ^
src/bpf/vmlinux.h:434:26: note: previous definition is here
typedef __kernel_ulong_t __kernel_size_t;
                         ^
In file included from src/bpf/python.bpf.c:5:
In file included from /tmp/.tmpHfkjYT/bpf/src/bpf/bpf.h:26:
In file included from /usr/include/linux/bpf.h:11:
In file included from /usr/include/linux/types.h:9:
In file included from /usr/include/linux/posix_types.h:36:
In file included from /usr/include/asm/posix_types.h:7:
In file included from /usr/include/asm/posix_types_64.h:18:
/usr/include/asm-generic/posix_types.h:69:14: error: typedef redefinition with different types ('int' vs '__kernel_long_t' (aka 'long'))
...

How can I use BPF_MAP_TYPE_HASH_OF_MAPS?

1

There are 1 best solutions below

0
On

bfptrace does not use BPF_MAP_TYPE_HASH_OF_MAPS. Instead appends 8 bytes of a bucket number to each key.

@map["a"] = hist(var);
@map["b"] = hist(var);

a00
a01
..
b00
b01
..

to read it, bpftrace iterates them one by one, extract 'a' from 'a00', 'a01', and so on.

ref: BPFtrace::print_map_hist