162306a36Sopenharmony_ci#include <stdio.h>
262306a36Sopenharmony_ci#include <fcntl.h>
362306a36Sopenharmony_ci#include <stdint.h>
462306a36Sopenharmony_ci#include <stdlib.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/err.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "util/ftrace.h"
962306a36Sopenharmony_ci#include "util/cpumap.h"
1062306a36Sopenharmony_ci#include "util/thread_map.h"
1162306a36Sopenharmony_ci#include "util/debug.h"
1262306a36Sopenharmony_ci#include "util/evlist.h"
1362306a36Sopenharmony_ci#include "util/bpf_counter.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "util/bpf_skel/func_latency.skel.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic struct func_latency_bpf *skel;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciint perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int fd, err;
2262306a36Sopenharmony_ci	int i, ncpus = 1, ntasks = 1;
2362306a36Sopenharmony_ci	struct filter_entry *func;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (!list_is_singular(&ftrace->filters)) {
2662306a36Sopenharmony_ci		pr_err("ERROR: %s target function(s).\n",
2762306a36Sopenharmony_ci		       list_empty(&ftrace->filters) ? "No" : "Too many");
2862306a36Sopenharmony_ci		return -1;
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	func = list_first_entry(&ftrace->filters, struct filter_entry, list);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	skel = func_latency_bpf__open();
3462306a36Sopenharmony_ci	if (!skel) {
3562306a36Sopenharmony_ci		pr_err("Failed to open func latency skeleton\n");
3662306a36Sopenharmony_ci		return -1;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* don't need to set cpu filter for system-wide mode */
4062306a36Sopenharmony_ci	if (ftrace->target.cpu_list) {
4162306a36Sopenharmony_ci		ncpus = perf_cpu_map__nr(ftrace->evlist->core.user_requested_cpus);
4262306a36Sopenharmony_ci		bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus);
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) {
4662306a36Sopenharmony_ci		ntasks = perf_thread_map__nr(ftrace->evlist->core.threads);
4762306a36Sopenharmony_ci		bpf_map__set_max_entries(skel->maps.task_filter, ntasks);
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	set_max_rlimit();
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	err = func_latency_bpf__load(skel);
5362306a36Sopenharmony_ci	if (err) {
5462306a36Sopenharmony_ci		pr_err("Failed to load func latency skeleton\n");
5562306a36Sopenharmony_ci		goto out;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (ftrace->target.cpu_list) {
5962306a36Sopenharmony_ci		u32 cpu;
6062306a36Sopenharmony_ci		u8 val = 1;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		skel->bss->has_cpu = 1;
6362306a36Sopenharmony_ci		fd = bpf_map__fd(skel->maps.cpu_filter);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		for (i = 0; i < ncpus; i++) {
6662306a36Sopenharmony_ci			cpu = perf_cpu_map__cpu(ftrace->evlist->core.user_requested_cpus, i).cpu;
6762306a36Sopenharmony_ci			bpf_map_update_elem(fd, &cpu, &val, BPF_ANY);
6862306a36Sopenharmony_ci		}
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) {
7262306a36Sopenharmony_ci		u32 pid;
7362306a36Sopenharmony_ci		u8 val = 1;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		skel->bss->has_task = 1;
7662306a36Sopenharmony_ci		fd = bpf_map__fd(skel->maps.task_filter);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		for (i = 0; i < ntasks; i++) {
7962306a36Sopenharmony_ci			pid = perf_thread_map__pid(ftrace->evlist->core.threads, i);
8062306a36Sopenharmony_ci			bpf_map_update_elem(fd, &pid, &val, BPF_ANY);
8162306a36Sopenharmony_ci		}
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	skel->bss->use_nsec = ftrace->use_nsec;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	skel->links.func_begin = bpf_program__attach_kprobe(skel->progs.func_begin,
8762306a36Sopenharmony_ci							    false, func->name);
8862306a36Sopenharmony_ci	if (IS_ERR(skel->links.func_begin)) {
8962306a36Sopenharmony_ci		pr_err("Failed to attach fentry program\n");
9062306a36Sopenharmony_ci		err = PTR_ERR(skel->links.func_begin);
9162306a36Sopenharmony_ci		goto out;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	skel->links.func_end = bpf_program__attach_kprobe(skel->progs.func_end,
9562306a36Sopenharmony_ci							  true, func->name);
9662306a36Sopenharmony_ci	if (IS_ERR(skel->links.func_end)) {
9762306a36Sopenharmony_ci		pr_err("Failed to attach fexit program\n");
9862306a36Sopenharmony_ci		err = PTR_ERR(skel->links.func_end);
9962306a36Sopenharmony_ci		goto out;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* XXX: we don't actually use this fd - just for poll() */
10362306a36Sopenharmony_ci	return open("/dev/null", O_RDONLY);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ciout:
10662306a36Sopenharmony_ci	return err;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciint perf_ftrace__latency_start_bpf(struct perf_ftrace *ftrace __maybe_unused)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	skel->bss->enabled = 1;
11262306a36Sopenharmony_ci	return 0;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciint perf_ftrace__latency_stop_bpf(struct perf_ftrace *ftrace __maybe_unused)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	skel->bss->enabled = 0;
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciint perf_ftrace__latency_read_bpf(struct perf_ftrace *ftrace __maybe_unused,
12262306a36Sopenharmony_ci				  int buckets[])
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	int i, fd, err;
12562306a36Sopenharmony_ci	u32 idx;
12662306a36Sopenharmony_ci	u64 *hist;
12762306a36Sopenharmony_ci	int ncpus = cpu__max_cpu().cpu;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	fd = bpf_map__fd(skel->maps.latency);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	hist = calloc(ncpus, sizeof(*hist));
13262306a36Sopenharmony_ci	if (hist == NULL)
13362306a36Sopenharmony_ci		return -ENOMEM;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	for (idx = 0; idx < NUM_BUCKET; idx++) {
13662306a36Sopenharmony_ci		err = bpf_map_lookup_elem(fd, &idx, hist);
13762306a36Sopenharmony_ci		if (err) {
13862306a36Sopenharmony_ci			buckets[idx] = 0;
13962306a36Sopenharmony_ci			continue;
14062306a36Sopenharmony_ci		}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		for (i = 0; i < ncpus; i++)
14362306a36Sopenharmony_ci			buckets[idx] += hist[i];
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	free(hist);
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciint perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace __maybe_unused)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	func_latency_bpf__destroy(skel);
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
155