155 lines · c
1#include <stdio.h>2#include <fcntl.h>3#include <stdint.h>4#include <stdlib.h>5 6#include <linux/err.h>7 8#include "util/ftrace.h"9#include "util/cpumap.h"10#include "util/thread_map.h"11#include "util/debug.h"12#include "util/evlist.h"13#include "util/bpf_counter.h"14 15#include "util/bpf_skel/func_latency.skel.h"16 17static struct func_latency_bpf *skel;18 19int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace)20{21 int fd, err;22 int i, ncpus = 1, ntasks = 1;23 struct filter_entry *func;24 25 if (!list_is_singular(&ftrace->filters)) {26 pr_err("ERROR: %s target function(s).\n",27 list_empty(&ftrace->filters) ? "No" : "Too many");28 return -1;29 }30 31 func = list_first_entry(&ftrace->filters, struct filter_entry, list);32 33 skel = func_latency_bpf__open();34 if (!skel) {35 pr_err("Failed to open func latency skeleton\n");36 return -1;37 }38 39 /* don't need to set cpu filter for system-wide mode */40 if (ftrace->target.cpu_list) {41 ncpus = perf_cpu_map__nr(ftrace->evlist->core.user_requested_cpus);42 bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus);43 skel->rodata->has_cpu = 1;44 }45 46 if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) {47 ntasks = perf_thread_map__nr(ftrace->evlist->core.threads);48 bpf_map__set_max_entries(skel->maps.task_filter, ntasks);49 skel->rodata->has_task = 1;50 }51 52 skel->rodata->use_nsec = ftrace->use_nsec;53 54 set_max_rlimit();55 56 err = func_latency_bpf__load(skel);57 if (err) {58 pr_err("Failed to load func latency skeleton\n");59 goto out;60 }61 62 if (ftrace->target.cpu_list) {63 u32 cpu;64 u8 val = 1;65 66 fd = bpf_map__fd(skel->maps.cpu_filter);67 68 for (i = 0; i < ncpus; i++) {69 cpu = perf_cpu_map__cpu(ftrace->evlist->core.user_requested_cpus, i).cpu;70 bpf_map_update_elem(fd, &cpu, &val, BPF_ANY);71 }72 }73 74 if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) {75 u32 pid;76 u8 val = 1;77 78 fd = bpf_map__fd(skel->maps.task_filter);79 80 for (i = 0; i < ntasks; i++) {81 pid = perf_thread_map__pid(ftrace->evlist->core.threads, i);82 bpf_map_update_elem(fd, &pid, &val, BPF_ANY);83 }84 }85 86 skel->links.func_begin = bpf_program__attach_kprobe(skel->progs.func_begin,87 false, func->name);88 if (IS_ERR(skel->links.func_begin)) {89 pr_err("Failed to attach fentry program\n");90 err = PTR_ERR(skel->links.func_begin);91 goto out;92 }93 94 skel->links.func_end = bpf_program__attach_kprobe(skel->progs.func_end,95 true, func->name);96 if (IS_ERR(skel->links.func_end)) {97 pr_err("Failed to attach fexit program\n");98 err = PTR_ERR(skel->links.func_end);99 goto out;100 }101 102 /* XXX: we don't actually use this fd - just for poll() */103 return open("/dev/null", O_RDONLY);104 105out:106 return err;107}108 109int perf_ftrace__latency_start_bpf(struct perf_ftrace *ftrace __maybe_unused)110{111 skel->bss->enabled = 1;112 return 0;113}114 115int perf_ftrace__latency_stop_bpf(struct perf_ftrace *ftrace __maybe_unused)116{117 skel->bss->enabled = 0;118 return 0;119}120 121int perf_ftrace__latency_read_bpf(struct perf_ftrace *ftrace __maybe_unused,122 int buckets[])123{124 int i, fd, err;125 u32 idx;126 u64 *hist;127 int ncpus = cpu__max_cpu().cpu;128 129 fd = bpf_map__fd(skel->maps.latency);130 131 hist = calloc(ncpus, sizeof(*hist));132 if (hist == NULL)133 return -ENOMEM;134 135 for (idx = 0; idx < NUM_BUCKET; idx++) {136 err = bpf_map_lookup_elem(fd, &idx, hist);137 if (err) {138 buckets[idx] = 0;139 continue;140 }141 142 for (i = 0; i < ncpus; i++)143 buckets[idx] += hist[i];144 }145 146 free(hist);147 return 0;148}149 150int perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace __maybe_unused)151{152 func_latency_bpf__destroy(skel);153 return 0;154}155