in profiler/profile.cpp [338:502]
int main(int argc, char **argv)
{
static const struct argp argp = {
.options = opts,
.parser = parse_arg,
.doc = argp_program_doc,
};
struct syms_cache *syms_cache = NULL;
struct ksyms *ksyms = NULL;
struct bpf_link *cpu_links[MAX_CPU_NR] = {};
struct bpf_link *uprobe_links[UPROBE_SIZE] = {};
struct profile_bpf *obj = nullptr;
struct perf_buffer *pb = nullptr;
int err, i;
const char *stack_context = "user + kernel";
char thread_context[64];
char sample_context[64];
err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
if (err)
return err;
if (env.user_stacks_only && env.kernel_stacks_only)
{
fprintf(stderr, "user_stacks_only and kernel_stacks_only cannot be used together.\n");
return 1;
}
libbpf_set_print(libbpf_print_fn);
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
nr_cpus = libbpf_num_possible_cpus();
if (nr_cpus < 0)
{
printf("failed to get # of possible cpus: '%s'!\n",
strerror(-nr_cpus));
return 1;
}
if (nr_cpus > MAX_CPU_NR)
{
fprintf(stderr, "the number of cpu cores is too big, please "
"increase MAX_CPU_NR's value and recompile");
return 1;
}
obj = profile_bpf__open();
if (!obj)
{
fprintf(stderr, "failed to open BPF object\n");
return 1;
}
/* initialize global data (filtering options) */
obj->rodata->targ_pid = env.pid;
obj->rodata->targ_tid = env.tid;
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;
obj->rodata->frame_depth = env.frame_depth;
bpf_map__set_value_size(obj->maps.stackmap,
env.perf_max_stack_depth * sizeof(unsigned long));
bpf_map__set_max_entries(obj->maps.stackmap, env.stack_storage_size);
err = profile_bpf__load(obj);
if (err)
{
fprintf(stderr, "failed to load BPF programs\n");
fprintf(stderr, "try decrease the max frame depth with -D and rerun with sudo?\n");
goto cleanup;
}
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");
goto cleanup;
}
err = attach_lua_uprobes(obj, uprobe_links);
if (err < 0)
{
// cannot found lua lib, so skip lua uprobe
env.disable_lua_user_trace = true;
}
pb = perf_buffer__new(bpf_map__fd(obj->maps.lua_event_output), PERF_BUFFER_PAGES,
handle_lua_stack_event, handle_lua_stack_lost_events, NULL, NULL);
if (!pb)
{
err = -errno;
warn("failed to open perf buffer: %d\n", err);
goto cleanup;
}
err = open_and_attach_perf_event(env.freq, obj->progs.do_perf_event, cpu_links);
if (err)
goto cleanup;
signal(SIGINT, sig_handler);
if (env.pid != -1)
snprintf(thread_context, sizeof(thread_context), "PID %d", env.pid);
else if (env.tid != -1)
snprintf(thread_context, sizeof(thread_context), "TID %d", env.tid);
else
snprintf(thread_context, sizeof(thread_context), "all threads");
snprintf(sample_context, sizeof(sample_context), "%d Hertz", env.sample_freq);
if (env.user_stacks_only)
stack_context = "user";
else if (env.kernel_stacks_only)
stack_context = "kernel";
if (!env.folded)
{
printf("Sampling at %s of %s by %s stack", sample_context, thread_context, stack_context);
if (env.cpu != -1)
printf(" on CPU#%d", env.cpu);
if (env.duration < 99999999)
printf(" for %d secs.\n", env.duration);
else
printf("... Hit Ctrl-C to end.\n");
}
/*
* We'll get sleep interrupted when someone presses Ctrl-C (which will
* be "handled" with noop by sig_handler).
*/
while (!exiting)
{
// print perf event to get stack trace
err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
if (err < 0 && err != -EINTR)
{
warn("error polling perf buffer: %s\n", strerror(-err));
goto cleanup;
}
/* reset err to return 0 if exiting */
err = 0;
}
print_stack_trace(ksyms, syms_cache, obj);
cleanup:
if (env.cpu != -1)
bpf_link__destroy(cpu_links[env.cpu]);
else
{
for (i = 0; i < nr_cpus; i++)
bpf_link__destroy(cpu_links[i]);
}
for (i = 0; i < UPROBE_SIZE; i++)
bpf_link__destroy(uprobe_links[i]);
profile_bpf__destroy(obj);
perf_buffer__free(pb);
syms_cache__free(syms_cache);
ksyms__free(ksyms);
return err != 0;
}