From 447625dbdbeb4fe030d0b93afcd85767363645da Mon Sep 17 00:00:00 2001 From: louxiu Date: Thu, 26 Sep 2024 11:20:29 +0800 Subject: [PATCH 1/2] FIX: Ensure that the type of vals matches counts's --- bpftools/profile_nginx_lua/profile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bpftools/profile_nginx_lua/profile.c b/bpftools/profile_nginx_lua/profile.c index 39e5485..de5235e 100644 --- a/bpftools/profile_nginx_lua/profile.c +++ b/bpftools/profile_nginx_lua/profile.c @@ -299,7 +299,7 @@ static bool read_batch_counts_map(int fd, struct key_ext_t *items, __u32 *count) void *in = NULL, *out; __u32 i, n, n_read = 0; int err = 0; - __u32 vals[*count]; + __u64 vals[*count]; struct profile_key_t keys[*count]; while (n_read < *count && !err) From c4e37571e2c3421294169a70052d31d560ee4432 Mon Sep 17 00:00:00 2001 From: louyl Date: Thu, 7 Nov 2024 12:45:37 +0800 Subject: [PATCH 2/2] ADD: support run in docker without pid=host --- bpftools/profile_nginx_lua/profile.bpf.c | 47 ++++++++++++++++----- bpftools/profile_nginx_lua/profile.c | 52 ++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/bpftools/profile_nginx_lua/profile.bpf.c b/bpftools/profile_nginx_lua/profile.bpf.c index 1321312..07bdf15 100644 --- a/bpftools/profile_nginx_lua/profile.bpf.c +++ b/bpftools/profile_nginx_lua/profile.bpf.c @@ -10,6 +10,9 @@ const volatile bool disable_lua_user_trace = false; const volatile bool include_idle = false; const volatile pid_t targ_pid = -1; const volatile pid_t targ_tid = -1; +const volatile __u64 targ_ns_dev = 0; +const volatile __u64 targ_ns_ino = 0; +const volatile __u64 stack_depth_limit = 0; struct { @@ -84,7 +87,7 @@ static inline int lua_get_funcdata(struct bpf_perf_event_data *ctx, cTValue *fra if (!src) return -1; bpf_probe_read_user_str(eventp->name, sizeof(eventp->name), src); - bpf_printk("level= %d, fn_name=%s\n", level, eventp->name); + //bpf_printk("level= %d, fn_name=%s\n", level, eventp->name); } else if (iscfunc(fn)) { @@ -127,7 +130,7 @@ static int fix_lua_stack(struct bpf_perf_event_data *ctx, __u32 tid, int stack_i frame = nextframe = BPF_PROBE_READ_USER(L, base) - 1; /* Traverse frames backwards. */ // for the ebpf verifier insns (limit 1000000), we need to limit the max loop times to 13 - for (; i < 15 && frame > bot; i++) + for (; i < stack_depth_limit && frame > bot; i++) { if (frame_gc(frame) == obj2gco(L)) { @@ -159,12 +162,33 @@ static int fix_lua_stack(struct bpf_perf_event_data *ctx, __u32 tid, int stack_i return 0; } +static long get_current_pid_tgid(__u32 *pid, __u32 *tid) +{ + if (targ_ns_dev == 0 && targ_ns_ino == 0) + { + __u64 id = bpf_get_current_pid_tgid(); + *pid = id >> 32; + *tid = id; + return 0; + } + + struct bpf_pidns_info ns = {}; + long ret = bpf_get_ns_current_pid_tgid(targ_ns_dev, targ_ns_ino, &ns, sizeof(struct bpf_pidns_info)); + if (ret) + return ret; + + *pid = ns.pid; + *tid = ns.tgid; + return 0; +} + SEC("perf_event") int do_perf_event(struct bpf_perf_event_data *ctx) { - __u64 id = bpf_get_current_pid_tgid(); - __u32 pid = id >> 32; - __u32 tid = id; + __u32 pid = 0, tid = 0; + if (get_current_pid_tgid(&pid, &tid)) + return 0; + __u64 *valp; static const __u64 zero; struct profile_key_t key = {}; @@ -220,9 +244,9 @@ static int probe_entry_lua_cancel(struct pt_regs *ctx) if (!PT_REGS_PARM4(ctx)) return 0; - __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 pid = pid_tgid >> 32; - __u32 tid = (__u32)pid_tgid; + __u32 pid = 0, tid = 0; + if (get_current_pid_tgid(&pid, &tid)) + return 0; if (targ_pid != -1 && targ_pid != pid) return 0; @@ -241,9 +265,10 @@ static int probe_entry_lua(struct pt_regs *ctx) if (!PT_REGS_PARM1(ctx)) return 0; - __u64 pid_tgid = bpf_get_current_pid_tgid(); - __u32 pid = pid_tgid >> 32; - __u32 tid = (__u32)pid_tgid; + __u32 pid = 0, tid = 0; + if (get_current_pid_tgid(&pid, &tid)) + return 0; + struct lua_stack_event event = {}; if (targ_pid != -1 && targ_pid != pid) diff --git a/bpftools/profile_nginx_lua/profile.c b/bpftools/profile_nginx_lua/profile.c index de5235e..5b9cb7f 100644 --- a/bpftools/profile_nginx_lua/profile.c +++ b/bpftools/profile_nginx_lua/profile.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -38,12 +39,15 @@ static struct env { pid_t pid; pid_t tid; + __u64 ns_dev; + __u64 ns_ino; bool user_stacks_only; bool kernel_stacks_only; // control lua user space stack trace bool disable_lua_user_trace; bool lua_user_stacks_only; int stack_storage_size; + int stack_depth_limit; int perf_max_stack_depth; int duration; bool verbose; @@ -56,7 +60,10 @@ static struct env } env = { .pid = -1, .tid = -1, + .ns_dev = 0, + .ns_ino = 0, .stack_storage_size = 8192, + .stack_depth_limit = 15, .perf_max_stack_depth = 127, .duration = 3, .freq = 1, @@ -87,8 +94,9 @@ const char argp_program_doc[] = #define OPT_PERF_MAX_STACK_DEPTH 1 /* --perf-max-stack-depth */ #define OPT_STACK_STORAGE_SIZE 2 /* --stack-storage-size */ -#define OPT_LUA_USER_STACK_ONLY 3 /* --lua-user-stacks-only */ -#define OPT_DISABLE_LUA_USER_TRACE 4 /* --disable-lua-user-trace */ +#define OPT_STACK_DEPTH_LIMIT 3 /* --stack-depth-limit */ +#define OPT_LUA_USER_STACK_ONLY 4 /* --lua-user-stacks-only */ +#define OPT_DISABLE_LUA_USER_TRACE 5 /* --disable-lua-user-trace */ #define PERF_BUFFER_PAGES 16 #define PERF_POLL_TIMEOUT_MS 100 @@ -109,6 +117,8 @@ static const struct argp_option opts[] = { {"folded", 'f', NULL, 0, "output folded format, one line per stack (for flame graphs)"}, {"stack-storage-size", OPT_STACK_STORAGE_SIZE, "STACK-STORAGE-SIZE", 0, "the number of unique stack traces that can be stored and displayed (default 1024)"}, + {"stack-depth-limit", OPT_STACK_DEPTH_LIMIT, "OPT_STACK_DEPTH_LIMIT", 0, + "the limit depth of stack that be traversed (default 15)"}, {"cpu", 'C', "CPU", 0, "cpu number to run profile on"}, {"perf-max-stack-depth", OPT_PERF_MAX_STACK_DEPTH, "PERF-MAX-STACK-DEPTH", 0, "the limit for both kernel and user stack traces (default 127)"}, @@ -117,6 +127,22 @@ static const struct argp_option opts[] = { {}, }; +static int read_ns_dev_ino( __u64 *ns_dev, __u64 *ns_ino) +{ + struct stat statbuf; + const char *path = "/proc/self/ns/pid"; + + if (stat(path, &statbuf) == -1) { + perror("stat"); + return 1; + } + + *ns_dev = statbuf.st_dev; + *ns_ino = statbuf.st_ino; + + return 0; +} + static error_t parse_arg(int key, char *arg, struct argp_state *state) { static int pos_args; @@ -198,6 +224,15 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) argp_usage(state); } break; + case OPT_STACK_DEPTH_LIMIT: + errno = 0; + env.stack_depth_limit = strtol(arg, NULL, 10); + if (errno) + { + fprintf(stderr, "invalid stack depth limit: %s\n", arg); + argp_usage(state); + } + break; case OPT_LUA_USER_STACK_ONLY: env.lua_user_stacks_only = true; break; @@ -774,9 +809,18 @@ int main(int argc, char **argv) return 1; } + if(read_ns_dev_ino(&env.ns_dev, &env.ns_ino)) + { + fprintf(stderr, "failed to read ns_dev and ns_ino\n"); + return 1; + } + /* initialize global data (filtering options) */ obj->rodata->targ_pid = env.pid; obj->rodata->targ_tid = env.tid; + obj->rodata->targ_ns_dev = env.ns_dev; + obj->rodata->targ_ns_ino = env.ns_ino; + obj->rodata->stack_depth_limit = env.stack_depth_limit; obj->rodata->user_stacks_only = env.user_stacks_only; obj->rodata->kernel_stacks_only = env.kernel_stacks_only; obj->rodata->include_idle = env.include_idle; @@ -788,7 +832,9 @@ int main(int argc, char **argv) err = profile_bpf__load(obj); if (err) { - fprintf(stderr, "failed to load BPF programs\n"); + fprintf(stderr, "failed to load BPF programs. " + "if the error message indicates `BPF program is too large`, " + "consider using the `--stack-depth-limit` option.\n"); goto cleanup; } ksyms = ksyms__load();