int main()

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;
}