diff options
Diffstat (limited to 'tools/perf/util/bpf_lock_contention.c')
-rw-r--r-- | tools/perf/util/bpf_lock_contention.c | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index e7dddf0127bc..e105245eb905 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include "util/cgroup.h" #include "util/debug.h" #include "util/evlist.h" #include "util/machine.h" @@ -20,7 +21,7 @@ static struct lock_contention_bpf *skel; int lock_contention_prepare(struct lock_contention *con) { int i, fd; - int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1; + int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1, ncgrps = 1; struct evlist *evlist = con->evlist; struct target *target = con->target; @@ -50,6 +51,8 @@ int lock_contention_prepare(struct lock_contention *con) ntasks = perf_thread_map__nr(evlist->core.threads); if (con->filters->nr_types) ntypes = con->filters->nr_types; + if (con->filters->nr_cgrps) + ncgrps = con->filters->nr_cgrps; /* resolve lock name filters to addr */ if (con->filters->nr_syms) { @@ -84,6 +87,7 @@ int lock_contention_prepare(struct lock_contention *con) bpf_map__set_max_entries(skel->maps.task_filter, ntasks); bpf_map__set_max_entries(skel->maps.type_filter, ntypes); bpf_map__set_max_entries(skel->maps.addr_filter, naddrs); + bpf_map__set_max_entries(skel->maps.cgroup_filter, ncgrps); if (lock_contention_bpf__load(skel) < 0) { pr_err("Failed to load lock-contention BPF skeleton\n"); @@ -145,12 +149,29 @@ int lock_contention_prepare(struct lock_contention *con) bpf_map_update_elem(fd, &con->filters->addrs[i], &val, BPF_ANY); } + if (con->filters->nr_cgrps) { + u8 val = 1; + + skel->bss->has_cgroup = 1; + fd = bpf_map__fd(skel->maps.cgroup_filter); + + for (i = 0; i < con->filters->nr_cgrps; i++) + bpf_map_update_elem(fd, &con->filters->cgrps[i], &val, BPF_ANY); + } + /* these don't work well if in the rodata section */ skel->bss->stack_skip = con->stack_skip; skel->bss->aggr_mode = con->aggr_mode; skel->bss->needs_callstack = con->save_callstack; skel->bss->lock_owner = con->owner; + if (con->aggr_mode == LOCK_AGGR_CGROUP) { + if (cgroup_is_v2("perf_event")) + skel->bss->use_cgroup_v2 = 1; + + read_all_cgroups(&con->cgroups); + } + bpf_program__set_autoload(skel->progs.collect_lock_syms, false); lock_contention_bpf__attach(skel); @@ -209,12 +230,12 @@ static const char *lock_contention_get_name(struct lock_contention *con, return "siglock"; /* global locks with symbols */ - sym = machine__find_kernel_symbol(machine, key->lock_addr, &kmap); + sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, &kmap); if (sym) return sym->name; /* try semi-global locks collected separately */ - if (!bpf_map_lookup_elem(lock_fd, &key->lock_addr, &flags)) { + if (!bpf_map_lookup_elem(lock_fd, &key->lock_addr_or_cgroup, &flags)) { if (flags == LOCK_CLASS_RQLOCK) return "rq_lock"; } @@ -222,6 +243,17 @@ static const char *lock_contention_get_name(struct lock_contention *con, return ""; } + if (con->aggr_mode == LOCK_AGGR_CGROUP) { + u64 cgrp_id = key->lock_addr_or_cgroup; + struct cgroup *cgrp = __cgroup__find(&con->cgroups, cgrp_id); + + if (cgrp) + return cgrp->name; + + snprintf(name_buf, sizeof(name_buf), "cgroup:%lu", cgrp_id); + return name_buf; + } + /* LOCK_AGGR_CALLER: skip lock internal functions */ while (machine__is_lock_function(machine, stack_trace[idx]) && idx < con->max_stack - 1) @@ -313,7 +345,8 @@ int lock_contention_read(struct lock_contention *con) ls_key = key.pid; break; case LOCK_AGGR_ADDR: - ls_key = key.lock_addr; + case LOCK_AGGR_CGROUP: + ls_key = key.lock_addr_or_cgroup; break; default: goto next; @@ -364,12 +397,20 @@ next: return err; } -int lock_contention_finish(void) +int lock_contention_finish(struct lock_contention *con) { if (skel) { skel->bss->enabled = 0; lock_contention_bpf__destroy(skel); } + while (!RB_EMPTY_ROOT(&con->cgroups)) { + struct rb_node *node = rb_first(&con->cgroups); + struct cgroup *cgrp = rb_entry(node, struct cgroup, node); + + rb_erase(node, &con->cgroups); + cgroup__put(cgrp); + } + return 0; } |