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" 15*fd507d3eSNamhyung Kim #include "bpf_skel/lock_data.h" 16407b36f6SNamhyung Kim 17407b36f6SNamhyung Kim static struct lock_contention_bpf *skel; 18407b36f6SNamhyung Kim 19447ec4e5SNamhyung Kim int lock_contention_prepare(struct lock_contention *con) 20407b36f6SNamhyung Kim { 216fda2405SNamhyung Kim int i, fd; 226fda2405SNamhyung Kim int ncpus = 1, ntasks = 1; 23447ec4e5SNamhyung Kim struct evlist *evlist = con->evlist; 24447ec4e5SNamhyung Kim struct target *target = con->target; 256fda2405SNamhyung Kim 26407b36f6SNamhyung Kim skel = lock_contention_bpf__open(); 27407b36f6SNamhyung Kim if (!skel) { 28407b36f6SNamhyung Kim pr_err("Failed to open lock-contention BPF skeleton\n"); 29407b36f6SNamhyung Kim return -1; 30407b36f6SNamhyung Kim } 31407b36f6SNamhyung Kim 3296532a83SNamhyung Kim bpf_map__set_value_size(skel->maps.stacks, con->max_stack * sizeof(u64)); 33ceb13bfcSNamhyung Kim bpf_map__set_max_entries(skel->maps.stacks, con->map_nr_entries); 34ceb13bfcSNamhyung Kim bpf_map__set_max_entries(skel->maps.lock_stat, con->map_nr_entries); 35c66a36afSNamhyung Kim bpf_map__set_max_entries(skel->maps.tstamp, con->map_nr_entries); 36ceb13bfcSNamhyung Kim 376fda2405SNamhyung Kim if (target__has_cpu(target)) 386fda2405SNamhyung Kim ncpus = perf_cpu_map__nr(evlist->core.user_requested_cpus); 396fda2405SNamhyung Kim if (target__has_task(target)) 406fda2405SNamhyung Kim ntasks = perf_thread_map__nr(evlist->core.threads); 416fda2405SNamhyung Kim 426fda2405SNamhyung Kim bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); 436fda2405SNamhyung Kim bpf_map__set_max_entries(skel->maps.task_filter, ntasks); 446fda2405SNamhyung Kim 45407b36f6SNamhyung Kim if (lock_contention_bpf__load(skel) < 0) { 46407b36f6SNamhyung Kim pr_err("Failed to load lock-contention BPF skeleton\n"); 47407b36f6SNamhyung Kim return -1; 48407b36f6SNamhyung Kim } 49407b36f6SNamhyung Kim 506fda2405SNamhyung Kim if (target__has_cpu(target)) { 516fda2405SNamhyung Kim u32 cpu; 526fda2405SNamhyung Kim u8 val = 1; 536fda2405SNamhyung Kim 546fda2405SNamhyung Kim skel->bss->has_cpu = 1; 556fda2405SNamhyung Kim fd = bpf_map__fd(skel->maps.cpu_filter); 566fda2405SNamhyung Kim 576fda2405SNamhyung Kim for (i = 0; i < ncpus; i++) { 586fda2405SNamhyung Kim cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, i).cpu; 596fda2405SNamhyung Kim bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); 606fda2405SNamhyung Kim } 616fda2405SNamhyung Kim } 626fda2405SNamhyung Kim 636fda2405SNamhyung Kim if (target__has_task(target)) { 646fda2405SNamhyung Kim u32 pid; 656fda2405SNamhyung Kim u8 val = 1; 666fda2405SNamhyung Kim 676fda2405SNamhyung Kim skel->bss->has_task = 1; 686fda2405SNamhyung Kim fd = bpf_map__fd(skel->maps.task_filter); 696fda2405SNamhyung Kim 706fda2405SNamhyung Kim for (i = 0; i < ntasks; i++) { 716fda2405SNamhyung Kim pid = perf_thread_map__pid(evlist->core.threads, i); 726fda2405SNamhyung Kim bpf_map_update_elem(fd, &pid, &val, BPF_ANY); 736fda2405SNamhyung Kim } 746fda2405SNamhyung Kim } 756fda2405SNamhyung Kim 766fda2405SNamhyung Kim if (target__none(target) && evlist->workload.pid > 0) { 776fda2405SNamhyung Kim u32 pid = evlist->workload.pid; 786fda2405SNamhyung Kim u8 val = 1; 796fda2405SNamhyung Kim 806fda2405SNamhyung Kim skel->bss->has_task = 1; 816fda2405SNamhyung Kim fd = bpf_map__fd(skel->maps.task_filter); 826fda2405SNamhyung Kim bpf_map_update_elem(fd, &pid, &val, BPF_ANY); 836fda2405SNamhyung Kim } 846fda2405SNamhyung Kim 85c1da8dd5SNamhyung Kim skel->bss->stack_skip = con->stack_skip; 86c1da8dd5SNamhyung Kim 87407b36f6SNamhyung Kim lock_contention_bpf__attach(skel); 88407b36f6SNamhyung Kim return 0; 89407b36f6SNamhyung Kim } 90407b36f6SNamhyung Kim 91407b36f6SNamhyung Kim int lock_contention_start(void) 92407b36f6SNamhyung Kim { 93407b36f6SNamhyung Kim skel->bss->enabled = 1; 94407b36f6SNamhyung Kim return 0; 95407b36f6SNamhyung Kim } 96407b36f6SNamhyung Kim 97407b36f6SNamhyung Kim int lock_contention_stop(void) 98407b36f6SNamhyung Kim { 99407b36f6SNamhyung Kim skel->bss->enabled = 0; 100407b36f6SNamhyung Kim return 0; 101407b36f6SNamhyung Kim } 102407b36f6SNamhyung Kim 103447ec4e5SNamhyung Kim int lock_contention_read(struct lock_contention *con) 104407b36f6SNamhyung Kim { 1059e9c5f3cSNamhyung Kim int fd, stack, err = 0; 106*fd507d3eSNamhyung Kim struct contention_key *prev_key, key; 107*fd507d3eSNamhyung Kim struct contention_data data = {}; 1089e9c5f3cSNamhyung Kim struct lock_stat *st = NULL; 109447ec4e5SNamhyung Kim struct machine *machine = con->machine; 1109e9c5f3cSNamhyung Kim u64 *stack_trace; 1119e9c5f3cSNamhyung Kim size_t stack_size = con->max_stack * sizeof(*stack_trace); 112407b36f6SNamhyung Kim 113407b36f6SNamhyung Kim fd = bpf_map__fd(skel->maps.lock_stat); 114407b36f6SNamhyung Kim stack = bpf_map__fd(skel->maps.stacks); 115407b36f6SNamhyung Kim 1166d499a6bSNamhyung Kim con->lost = skel->bss->lost; 1176d499a6bSNamhyung Kim 1189e9c5f3cSNamhyung Kim stack_trace = zalloc(stack_size); 1199e9c5f3cSNamhyung Kim if (stack_trace == NULL) 1209e9c5f3cSNamhyung Kim return -1; 1219e9c5f3cSNamhyung Kim 122*fd507d3eSNamhyung Kim prev_key = NULL; 123*fd507d3eSNamhyung Kim while (!bpf_map_get_next_key(fd, prev_key, &key)) { 124407b36f6SNamhyung Kim struct map *kmap; 125407b36f6SNamhyung Kim struct symbol *sym; 126c1da8dd5SNamhyung Kim int idx = 0; 127407b36f6SNamhyung Kim 1289e9c5f3cSNamhyung Kim /* to handle errors in the loop body */ 1299e9c5f3cSNamhyung Kim err = -1; 1309e9c5f3cSNamhyung Kim 131407b36f6SNamhyung Kim bpf_map_lookup_elem(fd, &key, &data); 132407b36f6SNamhyung Kim st = zalloc(sizeof(*st)); 133407b36f6SNamhyung Kim if (st == NULL) 1349e9c5f3cSNamhyung Kim break; 135407b36f6SNamhyung Kim 136407b36f6SNamhyung Kim st->nr_contended = data.count; 137407b36f6SNamhyung Kim st->wait_time_total = data.total_time; 138407b36f6SNamhyung Kim st->wait_time_max = data.max_time; 139407b36f6SNamhyung Kim st->wait_time_min = data.min_time; 140407b36f6SNamhyung Kim 141407b36f6SNamhyung Kim if (data.count) 142407b36f6SNamhyung Kim st->avg_wait_time = data.total_time / data.count; 143407b36f6SNamhyung Kim 144407b36f6SNamhyung Kim st->flags = data.flags; 145407b36f6SNamhyung Kim 146407b36f6SNamhyung Kim bpf_map_lookup_elem(stack, &key, stack_trace); 147407b36f6SNamhyung Kim 148c1da8dd5SNamhyung Kim /* skip lock internal functions */ 149cc2367eeSArnaldo Carvalho de Melo while (machine__is_lock_function(machine, stack_trace[idx]) && 15096532a83SNamhyung Kim idx < con->max_stack - 1) 151407b36f6SNamhyung Kim idx++; 152407b36f6SNamhyung Kim 153407b36f6SNamhyung Kim st->addr = stack_trace[idx]; 154407b36f6SNamhyung Kim sym = machine__find_kernel_symbol(machine, st->addr, &kmap); 155407b36f6SNamhyung Kim 156407b36f6SNamhyung Kim if (sym) { 157407b36f6SNamhyung Kim unsigned long offset; 158407b36f6SNamhyung Kim int ret = 0; 159407b36f6SNamhyung Kim 160407b36f6SNamhyung Kim offset = kmap->map_ip(kmap, st->addr) - sym->start; 161407b36f6SNamhyung Kim 162407b36f6SNamhyung Kim if (offset) 163407b36f6SNamhyung Kim ret = asprintf(&st->name, "%s+%#lx", sym->name, offset); 164407b36f6SNamhyung Kim else 165407b36f6SNamhyung Kim st->name = strdup(sym->name); 166407b36f6SNamhyung Kim 167407b36f6SNamhyung Kim if (ret < 0 || st->name == NULL) 1689e9c5f3cSNamhyung Kim break; 169407b36f6SNamhyung Kim } else if (asprintf(&st->name, "%#lx", (unsigned long)st->addr) < 0) { 1709e9c5f3cSNamhyung Kim break; 171407b36f6SNamhyung Kim } 172407b36f6SNamhyung Kim 173a6eaf966SNamhyung Kim if (verbose) { 1749e9c5f3cSNamhyung Kim st->callstack = memdup(stack_trace, stack_size); 1759e9c5f3cSNamhyung Kim if (st->callstack == NULL) 1769e9c5f3cSNamhyung Kim break; 177a6eaf966SNamhyung Kim } 178a6eaf966SNamhyung Kim 179447ec4e5SNamhyung Kim hlist_add_head(&st->hash_entry, con->result); 180*fd507d3eSNamhyung Kim prev_key = &key; 1819e9c5f3cSNamhyung Kim 1829e9c5f3cSNamhyung Kim /* we're fine now, reset the values */ 1839e9c5f3cSNamhyung Kim st = NULL; 1849e9c5f3cSNamhyung Kim err = 0; 185407b36f6SNamhyung Kim } 186407b36f6SNamhyung Kim 1879e9c5f3cSNamhyung Kim free(stack_trace); 1889e9c5f3cSNamhyung Kim if (st) { 1899e9c5f3cSNamhyung Kim free(st->name); 1909e9c5f3cSNamhyung Kim free(st); 1919e9c5f3cSNamhyung Kim } 1929e9c5f3cSNamhyung Kim 1939e9c5f3cSNamhyung Kim return err; 194407b36f6SNamhyung Kim } 195407b36f6SNamhyung Kim 196407b36f6SNamhyung Kim int lock_contention_finish(void) 197407b36f6SNamhyung Kim { 198407b36f6SNamhyung Kim if (skel) { 199407b36f6SNamhyung Kim skel->bss->enabled = 0; 200407b36f6SNamhyung Kim lock_contention_bpf__destroy(skel); 201407b36f6SNamhyung Kim } 202407b36f6SNamhyung Kim 203407b36f6SNamhyung Kim return 0; 204407b36f6SNamhyung Kim } 205