Likewise, add addr_filter BPF hash map and check it with the lock address. $ sudo ./perf lock con -ab -L tasklist_lock -- ./perf bench sched messaging # Running 'sched/messaging' benchmark: # 20 sender and receiver processes per group # 10 groups == 400 processes run Total time: 0.169 [sec] contended total wait max wait avg wait type caller 18 174.09 us 25.31 us 9.67 us rwlock:W do_exit+0x36d 5 32.34 us 10.87 us 6.47 us rwlock:R do_wait+0x8b 4 15.41 us 4.73 us 3.85 us rwlock:W release_task+0x6e Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx> --- tools/perf/util/bpf_lock_contention.c | 42 ++++++++++++++++++- .../perf/util/bpf_skel/lock_contention.bpf.c | 17 ++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c index b8590b82ad3d..4a95c0ebcb3c 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -20,7 +20,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; + int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1; struct evlist *evlist = con->evlist; struct target *target = con->target; @@ -49,9 +49,39 @@ int lock_contention_prepare(struct lock_contention *con) if (con->filters->nr_types) ntypes = con->filters->nr_types; + /* resolve lock name filters to addr */ + if (con->filters->nr_syms) { + struct symbol *sym; + struct map *kmap; + unsigned long *addrs; + + for (i = 0; i < con->filters->nr_syms; i++) { + sym = machine__find_kernel_symbol_by_name(con->machine, + con->filters->syms[i], + &kmap); + if (sym == NULL) { + pr_warning("ignore unknown symbol: %s\n", + con->filters->syms[i]); + continue; + } + + addrs = realloc(con->filters->addrs, + (con->filters->nr_addrs + 1) * sizeof(*addrs)); + if (addrs == NULL) { + pr_warning("memory allocation failure\n"); + continue; + } + + addrs[con->filters->nr_addrs++] = kmap->unmap_ip(kmap, sym->start); + con->filters->addrs = addrs; + } + naddrs = con->filters->nr_addrs; + } + bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); 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); if (lock_contention_bpf__load(skel) < 0) { pr_err("Failed to load lock-contention BPF skeleton\n"); @@ -103,6 +133,16 @@ int lock_contention_prepare(struct lock_contention *con) bpf_map_update_elem(fd, &con->filters->types[i], &val, BPF_ANY); } + if (con->filters->nr_addrs) { + u8 val = 1; + + skel->bss->has_addr = 1; + fd = bpf_map__fd(skel->maps.addr_filter); + + for (i = 0; i < con->filters->nr_addrs; i++) + bpf_map_update_elem(fd, &con->filters->addrs[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; diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c index fb0128de7c00..ad0ca5d50557 100644 --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c @@ -69,11 +69,19 @@ struct { __uint(max_entries, 1); } type_filter SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u64)); + __uint(value_size, sizeof(__u8)); + __uint(max_entries, 1); +} addr_filter SEC(".maps"); + /* control flags */ int enabled; int has_cpu; int has_task; int has_type; +int has_addr; int stack_skip; /* determine the key of lock stat */ @@ -111,6 +119,15 @@ static inline int can_record(u64 *ctx) return 0; } + if (has_addr) { + __u8 *ok; + __u64 addr = ctx[0]; + + ok = bpf_map_lookup_elem(&addr_filter, &addr); + if (!ok) + return 0; + } + return 1; } -- 2.39.0.314.g84b9a713c41-goog