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

WIP: Remove dependency on kallsyms with eBPF #5217

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool
LIBBPF_SRC := $(abspath ../src/cc/libbpf/src)
LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a)
LIBBLAZESYM_SRC := $(abspath blazesym/target/release/libblazesym.a)
INCLUDES := -I$(OUTPUT) -I../src/cc/libbpf/include/uapi
INCLUDES := -I$(OUTPUT) -I../src/cc/libbpf/include/uapi -I/usr/include/x86_64-linux-gnu/
CFLAGS := -g -O2 -Wall -Wmissing-field-initializers -Werror -Werror=undef
BPFCFLAGS := -g -O2 -Wall -Werror=undef
BPFCFLAGS_softirqs := $(BPFCFLAGS) -mcpu=v3
Expand Down Expand Up @@ -138,6 +138,8 @@ all: $(APPS) $(APP_ALIASES)
ifeq ($(V),1)
Q =
msg =
CFLAGS += -v
BPFCFLAGS += -v
else
Q = @
msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
Expand Down
32 changes: 30 additions & 2 deletions libbpf-tools/profile.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#include <bpf/usdt.bpf.h>
#include "profile.h"
#include "maps.bpf.h"

Expand Down Expand Up @@ -47,6 +48,13 @@ struct {
__uint(max_entries, MAX_TID_NR);
} tids SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, u64);
__type(value, char[MAX_SYM_LEN]);
__uint(max_entries, 2 * 4096); // TODO: make this dynamic and small enough
} kaddr_to_sym SEC(".maps");

SEC("perf_event")
int do_perf_event(struct bpf_perf_event_data *ctx)
{
Expand All @@ -57,6 +65,7 @@ int do_perf_event(struct bpf_perf_event_data *ctx)
u32 pid;
u32 tid;
struct bpf_pidns_info ns = {};
const u64 stackid_flags = BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID;

if (use_pidns && !bpf_get_ns_current_pid_tgid(pidns_dev, pidns_ino, &ns,
sizeof(ns))) {
Expand All @@ -83,13 +92,13 @@ int do_perf_event(struct bpf_perf_event_data *ctx)
if (user_stacks_only)
key.kern_stack_id = -1;
else
key.kern_stack_id = bpf_get_stackid(&ctx->regs, &stackmap, 0);
key.kern_stack_id = bpf_get_stackid(&ctx->regs, &stackmap, stackid_flags);

if (kernel_stacks_only)
key.user_stack_id = -1;
else
key.user_stack_id = bpf_get_stackid(&ctx->regs, &stackmap,
BPF_F_USER_STACK);
BPF_F_USER_STACK | stackid_flags);

valp = bpf_map_lookup_or_try_init(&counts, &key, &zero);
if (valp)
Expand All @@ -98,4 +107,23 @@ int do_perf_event(struct bpf_perf_event_data *ctx)
return 0;
}

static long __convert_fn(struct bpf_map *map, const void *key, void *value, void *_ctx)
{
char *str = value;
u64 *addr = (u64*) key;
long err = bpf_snprintf(str, MAX_SYM_LEN, "%pB", addr, 1 * sizeof(u64));
if (err < 0) {
static const char err_fmt[] = "convert: bpf_snprintf failed unexpectadly";
bpf_trace_printk(err_fmt, sizeof(err_fmt));
return 1;
}
bpf_map_update_elem(map, key, value, BPF_EXIST);
return 0;
}

SEC("usdt//proc/self/exe:" TOSTRING(USDT_PROVIDER) ":" TOSTRING(USDT_READY_TO_CONVERT))
long convert(void *ctx) {
return bpf_for_each_map_elem(&kaddr_to_sym, &__convert_fn, 0, 0);
}

char LICENSE[] SEC("license") = "GPL";
114 changes: 80 additions & 34 deletions libbpf-tools/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include <sys/stat.h>
#include <sys/sdt.h>
#include "profile.h"
#include "profile.skel.h"
#include "trace_helpers.h"
Expand Down Expand Up @@ -99,7 +100,6 @@ const char argp_program_doc[] =
"EXAMPLES:\n"
" profile # profile stack traces at 49 Hertz until Ctrl-C\n"
" profile -F 99 # profile stack traces at 99 Hertz\n"
" profile -c 1000000 # profile stack traces every 1 in a million events\n"
" profile 5 # profile at 49 Hertz for 5 seconds only\n"
" profile -f # output in folded format for flame graphs\n"
" profile -p 185 # only profile process with PID 185\n"
Expand Down Expand Up @@ -128,7 +128,6 @@ static const struct argp_option opts[] = {
{},
};

