linux-next/tools/perf/util/lock-contention.c
Ian Rogers 1a12ed09bc perf lock: Move common lock contention code to new file
Avoid references from util code to builtin-lock that require python
stubs. Move the functions and related variables to
util/lock-contention.c. Add max_stack_depth parameter to
match_callstack_filter to avoid sharing a global variable.

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Colin Ian King <colin.i.king@gmail.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ilya Leoshkevich <iii@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Veronika Molnarova <vmolnaro@redhat.com>
Cc: Weilin Wang <weilin.wang@intel.com>
Link: https://lore.kernel.org/r/20241119011644.971342-16-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2024-12-18 16:24:33 -03:00

144 lines
3.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include "debug.h"
#include "env.h"
#include "lock-contention.h"
#include "machine.h"
#include "symbol.h"
#include <limits.h>
#include <string.h>
#include <linux/hash.h>
#include <linux/zalloc.h>
#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
struct callstack_filter {
struct list_head list;
char name[];
};
static LIST_HEAD(callstack_filters);
struct hlist_head *lockhash_table;
int parse_call_stack(const struct option *opt __maybe_unused, const char *str,
int unset __maybe_unused)
{
char *s, *tmp, *tok;
int ret = 0;
s = strdup(str);
if (s == NULL)
return -1;
for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
struct callstack_filter *entry;
entry = malloc(sizeof(*entry) + strlen(tok) + 1);
if (entry == NULL) {
pr_err("Memory allocation failure\n");
free(s);
return -1;
}
strcpy(entry->name, tok);
list_add_tail(&entry->list, &callstack_filters);
}
free(s);
return ret;
}
bool needs_callstack(void)
{
return !list_empty(&callstack_filters);
}
struct lock_stat *lock_stat_find(u64 addr)
{
struct hlist_head *entry = lockhashentry(addr);
struct lock_stat *ret;
hlist_for_each_entry(ret, entry, hash_entry) {
if (ret->addr == addr)
return ret;
}
return NULL;
}
struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags)
{
struct hlist_head *entry = lockhashentry(addr);
struct lock_stat *ret, *new;
hlist_for_each_entry(ret, entry, hash_entry) {
if (ret->addr == addr)
return ret;
}
new = zalloc(sizeof(struct lock_stat));
if (!new)
goto alloc_failed;
new->addr = addr;
new->name = strdup(name);
if (!new->name) {
free(new);
goto alloc_failed;
}
new->flags = flags;
new->wait_time_min = ULLONG_MAX;
hlist_add_head(&new->hash_entry, entry);
return new;
alloc_failed:
pr_err("memory allocation failed\n");
return NULL;
}
bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_stack_depth)
{
struct map *kmap;
struct symbol *sym;
u64 ip;
const char *arch = perf_env__arch(machine->env);
if (list_empty(&callstack_filters))
return true;
for (int i = 0; i < max_stack_depth; i++) {
struct callstack_filter *filter;
/*
* In powerpc, the callchain saved by kernel always includes
* first three entries as the NIP (next instruction pointer),
* LR (link register), and the contents of LR save area in the
* second stack frame. In certain scenarios its possible to have
* invalid kernel instruction addresses in either LR or the second
* stack frame's LR. In that case, kernel will store that address as
* zero.
*
* The below check will continue to look into callstack,
* incase first or second callstack index entry has 0
* address for powerpc.
*/
if (!callstack || (!callstack[i] && (strcmp(arch, "powerpc") ||
(i != 1 && i != 2))))
break;
ip = callstack[i];
sym = machine__find_kernel_symbol(machine, ip, &kmap);
if (sym == NULL)
continue;
list_for_each_entry(filter, &callstack_filters, list) {
if (strstr(sym->name, filter->name))
return true;
}
}
return false;
}