0001 #include <stdio.h>
0002 #include <fcntl.h>
0003 #include <stdint.h>
0004 #include <stdlib.h>
0005
0006 #include <linux/err.h>
0007
0008 #include "util/ftrace.h"
0009 #include "util/cpumap.h"
0010 #include "util/thread_map.h"
0011 #include "util/debug.h"
0012 #include "util/evlist.h"
0013 #include "util/bpf_counter.h"
0014
0015 #include "util/bpf_skel/func_latency.skel.h"
0016
0017 static struct func_latency_bpf *skel;
0018
0019 int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace)
0020 {
0021 int fd, err;
0022 int i, ncpus = 1, ntasks = 1;
0023 struct filter_entry *func;
0024
0025 if (!list_is_singular(&ftrace->filters)) {
0026 pr_err("ERROR: %s target function(s).\n",
0027 list_empty(&ftrace->filters) ? "No" : "Too many");
0028 return -1;
0029 }
0030
0031 func = list_first_entry(&ftrace->filters, struct filter_entry, list);
0032
0033 skel = func_latency_bpf__open();
0034 if (!skel) {
0035 pr_err("Failed to open func latency skeleton\n");
0036 return -1;
0037 }
0038
0039
0040 if (ftrace->target.cpu_list) {
0041 ncpus = perf_cpu_map__nr(ftrace->evlist->core.user_requested_cpus);
0042 bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus);
0043 }
0044
0045 if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) {
0046 ntasks = perf_thread_map__nr(ftrace->evlist->core.threads);
0047 bpf_map__set_max_entries(skel->maps.task_filter, ntasks);
0048 }
0049
0050 set_max_rlimit();
0051
0052 err = func_latency_bpf__load(skel);
0053 if (err) {
0054 pr_err("Failed to load func latency skeleton\n");
0055 goto out;
0056 }
0057
0058 if (ftrace->target.cpu_list) {
0059 u32 cpu;
0060 u8 val = 1;
0061
0062 skel->bss->has_cpu = 1;
0063 fd = bpf_map__fd(skel->maps.cpu_filter);
0064
0065 for (i = 0; i < ncpus; i++) {
0066 cpu = perf_cpu_map__cpu(ftrace->evlist->core.user_requested_cpus, i).cpu;
0067 bpf_map_update_elem(fd, &cpu, &val, BPF_ANY);
0068 }
0069 }
0070
0071 if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) {
0072 u32 pid;
0073 u8 val = 1;
0074
0075 skel->bss->has_task = 1;
0076 fd = bpf_map__fd(skel->maps.task_filter);
0077
0078 for (i = 0; i < ntasks; i++) {
0079 pid = perf_thread_map__pid(ftrace->evlist->core.threads, i);
0080 bpf_map_update_elem(fd, &pid, &val, BPF_ANY);
0081 }
0082 }
0083
0084 skel->bss->use_nsec = ftrace->use_nsec;
0085
0086 skel->links.func_begin = bpf_program__attach_kprobe(skel->progs.func_begin,
0087 false, func->name);
0088 if (IS_ERR(skel->links.func_begin)) {
0089 pr_err("Failed to attach fentry program\n");
0090 err = PTR_ERR(skel->links.func_begin);
0091 goto out;
0092 }
0093
0094 skel->links.func_end = bpf_program__attach_kprobe(skel->progs.func_end,
0095 true, func->name);
0096 if (IS_ERR(skel->links.func_end)) {
0097 pr_err("Failed to attach fexit program\n");
0098 err = PTR_ERR(skel->links.func_end);
0099 goto out;
0100 }
0101
0102
0103 return open("/dev/null", O_RDONLY);
0104
0105 out:
0106 return err;
0107 }
0108
0109 int perf_ftrace__latency_start_bpf(struct perf_ftrace *ftrace __maybe_unused)
0110 {
0111 skel->bss->enabled = 1;
0112 return 0;
0113 }
0114
0115 int perf_ftrace__latency_stop_bpf(struct perf_ftrace *ftrace __maybe_unused)
0116 {
0117 skel->bss->enabled = 0;
0118 return 0;
0119 }
0120
0121 int perf_ftrace__latency_read_bpf(struct perf_ftrace *ftrace __maybe_unused,
0122 int buckets[])
0123 {
0124 int i, fd, err;
0125 u32 idx;
0126 u64 *hist;
0127 int ncpus = cpu__max_cpu().cpu;
0128
0129 fd = bpf_map__fd(skel->maps.latency);
0130
0131 hist = calloc(ncpus, sizeof(*hist));
0132 if (hist == NULL)
0133 return -ENOMEM;
0134
0135 for (idx = 0; idx < NUM_BUCKET; idx++) {
0136 err = bpf_map_lookup_elem(fd, &idx, hist);
0137 if (err) {
0138 buckets[idx] = 0;
0139 continue;
0140 }
0141
0142 for (i = 0; i < ncpus; i++)
0143 buckets[idx] += hist[i];
0144 }
0145
0146 free(hist);
0147 return 0;
0148 }
0149
0150 int perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace __maybe_unused)
0151 {
0152 func_latency_bpf__destroy(skel);
0153 return 0;
0154 }