]> Git Repo - linux.git/blob - tools/perf/util/lock-contention.c
Linux 6.14-rc3
[linux.git] / tools / perf / util / lock-contention.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "debug.h"
3 #include "env.h"
4 #include "lock-contention.h"
5 #include "machine.h"
6 #include "symbol.h"
7
8 #include <limits.h>
9 #include <string.h>
10
11 #include <linux/hash.h>
12 #include <linux/zalloc.h>
13
14 #define __lockhashfn(key)       hash_long((unsigned long)key, LOCKHASH_BITS)
15 #define lockhashentry(key)      (lockhash_table + __lockhashfn((key)))
16
17 struct callstack_filter {
18         struct list_head list;
19         char name[];
20 };
21
22 static LIST_HEAD(callstack_filters);
23 struct hlist_head *lockhash_table;
24
25 int parse_call_stack(const struct option *opt __maybe_unused, const char *str,
26                      int unset __maybe_unused)
27 {
28         char *s, *tmp, *tok;
29         int ret = 0;
30
31         s = strdup(str);
32         if (s == NULL)
33                 return -1;
34
35         for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
36                 struct callstack_filter *entry;
37
38                 entry = malloc(sizeof(*entry) + strlen(tok) + 1);
39                 if (entry == NULL) {
40                         pr_err("Memory allocation failure\n");
41                         free(s);
42                         return -1;
43                 }
44
45                 strcpy(entry->name, tok);
46                 list_add_tail(&entry->list, &callstack_filters);
47         }
48
49         free(s);
50         return ret;
51 }
52
53 bool needs_callstack(void)
54 {
55         return !list_empty(&callstack_filters);
56 }
57
58 struct lock_stat *lock_stat_find(u64 addr)
59 {
60         struct hlist_head *entry = lockhashentry(addr);
61         struct lock_stat *ret;
62
63         hlist_for_each_entry(ret, entry, hash_entry) {
64                 if (ret->addr == addr)
65                         return ret;
66         }
67         return NULL;
68 }
69
70 struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags)
71 {
72         struct hlist_head *entry = lockhashentry(addr);
73         struct lock_stat *ret, *new;
74
75         hlist_for_each_entry(ret, entry, hash_entry) {
76                 if (ret->addr == addr)
77                         return ret;
78         }
79
80         new = zalloc(sizeof(struct lock_stat));
81         if (!new)
82                 goto alloc_failed;
83
84         new->addr = addr;
85         new->name = strdup(name);
86         if (!new->name) {
87                 free(new);
88                 goto alloc_failed;
89         }
90
91         new->flags = flags;
92         new->wait_time_min = ULLONG_MAX;
93
94         hlist_add_head(&new->hash_entry, entry);
95         return new;
96
97 alloc_failed:
98         pr_err("memory allocation failed\n");
99         return NULL;
100 }
101
102 bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_stack_depth)
103 {
104         struct map *kmap;
105         struct symbol *sym;
106         u64 ip;
107         const char *arch = perf_env__arch(machine->env);
108
109         if (list_empty(&callstack_filters))
110                 return true;
111
112         for (int i = 0; i < max_stack_depth; i++) {
113                 struct callstack_filter *filter;
114
115                 /*
116                  * In powerpc, the callchain saved by kernel always includes
117                  * first three entries as the NIP (next instruction pointer),
118                  * LR (link register), and the contents of LR save area in the
119                  * second stack frame. In certain scenarios its possible to have
120                  * invalid kernel instruction addresses in either LR or the second
121                  * stack frame's LR. In that case, kernel will store that address as
122                  * zero.
123                  *
124                  * The below check will continue to look into callstack,
125                  * incase first or second callstack index entry has 0
126                  * address for powerpc.
127                  */
128                 if (!callstack || (!callstack[i] && (strcmp(arch, "powerpc") ||
129                                                 (i != 1 && i != 2))))
130                         break;
131
132                 ip = callstack[i];
133                 sym = machine__find_kernel_symbol(machine, ip, &kmap);
134                 if (sym == NULL)
135                         continue;
136
137                 list_for_each_entry(filter, &callstack_filters, list) {
138                         if (strstr(sym->name, filter->name))
139                                 return true;
140                 }
141         }
142         return false;
143 }
This page took 0.038428 seconds and 4 git commands to generate.