Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf lock contention: Support lock addr/name filtering for BPF

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@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Blake Jones <blakejones@google.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <song@kernel.org>
Cc: bpf@vger.kernel.org
Link: https://lore.kernel.org/r/20221219201732.460111-6-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
5e3febe7 511e19b9

+58 -1
+41 -1
tools/perf/util/bpf_lock_contention.c
··· 20 20 int lock_contention_prepare(struct lock_contention *con) 21 21 { 22 22 int i, fd; 23 - int ncpus = 1, ntasks = 1, ntypes = 1; 23 + int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1; 24 24 struct evlist *evlist = con->evlist; 25 25 struct target *target = con->target; 26 26 ··· 49 49 if (con->filters->nr_types) 50 50 ntypes = con->filters->nr_types; 51 51 52 + /* resolve lock name filters to addr */ 53 + if (con->filters->nr_syms) { 54 + struct symbol *sym; 55 + struct map *kmap; 56 + unsigned long *addrs; 57 + 58 + for (i = 0; i < con->filters->nr_syms; i++) { 59 + sym = machine__find_kernel_symbol_by_name(con->machine, 60 + con->filters->syms[i], 61 + &kmap); 62 + if (sym == NULL) { 63 + pr_warning("ignore unknown symbol: %s\n", 64 + con->filters->syms[i]); 65 + continue; 66 + } 67 + 68 + addrs = realloc(con->filters->addrs, 69 + (con->filters->nr_addrs + 1) * sizeof(*addrs)); 70 + if (addrs == NULL) { 71 + pr_warning("memory allocation failure\n"); 72 + continue; 73 + } 74 + 75 + addrs[con->filters->nr_addrs++] = kmap->unmap_ip(kmap, sym->start); 76 + con->filters->addrs = addrs; 77 + } 78 + naddrs = con->filters->nr_addrs; 79 + } 80 + 52 81 bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); 53 82 bpf_map__set_max_entries(skel->maps.task_filter, ntasks); 54 83 bpf_map__set_max_entries(skel->maps.type_filter, ntypes); 84 + bpf_map__set_max_entries(skel->maps.addr_filter, naddrs); 55 85 56 86 if (lock_contention_bpf__load(skel) < 0) { 57 87 pr_err("Failed to load lock-contention BPF skeleton\n"); ··· 131 101 132 102 for (i = 0; i < con->filters->nr_types; i++) 133 103 bpf_map_update_elem(fd, &con->filters->types[i], &val, BPF_ANY); 104 + } 105 + 106 + if (con->filters->nr_addrs) { 107 + u8 val = 1; 108 + 109 + skel->bss->has_addr = 1; 110 + fd = bpf_map__fd(skel->maps.addr_filter); 111 + 112 + for (i = 0; i < con->filters->nr_addrs; i++) 113 + bpf_map_update_elem(fd, &con->filters->addrs[i], &val, BPF_ANY); 134 114 } 135 115 136 116 /* these don't work well if in the rodata section */
+17
tools/perf/util/bpf_skel/lock_contention.bpf.c
··· 69 69 __uint(max_entries, 1); 70 70 } type_filter SEC(".maps"); 71 71 72 + struct { 73 + __uint(type, BPF_MAP_TYPE_HASH); 74 + __uint(key_size, sizeof(__u64)); 75 + __uint(value_size, sizeof(__u8)); 76 + __uint(max_entries, 1); 77 + } addr_filter SEC(".maps"); 78 + 72 79 /* control flags */ 73 80 int enabled; 74 81 int has_cpu; 75 82 int has_task; 76 83 int has_type; 84 + int has_addr; 77 85 int stack_skip; 78 86 79 87 /* determine the key of lock stat */ ··· 115 107 __u32 flags = (__u32)ctx[1]; 116 108 117 109 ok = bpf_map_lookup_elem(&type_filter, &flags); 110 + if (!ok) 111 + return 0; 112 + } 113 + 114 + if (has_addr) { 115 + __u8 *ok; 116 + __u64 addr = ctx[0]; 117 + 118 + ok = bpf_map_lookup_elem(&addr_filter, &addr); 118 119 if (!ok) 119 120 return 0; 120 121 }