]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf lock: Move common lock contention code to new file
authorIan Rogers <irogers@google.com>
Tue, 19 Nov 2024 01:16:37 +0000 (17:16 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 18 Dec 2024 19:24:33 +0000 (16:24 -0300)
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>
tools/perf/builtin-lock.c
tools/perf/util/Build
tools/perf/util/bpf_lock_contention.c
tools/perf/util/lock-contention.c [new file with mode: 0644]
tools/perf/util/lock-contention.h
tools/perf/util/python.c

index 062e2b56a2ab570ead5e9da4bba99e29b18d3fde..f66948b1fbed96de1297198de0aa45b572683d3d 100644 (file)
 static struct perf_session *session;
 static struct target target;
 
-/* based on kernel/lockdep.c */
-#define LOCKHASH_BITS          12
-#define LOCKHASH_SIZE          (1UL << LOCKHASH_BITS)
-
-static struct hlist_head *lockhash_table;
-
-#define __lockhashfn(key)      hash_long((unsigned long)key, LOCKHASH_BITS)
-#define lockhashentry(key)     (lockhash_table + __lockhashfn((key)))
-
 static struct rb_root          thread_stats;
 
 static bool combine_locks;
@@ -67,24 +58,13 @@ static unsigned long bpf_map_entries = MAX_ENTRIES;
 static int max_stack_depth = CONTENTION_STACK_DEPTH;
 static int stack_skip = CONTENTION_STACK_SKIP;
 static int print_nr_entries = INT_MAX / 2;
-static LIST_HEAD(callstack_filters);
 static const char *output_name = NULL;
 static FILE *lock_output;
 
-struct callstack_filter {
-       struct list_head list;
-       char name[];
-};
-
 static struct lock_filter filters;
 
 static enum lock_aggr_mode aggr_mode = LOCK_AGGR_ADDR;
 
-static bool needs_callstack(void)
-{
-       return !list_empty(&callstack_filters);
-}
-
 static struct thread_stat *thread_stat_find(u32 tid)
 {
        struct rb_node *node;
@@ -477,93 +457,6 @@ static struct lock_stat *pop_from_result(void)
        return container_of(node, struct lock_stat, rb);
 }
 
-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)
-{
-       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;
-}
-
 struct trace_lock_handler {
        /* it's used on CONFIG_LOCKDEP */
        int (*acquire_event)(struct evsel *evsel,
@@ -1165,7 +1058,7 @@ static int report_lock_contention_begin_event(struct evsel *evsel,
                if (callstack == NULL)
                        return -ENOMEM;
 
-               if (!match_callstack_filter(machine, callstack)) {
+               if (!match_callstack_filter(machine, callstack, max_stack_depth)) {
                        free(callstack);
                        return 0;
                }
@@ -2449,34 +2342,6 @@ static int parse_lock_addr(const struct option *opt __maybe_unused, const char *
        return ret;
 }
 
-static 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;
-}
-
 static int parse_output(const struct option *opt __maybe_unused, const char *str,
                        int unset __maybe_unused)
 {
index f8e77c53e2f9f1b786a6b136f7b205507f8f7f99..5ec97e8d6b6dd9ef0a0d8ff83f54b5f94cb8660e 100644 (file)
@@ -122,6 +122,7 @@ perf-util-y += topdown.o
 perf-util-y += iostat.o
 perf-util-y += stream.o
 perf-util-y += kvm-stat.o
+perf-util-y += lock-contention.o
 perf-util-$(CONFIG_AUXTRACE) += auxtrace.o
 perf-util-y += intel-pt-decoder/
 perf-util-$(CONFIG_AUXTRACE) += intel-pt.o
index 41a1ad08789511c39da6d9b83a030fbb6164ae3d..37e17c56f1064e60f5bc8676dabd630d437dcfa3 100644 (file)
@@ -458,7 +458,7 @@ int lock_contention_read(struct lock_contention *con)
                if (con->save_callstack) {
                        bpf_map_lookup_elem(stack, &key.stack_id, stack_trace);
 
-                       if (!match_callstack_filter(machine, stack_trace)) {
+                       if (!match_callstack_filter(machine, stack_trace, con->max_stack)) {
                                con->nr_filtered += data.count;
                                goto next;
                        }
diff --git a/tools/perf/util/lock-contention.c b/tools/perf/util/lock-contention.c
new file mode 100644 (file)
index 0000000..92e7b7b
--- /dev/null
@@ -0,0 +1,143 @@
+// 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;
+}
index 1a7248ff388947e12b5cc109a88c8ac924dbc40c..bd71fb73825aa8e19178aa817eb7939abd5b5307 100644 (file)
@@ -67,10 +67,11 @@ struct lock_stat {
  */
 #define MAX_LOCK_DEPTH 48
 
-struct lock_stat *lock_stat_find(u64 addr);
-struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags);
+/* based on kernel/lockdep.c */
+#define LOCKHASH_BITS          12
+#define LOCKHASH_SIZE          (1UL << LOCKHASH_BITS)
 
-bool match_callstack_filter(struct machine *machine, u64 *callstack);
+extern struct hlist_head *lockhash_table;
 
 /*
  * struct lock_seq_stat:
@@ -148,8 +149,17 @@ struct lock_contention {
        bool save_callstack;
 };
 
-#ifdef HAVE_BPF_SKEL
+struct option;
+int parse_call_stack(const struct option *opt, const char *str, int unset);
+bool needs_callstack(void);
 
+struct lock_stat *lock_stat_find(u64 addr);
+struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags);
+
+bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_stack_depth);
+
+
+#ifdef HAVE_BPF_SKEL
 int lock_contention_prepare(struct lock_contention *con);
 int lock_contention_start(void);
 int lock_contention_stop(void);
index fa25e7ed8a7f9dbe3a676888e6f0d438a79f8abf..6851f9b07e04d33fd3d9e33097066b96b731fed2 100644 (file)
@@ -18,7 +18,6 @@
 #include "mmap.h"
 #include "util/kwork.h"
 #include "util/sample.h"
-#include "util/lock-contention.h"
 #include <internal/lib.h>
 #include "../builtin.h"
 
@@ -1311,22 +1310,6 @@ struct kwork_work *perf_kwork_add_work(struct perf_kwork *kwork __maybe_unused,
        return NULL;
 }
 
-bool match_callstack_filter(struct machine *machine __maybe_unused, u64 *callstack __maybe_unused)
-{
-       return false;
-}
-
-struct lock_stat *lock_stat_find(u64 addr __maybe_unused)
-{
-       return NULL;
-}
-
-struct lock_stat *lock_stat_findnew(u64 addr __maybe_unused, const char *name __maybe_unused,
-                               int flags __maybe_unused)
-{
-       return NULL;
-}
-
 int cmd_inject(int argc __maybe_unused, const char *argv[] __maybe_unused)
 {
        return -1;