1407b36f6SNamhyung Kim // SPDX-License-Identifier: GPL-2.0 2407b36f6SNamhyung Kim #include "util/debug.h" 36fda2405SNamhyung Kim #include "util/evlist.h" 4407b36f6SNamhyung Kim #include "util/machine.h" 5407b36f6SNamhyung Kim #include "util/map.h" 6407b36f6SNamhyung Kim #include "util/symbol.h" 76fda2405SNamhyung Kim #include "util/target.h" 86fda2405SNamhyung Kim #include "util/thread_map.h" 9407b36f6SNamhyung Kim #include "util/lock-contention.h" 10407b36f6SNamhyung Kim #include <linux/zalloc.h> 11a6eaf966SNamhyung Kim #include <linux/string.h> 12407b36f6SNamhyung Kim #include <bpf/bpf.h> 13407b36f6SNamhyung Kim 14407b36f6SNamhyung Kim #include "bpf_skel/lock_contention.skel.h" 15407b36f6SNamhyung Kim 16407b36f6SNamhyung Kim static struct lock_contention_bpf *skel; 17407b36f6SNamhyung Kim 18407b36f6SNamhyung Kim struct lock_contention_data { 19407b36f6SNamhyung Kim u64 total_time; 20407b36f6SNamhyung Kim u64 min_time; 21407b36f6SNamhyung Kim u64 max_time; 22407b36f6SNamhyung Kim u32 count; 23407b36f6SNamhyung Kim u32 flags; 24407b36f6SNamhyung Kim }; 25407b36f6SNamhyung Kim 26447ec4e5SNamhyung Kim int lock_contention_prepare(struct lock_contention *con) 27407b36f6SNamhyung Kim { 286fda2405SNamhyung Kim int i, fd; 296fda2405SNamhyung Kim int ncpus = 1, ntasks = 1; 30447ec4e5SNamhyung Kim struct evlist *evlist = con->evlist; 31447ec4e5SNamhyung Kim struct target *target = con->target; 326fda2405SNamhyung Kim 33407b36f6SNamhyung Kim skel = lock_contention_bpf__open(); 34407b36f6SNamhyung Kim if (!skel) { 35407b36f6SNamhyung Kim pr_err("Failed to open lock-contention BPF skeleton\n"); 36407b36f6SNamhyung Kim return -1; 37407b36f6SNamhyung Kim } 38407b36f6SNamhyung Kim 3996532a83SNamhyung Kim bpf_map__set_value_size(skel->maps.stacks, con->max_stack * sizeof(u64)); 40ceb13bfcSNamhyung Kim bpf_map__set_max_entries(skel->maps.stacks, con->map_nr_entries); 41ceb13bfcSNamhyung Kim bpf_map__set_max_entries(skel->maps.lock_stat, con->map_nr_entries); 42c66a36afSNamhyung Kim bpf_map__set_max_entries(skel->maps.tstamp, con->map_nr_entries); 43ceb13bfcSNamhyung Kim 446fda2405SNamhyung Kim if (target__has_cpu(target)) 456fda2405SNamhyung Kim ncpus = perf_cpu_map__nr(evlist->core.user_requested_cpus); 466fda2405SNamhyung Kim if (target__has_task(target)) 476fda2405SNamhyung Kim ntasks = perf_thread_map__nr(evlist->core.threads); 486fda2405SNamhyung Kim 496fda2405SNamhyung Kim bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); 506fda2405SNamhyung Kim bpf_map__set_max_entries(skel->maps.task_filter, ntasks); 516fda2405SNamhyung Kim 52407b36f6SNamhyung Kim if (lock_contention_bpf__load(skel) < 0) { 53407b36f6SNamhyung Kim pr_err("Failed to load lock-contention BPF skeleton\n"); 54407b36f6SNamhyung Kim return -1; 55407b36f6SNamhyung Kim } 56407b36f6SNamhyung Kim 576fda2405SNamhyung Kim if (target__has_cpu(target)) { 586fda2405SNamhyung Kim u32 cpu; 596fda2405SNamhyung Kim u8 val = 1; 606fda2405SNamhyung Kim 616fda2405SNamhyung Kim skel->bss->has_cpu = 1; 626fda2405SNamhyung Kim fd = bpf_map__fd(skel->maps.cpu_filter); 636fda2405SNamhyung Kim 646fda2405SNamhyung Kim for (i = 0; i < ncpus; i++) { 656fda2405SNamhyung Kim cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, i).cpu; 666fda2405SNamhyung Kim bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); 676fda2405SNamhyung Kim } 686fda2405SNamhyung Kim } 696fda2405SNamhyung Kim 706fda2405SNamhyung Kim if (target__has_task(target)) { 716fda2405SNamhyung Kim u32 pid; 726fda2405SNamhyung Kim u8 val = 1; 736fda2405SNamhyung Kim 746fda2405SNamhyung Kim skel->bss->has_task = 1; 756fda2405SNamhyung Kim fd = bpf_map__fd(skel->maps.task_filter); 766fda2405SNamhyung Kim 776fda2405SNamhyung Kim for (i = 0; i < ntasks; i++) { 786fda2405SNamhyung Kim pid = perf_thread_map__pid(evlist->core.threads, i); 796fda2405SNamhyung Kim bpf_map_update_elem(fd, &pid, &val, BPF_ANY); 806fda2405SNamhyung Kim } 816fda2405SNamhyung Kim } 826fda2405SNamhyung Kim 836fda2405SNamhyung Kim if (target__none(target) && evlist->workload.pid > 0) { 846fda2405SNamhyung Kim u32 pid = evlist->workload.pid; 856fda2405SNamhyung Kim u8 val = 1; 866fda2405SNamhyung Kim 876fda2405SNamhyung Kim skel->bss->has_task = 1; 886fda2405SNamhyung Kim fd = bpf_map__fd(skel->maps.task_filter); 896fda2405SNamhyung Kim bpf_map_update_elem(fd, &pid, &val, BPF_ANY); 906fda2405SNamhyung Kim } 916fda2405SNamhyung Kim 92c1da8dd5SNamhyung Kim skel->bss->stack_skip = con->stack_skip; 93c1da8dd5SNamhyung Kim 94407b36f6SNamhyung Kim lock_contention_bpf__attach(skel); 95407b36f6SNamhyung Kim return 0; 96407b36f6SNamhyung Kim } 97407b36f6SNamhyung Kim 98407b36f6SNamhyung Kim int lock_contention_start(void) 99407b36f6SNamhyung Kim { 100407b36f6SNamhyung Kim skel->bss->enabled = 1; 101407b36f6SNamhyung Kim return 0; 102407b36f6SNamhyung Kim } 103407b36f6SNamhyung Kim 104407b36f6SNamhyung Kim int lock_contention_stop(void) 105407b36f6SNamhyung Kim { 106407b36f6SNamhyung Kim skel->bss->enabled = 0; 107407b36f6SNamhyung Kim return 0; 108407b36f6SNamhyung Kim } 109407b36f6SNamhyung Kim 110447ec4e5SNamhyung Kim int lock_contention_read(struct lock_contention *con) 111407b36f6SNamhyung Kim { 1129e9c5f3cSNamhyung Kim int fd, stack, err = 0; 1136d499a6bSNamhyung Kim s32 prev_key, key; 114005ef2b4SNamhyung Kim struct lock_contention_data data = {}; 1159e9c5f3cSNamhyung Kim struct lock_stat *st = NULL; 116447ec4e5SNamhyung Kim struct machine *machine = con->machine; 1179e9c5f3cSNamhyung Kim u64 *stack_trace; 1189e9c5f3cSNamhyung Kim size_t stack_size = con->max_stack * sizeof(*stack_trace); 119407b36f6SNamhyung Kim 120407b36f6SNamhyung Kim fd = bpf_map__fd(skel->maps.lock_stat); 121407b36f6SNamhyung Kim stack = bpf_map__fd(skel->maps.stacks); 122407b36f6SNamhyung Kim 1236d499a6bSNamhyung Kim con->lost = skel->bss->lost; 1246d499a6bSNamhyung Kim 1259e9c5f3cSNamhyung Kim stack_trace = zalloc(stack_size); 1269e9c5f3cSNamhyung Kim if (stack_trace == NULL) 1279e9c5f3cSNamhyung Kim return -1; 1289e9c5f3cSNamhyung Kim 129407b36f6SNamhyung Kim prev_key = 0; 130407b36f6SNamhyung Kim while (!bpf_map_get_next_key(fd, &prev_key, &key)) { 131407b36f6SNamhyung Kim struct map *kmap; 132407b36f6SNamhyung Kim struct symbol *sym; 133c1da8dd5SNamhyung Kim int idx = 0; 134407b36f6SNamhyung Kim 1359e9c5f3cSNamhyung Kim /* to handle errors in the loop body */ 1369e9c5f3cSNamhyung Kim err = -1; 1379e9c5f3cSNamhyung Kim 138407b36f6SNamhyung Kim bpf_map_lookup_elem(fd, &key, &data); 139407b36f6SNamhyung Kim st = zalloc(sizeof(*st)); 140407b36f6SNamhyung Kim if (st == NULL) 1419e9c5f3cSNamhyung Kim break; 142407b36f6SNamhyung Kim 143407b36f6SNamhyung Kim st->nr_contended = data.count; 144407b36f6SNamhyung Kim st->wait_time_total = data.total_time; 145407b36f6SNamhyung Kim st->wait_time_max = data.max_time; 146407b36f6SNamhyung Kim st->wait_time_min = data.min_time; 147407b36f6SNamhyung Kim 148407b36f6SNamhyung Kim if (data.count) 149407b36f6SNamhyung Kim st->avg_wait_time = data.total_time / data.count; 150407b36f6SNamhyung Kim 151407b36f6SNamhyung Kim st->flags = data.flags; 152407b36f6SNamhyung Kim 153407b36f6SNamhyung Kim bpf_map_lookup_elem(stack, &key, stack_trace); 154407b36f6SNamhyung Kim 155c1da8dd5SNamhyung Kim /* skip lock internal functions */ 156*cc2367eeSArnaldo Carvalho de Melo while (machine__is_lock_function(machine, stack_trace[idx]) && 15796532a83SNamhyung Kim idx < con->max_stack - 1) 158407b36f6SNamhyung Kim idx++; 159407b36f6SNamhyung Kim 160407b36f6SNamhyung Kim st->addr = stack_trace[idx]; 161407b36f6SNamhyung Kim sym = machine__find_kernel_symbol(machine, st->addr, &kmap); 162407b36f6SNamhyung Kim 163407b36f6SNamhyung Kim if (sym) { 164407b36f6SNamhyung Kim unsigned long offset; 165407b36f6SNamhyung Kim int ret = 0; 166407b36f6SNamhyung Kim 167407b36f6SNamhyung Kim offset = kmap->map_ip(kmap, st->addr) - sym->start; 168407b36f6SNamhyung Kim 169407b36f6SNamhyung Kim if (offset) 170407b36f6SNamhyung Kim ret = asprintf(&st->name, "%s+%#lx", sym->name, offset); 171407b36f6SNamhyung Kim else 172407b36f6SNamhyung Kim st->name = strdup(sym->name); 173407b36f6SNamhyung Kim 174407b36f6SNamhyung Kim if (ret < 0 || st->name == NULL) 1759e9c5f3cSNamhyung Kim break; 176407b36f6SNamhyung Kim } else if (asprintf(&st->name, "%#lx", (unsigned long)st->addr) < 0) { 1779e9c5f3cSNamhyung Kim break; 178407b36f6SNamhyung Kim } 179407b36f6SNamhyung Kim 180a6eaf966SNamhyung Kim if (verbose) { 1819e9c5f3cSNamhyung Kim st->callstack = memdup(stack_trace, stack_size); 1829e9c5f3cSNamhyung Kim if (st->callstack == NULL) 1839e9c5f3cSNamhyung Kim break; 184a6eaf966SNamhyung Kim } 185a6eaf966SNamhyung Kim 186447ec4e5SNamhyung Kim hlist_add_head(&st->hash_entry, con->result); 187407b36f6SNamhyung Kim prev_key = key; 1889e9c5f3cSNamhyung Kim 1899e9c5f3cSNamhyung Kim /* we're fine now, reset the values */ 1909e9c5f3cSNamhyung Kim st = NULL; 1919e9c5f3cSNamhyung Kim err = 0; 192407b36f6SNamhyung Kim } 193407b36f6SNamhyung Kim 1949e9c5f3cSNamhyung Kim free(stack_trace); 1959e9c5f3cSNamhyung Kim if (st) { 1969e9c5f3cSNamhyung Kim free(st->name); 1979e9c5f3cSNamhyung Kim free(st); 1989e9c5f3cSNamhyung Kim } 1999e9c5f3cSNamhyung Kim 2009e9c5f3cSNamhyung Kim return err; 201407b36f6SNamhyung Kim } 202407b36f6SNamhyung Kim 203407b36f6SNamhyung Kim int lock_contention_finish(void) 204407b36f6SNamhyung Kim { 205407b36f6SNamhyung Kim if (skel) { 206407b36f6SNamhyung Kim skel->bss->enabled = 0; 207407b36f6SNamhyung Kim lock_contention_bpf__destroy(skel); 208407b36f6SNamhyung Kim } 209407b36f6SNamhyung Kim 210407b36f6SNamhyung Kim return 0; 211407b36f6SNamhyung Kim } 212