File Index
Files and directories
Sign in
FILE

lock-contention.c

File preview with syntax highlighting.

linux-6.19.14/tools/perf/util/lock-contention.c 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
 17struct callstack_filter {
 18	struct list_head list;
 19	char name[];
 20};
 21
 22static LIST_HEAD(callstack_filters);
 23struct hlist_head *lockhash_table;
 24
 25int 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
 53bool needs_callstack(void)
 54{
 55	return !list_empty(&callstack_filters);
 56}
 57
 58struct 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
 70struct 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
 97alloc_failed:
 98	pr_err("memory allocation failed\n");
 99	return NULL;
100}
101
102bool 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}
~/ Read-only file preview.