struct ksyms *ksyms;
struct syms_cache *syms_cache;
struct syms *syms;
static char syminfo[SYM_INFO_LEN];
Expand Down Expand Up @@ -301,7 +300,7 @@ static int cmp_counts(const void *a, const void *b)

static int read_counts_map(int fd, struct key_ext_t *items, __u32 *count)
{
struct key_t empty = {};
struct key_t empty = {0};
struct key_t *lookup_key = &empty;
int i = 0;
int err;
Expand All @@ -324,16 +323,16 @@ static int read_counts_map(int fd, struct key_ext_t *items, __u32 *count)
return 0;
}

static const char *ksymname(unsigned long addr)
static const char *ksymname(unsigned long addr, int ksym_map)
{
const struct ksym *ksym = ksyms__map_addr(ksyms, addr);
static char name[MAX_SYM_LEN];
int err = bpf_map_lookup_elem(ksym_map, &addr, name);

if (!env.verbose)
return ksym ? ksym->name : "[unknown]";
return !err ? name : "[unknown]";

if (ksym)
snprintf(syminfo, SYM_INFO_LEN, "0x%lx %s+0x%lx", addr,
ksym->name, addr - ksym->addr);
if (!err)
snprintf(syminfo, SYM_INFO_LEN, "0x%lx %s", addr, name);
else
snprintf(syminfo, SYM_INFO_LEN, "0x%lx [unknown]", addr);

Expand Down Expand Up @@ -381,7 +380,6 @@ static void print_stacktrace(unsigned long *ip, symname_fn_t symname, struct fmt
if (!f->folded) {
for (i = 0; ip[i] && i < env.perf_max_stack_depth; i++)
pr_format(symname(ip[i]), f);
return;
} else {
for (i = env.perf_max_stack_depth - 1; i >= 0; i--) {
if (!ip[i])
Expand Down Expand Up @@ -414,7 +412,7 @@ static bool print_user_stacktrace(struct key_t *event, int stack_map,
return true;
}

static bool print_kern_stacktrace(struct key_t *event, int stack_map,
static bool print_kern_stacktrace(struct key_t *event, int stack_map, int ksym_map,
unsigned long *ip, struct fmt_t *f, bool delim)
{
if (env.user_stacks_only || STACK_ID_EFAULT(event->kern_stack_id))
Expand All @@ -425,13 +423,26 @@ static bool print_kern_stacktrace(struct key_t *event, int stack_map,

if (bpf_map_lookup_elem(stack_map, &event->kern_stack_id, ip) != 0)
pr_format("[Missed Kernel Stack]", f);
else
print_stacktrace(ip, ksymname, f);
else {
int i;

if (!f->folded) {
for (i = 0; ip[i] && i < env.perf_max_stack_depth; i++)
pr_format(ksymname(ip[i], ksym_map), f);
} else {
for (i = env.perf_max_stack_depth - 1; i >= 0; i--) {
if (!ip[i])
continue;

pr_format(ksymname(ip[i], ksym_map), f);
}
}
}

return true;
}

static int print_count(struct key_t *event, __u64 count, int stack_map, bool folded)
static int print_count(struct key_t *event, __u64 count, int stack_map, int ksym_map, bool folded)
{
unsigned long *ip;
int ret;
Expand All @@ -445,15 +456,15 @@ static int print_count(struct key_t *event, __u64 count, int stack_map, bool fol

if (!folded) {
/* multi-line stack output */
ret = print_kern_stacktrace(event, stack_map, ip, fmt, false);
ret = print_kern_stacktrace(event, stack_map, ksym_map, ip, fmt, false);
print_user_stacktrace(event, stack_map, ip, fmt, ret && env.delimiter);
printf(" %-16s %s (%d)\n", "-", event->name, event->pid);
printf(" %lld\n\n", count);
} else {
/* folded stack output */
printf("%s", event->name);
ret = print_user_stacktrace(event, stack_map, ip, fmt, false);
print_kern_stacktrace(event, stack_map, ip, fmt, ret && env.delimiter);
print_kern_stacktrace(event, stack_map, ksym_map, ip, fmt, ret && env.delimiter);
printf(" %lld\n", count);
}

Expand All @@ -462,7 +473,7 @@ static int print_count(struct key_t *event, __u64 count, int stack_map, bool fol
return 0;
}

static int print_counts(int counts_map, int stack_map)
static int print_counts(int counts_map, int stack_map, int kaddr_map)
{
struct key_ext_t *counts;
struct key_t *event;
Expand All @@ -473,22 +484,51 @@ static int print_counts(int counts_map, int stack_map)
int i, ret = 0;

counts = calloc(MAX_ENTRIES, sizeof(struct key_ext_t));
if (!counts) {
fprintf(stderr, "Out of memory\n");
return -ENOMEM;
}
if (!counts)
goto out_of_mem;

ret = read_counts_map(counts_map, counts, &nr_count);
if (ret)
goto cleanup;

if (!env.user_stacks_only) {
char empty_str[MAX_SYM_LEN] = {0};
unsigned long *ip = calloc(env.perf_max_stack_depth, sizeof(ip[0]));
if (!ip)
goto out_of_mem;
for (i = 0; i < nr_count; i++) {
event = &counts[i].k;

if (STACK_ID_EFAULT(event->kern_stack_id))
continue;

if (bpf_map_lookup_elem(stack_map, &event->kern_stack_id, ip)) {
static bool has_run = false;
if (!has_run) {
fprintf(stderr, "Error searchin for kernel stack.\n"
"Consider incresing stack-storage-size.\n"
"Continuing anyway\n");
has_run = true;
}
continue;
}
for (int j=0; ip[j] && j < env.perf_max_stack_depth; j++) {
bpf_map_update_elem (kaddr_map, ip+j, empty_str, BPF_NOEXIST);
}
memset(ip, 0, env.perf_max_stack_depth);
}
free(ip);

DTRACE_PROBE(USDT_PROVIDER, USDT_READY_TO_CONVERT);
}

qsort(counts, nr_count, sizeof(struct key_ext_t), cmp_counts);

for (i = 0; i < nr_count; i++) {
event = &counts[i].k;
count = counts[i].v;

print_count(event, count, stack_map, env.folded);
print_count(event, count, stack_map, kaddr_map, env.folded);

/* handle stack id errors */
nr_missing_stacks += MISSING_STACKS(event->user_stack_id, event->kern_stack_id);
Expand All @@ -501,8 +541,13 @@ static int print_counts(int counts_map, int stack_map)
" Consider increasing --stack-storage-size.":"");
}

goto cleanup;
out_of_mem:
fprintf(stderr, "Out of memory\n");
ret = -ENOMEM;
cleanup:
free(counts);
if (counts)
free(counts);

return ret;
}
Expand Down Expand Up @@ -642,12 +687,6 @@ int main(int argc, char **argv)
}
}

ksyms = ksyms__load();
if (!ksyms) {
fprintf(stderr, "failed to load kallsyms\n");
goto cleanup;
}

syms_cache = syms_cache__new(0);
if (!syms_cache) {
fprintf(stderr, "failed to create syms_cache\n");
Expand All @@ -669,20 +708,27 @@ int main(int argc, char **argv)
*/
sleep(env.duration);

print_counts(bpf_map__fd(obj->maps.counts),
bpf_map__fd(obj->maps.stackmap));
profile_bpf__attach(obj);
if (!obj->links.convert) {
err = errno;
fprintf(stderr, "attaching failed: %s\n", strerror(err));
goto cleanup;
}

cleanup:
if (env.cpu != -1)
bpf_link__destroy(links[env.cpu]);
else {
for (i = 0; i < nr_cpus; i++)
bpf_link__destroy(links[i]);
}

print_counts(bpf_map__fd(obj->maps.counts),
bpf_map__fd(obj->maps.stackmap),
bpf_map__fd(obj->maps.kaddr_to_sym));

cleanup:
if (syms_cache)
syms_cache__free(syms_cache);
if (ksyms)
ksyms__free(ksyms);
profile_bpf__destroy(obj);

return err != 0;
Expand Down
9 changes: 9 additions & 0 deletions libbpf-tools/profile.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
#define MAX_ENTRIES 10240
#define MAX_PID_NR 30
#define MAX_TID_NR 30
// maximum kernel symbol name length including trailing 0
#define MAX_SYM_LEN 128
#define USDT_PROVIDER bpfprofiler
#define USDT_READY_TO_CONVERT ready_to_launch_converter


#define STRINGIFY(x) #x
// Useful to convert usdt tokens to strings
#define TOSTRING(x) STRINGIFY(x)

struct key_t {
__u32 pid;
Expand Down