xref: /linux/tools/perf/util/lock-contention.c (revision 7685b334d1e4927cc73b62c65293ba65748d9c52)
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 }
144