mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-17 05:45:20 +00:00
1a12ed09bc
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>
144 lines
3.2 KiB
C
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;
|
|
}
|