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