From nobody Mon Nov 25 07:22:32 2024 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2A37120E03E for ; Tue, 29 Oct 2024 22:45:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730241909; cv=none; b=N3DD5n0t4VI+vB9xJUILjKTQ2GUNH3tnhVJ9aHYbb3Z+b81VRZwT09mIt+DoWpwwcUN+Raq+9itjLYMLdm53WyLTTFa4d0cKi51ZepC8WvUAAxNzO+8TuKxtXX0yAEJsHlXzO+GCOMQLhCJOCV6QazYge8lWYmsiR3gXhQ2oRQw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730241909; c=relaxed/simple; bh=VDsV7b3OX/emG3gjapt2R1JtoaiE0+25N7pa2k/w/TA=; h=Date:In-Reply-To:Message-Id:Mime-Version:References:Subject:From: To:Content-Type; b=gXw4s1bkm+2lYedfQuHWGvsUJE/GuBZJ9ENf046BOw9zR/ckTYaXJ9gmEmAILoPry1Si0Nxqhi59OdLt69lxLX5kJb38glDno1FGeBEE7fbLYtptZdbi5O30eB7TY/tFEcSjMn3wCDnXOJQpFWi8lPtYMQh4gQ7Wdg3MzCX/Cag= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=GM6qnQyW; arc=none smtp.client-ip=209.85.128.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="GM6qnQyW" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-6e38562155bso88018197b3.1 for ; Tue, 29 Oct 2024 15:45:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1730241905; x=1730846705; darn=vger.kernel.org; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=bq7Yn07vcD3vGYwxT4kETwlahqFzcX5Rgl53aad5ETM=; b=GM6qnQyWvhQ6jsh6irPkfvcKDBOFAgD+c0uLrxoZl8KOUqM12Nz5kpimv6BMSaJgjb PX5PHV58yUqRoQRjhAyaiHHLEW0JvH0Me8cm4JfGl/iej0fPxLygC9FxJxnBnPMWv5ES foQL9tS8xyjNgiC73rh1o2SeUprNAdGKPzQFSfT9bFSsOkTs/0q76o/yiuqqU/X4QyLp JU3HrF9KPtlx60jsic4xOBim3Nly+uLahPxIkoQPACMeKVZDp5LD70BZk5qUemucjGI7 D7QHDF4DB2KmYQIqNldsTmQl5irgmThF8eJAMYMXyFPl9wFxiFE3kbSNhGU1jOuSQ0Kk hedQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730241905; x=1730846705; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=bq7Yn07vcD3vGYwxT4kETwlahqFzcX5Rgl53aad5ETM=; b=bvLUxb/Nb5mFi5gXkZEHqqTD6QLXFrjlXBODgJdxmXQ/xjRbC0KnUnaoObgNxxA0JK PyRDTjtapAmW1aQtKnS4+yIwEDXYLcoBHUTNFXLtBXF760R7kR+QYDDVzHer9aOBnwMK Sy2ivF3nXxa5kh+3mS/kC0b66FR0vBcxnk7PLMaCaa4ydMRjy0FSDISqkbxq/ik1r9pV A0FE9m8MctQW0KGj62LYfTomjH4HLFs9ZWEMDlSGEklCscCHKc81YldX7GMQbBgwJpoW /wMhpOinQDpULoYt+OxV3aEOiQhNk+BDUfA+lBjRw0+cW33iwg219FQyRDa0dXaAQ9yx nNiQ== X-Forwarded-Encrypted: i=1; AJvYcCWda2f85fhuN7l65ZZMy4I9bOQLZnhRXdBg75OjROcjXVtLmvtgbXszku10gLl9uPt5ySeE91Yd6Y6/BUU=@vger.kernel.org X-Gm-Message-State: AOJu0YzC2KeGAGmFWbvFtO7DuTZRcsU6pbLvv1z8NvNfOjYKk56o/X9H SoxRTk4CXowTycglIVWo3ThLVkuCZoOA8YhoCgqRREZHYUAo7HeSdn9o7IIB4mYQ8jwVxBOW51B rBn0YSQ== X-Google-Smtp-Source: AGHT+IHOuhal+mAGelAxUnrI8QP+h//1b0G8Ky0o5eO4R/EMlbmG9cgGa1znQd0Et9hMZhFTYOtvQwYOX4aj X-Received: from irogers.svl.corp.google.com ([2620:15c:2c5:11:8991:d3fd:38a7:c282]) (user=irogers job=sendgmr) by 2002:a05:690c:4a02:b0:6e3:b08:92c7 with SMTP id 00721157ae682-6e9d87070a8mr8170337b3.0.1730241905103; Tue, 29 Oct 2024 15:45:05 -0700 (PDT) Date: Tue, 29 Oct 2024 15:44:24 -0700 In-Reply-To: <20241029224431.167623-1-irogers@google.com> Message-Id: <20241029224431.167623-13-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241029224431.167623-1-irogers@google.com> X-Mailer: git-send-email 2.47.0.163.g1226f6d8fa-goog Subject: [PATCH v4 12/19] perf lock: Move common lock contention code to new file From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , James Clark , Howard Chu , Athira Jajeev , Michael Petlan , Veronika Molnarova , Dapeng Mi , Thomas Richter , Ilya Leoshkevich , Colin Ian King , Weilin Wang , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- tools/perf/builtin-lock.c | 137 +-------------------- tools/perf/util/Build | 1 + tools/perf/util/bpf_lock_contention.c | 2 +- tools/perf/util/lock-contention.c | 170 ++++++++++++++++++++++++++ tools/perf/util/lock-contention.h | 37 ++---- tools/perf/util/python.c | 17 --- 6 files changed, 185 insertions(+), 179 deletions(-) create mode 100644 tools/perf/util/lock-contention.c diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 062e2b56a2ab..f66948b1fbed 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -46,15 +46,6 @@ static struct perf_session *session; static struct target target; =20 -/* 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; =20 static bool combine_locks; @@ -67,24 +58,13 @@ static unsigned long bpf_map_entries =3D MAX_ENTRIES; static int max_stack_depth =3D CONTENTION_STACK_DEPTH; static int stack_skip =3D CONTENTION_STACK_SKIP; static int print_nr_entries =3D INT_MAX / 2; -static LIST_HEAD(callstack_filters); static const char *output_name =3D NULL; static FILE *lock_output; =20 -struct callstack_filter { - struct list_head list; - char name[]; -}; - static struct lock_filter filters; =20 static enum lock_aggr_mode aggr_mode =3D LOCK_AGGR_ADDR; =20 -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); } =20 -struct lock_stat *lock_stat_find(u64 addr) -{ - struct hlist_head *entry =3D lockhashentry(addr); - struct lock_stat *ret; - - hlist_for_each_entry(ret, entry, hash_entry) { - if (ret->addr =3D=3D addr) - return ret; - } - return NULL; -} - -struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags) -{ - struct hlist_head *entry =3D lockhashentry(addr); - struct lock_stat *ret, *new; - - hlist_for_each_entry(ret, entry, hash_entry) { - if (ret->addr =3D=3D addr) - return ret; - } - - new =3D zalloc(sizeof(struct lock_stat)); - if (!new) - goto alloc_failed; - - new->addr =3D addr; - new->name =3D strdup(name); - if (!new->name) { - free(new); - goto alloc_failed; - } - - new->flags =3D flags; - new->wait_time_min =3D 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 =3D perf_env__arch(machine->env); - - if (list_empty(&callstack_filters)) - return true; - - for (int i =3D 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 !=3D 1 && i !=3D 2)))) - break; - - ip =3D callstack[i]; - sym =3D machine__find_kernel_symbol(machine, ip, &kmap); - if (sym =3D=3D 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 =3D=3D NULL) return -ENOMEM; =20 - 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; } =20 -static int parse_call_stack(const struct option *opt __maybe_unused, const= char *str, - int unset __maybe_unused) -{ - char *s, *tmp, *tok; - int ret =3D 0; - - s =3D strdup(str); - if (s =3D=3D NULL) - return -1; - - for (tok =3D strtok_r(s, ", ", &tmp); tok; tok =3D strtok_r(NULL, ", ", &= tmp)) { - struct callstack_filter *entry; - - entry =3D malloc(sizeof(*entry) + strlen(tok) + 1); - if (entry =3D=3D 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 cha= r *str, int unset __maybe_unused) { diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 650974413849..e6404d2c598b 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -121,6 +121,7 @@ perf-util-y +=3D topdown.o perf-util-y +=3D iostat.o perf-util-y +=3D stream.o perf-util-y +=3D kvm-stat.o +perf-util-y +=3D lock-contention.o perf-util-$(CONFIG_AUXTRACE) +=3D auxtrace.o perf-util-$(CONFIG_AUXTRACE) +=3D intel-pt-decoder/ perf-util-$(CONFIG_AUXTRACE) +=3D intel-pt.o diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lo= ck_contention.c index 41a1ad087895..37e17c56f106 100644 --- a/tools/perf/util/bpf_lock_contention.c +++ b/tools/perf/util/bpf_lock_contention.c @@ -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); =20 - if (!match_callstack_filter(machine, stack_trace)) { + if (!match_callstack_filter(machine, stack_trace, con->max_stack)) { con->nr_filtered +=3D data.count; goto next; } diff --git a/tools/perf/util/lock-contention.c b/tools/perf/util/lock-conte= ntion.c new file mode 100644 index 000000000000..841bb18b1f06 --- /dev/null +++ b/tools/perf/util/lock-contention.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "debug.h" +#include "env.h" +#include "lock-contention.h" +#include "machine.h" +#include "symbol.h" + +#include +#include + +#include +#include + +#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 =3D 0; + + s =3D strdup(str); + if (s =3D=3D NULL) + return -1; + + for (tok =3D strtok_r(s, ", ", &tmp); tok; tok =3D strtok_r(NULL, ", ", &= tmp)) { + struct callstack_filter *entry; + + entry =3D malloc(sizeof(*entry) + strlen(tok) + 1); + if (entry =3D=3D 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 =3D lockhashentry(addr); + struct lock_stat *ret; + + hlist_for_each_entry(ret, entry, hash_entry) { + if (ret->addr =3D=3D addr) + return ret; + } + return NULL; +} + +struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags) +{ + struct hlist_head *entry =3D lockhashentry(addr); + struct lock_stat *ret, *new; + + hlist_for_each_entry(ret, entry, hash_entry) { + if (ret->addr =3D=3D addr) + return ret; + } + + new =3D zalloc(sizeof(struct lock_stat)); + if (!new) + goto alloc_failed; + + new->addr =3D addr; + new->name =3D strdup(name); + if (!new->name) { + free(new); + goto alloc_failed; + } + + new->flags =3D flags; + new->wait_time_min =3D 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 m= ax_stack_depth) +{ + struct map *kmap; + struct symbol *sym; + u64 ip; + const char *arch =3D perf_env__arch(machine->env); + + if (list_empty(&callstack_filters)) + return true; + + for (int i =3D 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 !=3D 1 && i !=3D 2)))) + break; + + ip =3D callstack[i]; + sym =3D machine__find_kernel_symbol(machine, ip, &kmap); + if (sym =3D=3D NULL) + continue; + + list_for_each_entry(filter, &callstack_filters, list) { + if (strstr(sym->name, filter->name)) + return true; + } + } + return false; +} + +#ifndef HAVE_BPF_SKEL +int lock_contention_prepare(struct lock_contention *con __maybe_unused) +{ + return 0; +} + +int lock_contention_start(void) +{ + return 0; +} + +int lock_contention_stop(void) +{ + return 0; +} + +int lock_contention_finish(struct lock_contention *con __maybe_unused) +{ + return 0; +} + +int lock_contention_read(struct lock_contention *con __maybe_unused) +{ + return 0; +} +#endif /* !HAVE_BPF_SKEL */ diff --git a/tools/perf/util/lock-contention.h b/tools/perf/util/lock-conte= ntion.h index 1a7248ff3889..bfa5c7db0a5d 100644 --- a/tools/perf/util/lock-contention.h +++ b/tools/perf/util/lock-contention.h @@ -67,10 +67,11 @@ struct lock_stat { */ #define MAX_LOCK_DEPTH 48 =20 -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) =20 -bool match_callstack_filter(struct machine *machine, u64 *callstack); +extern struct hlist_head *lockhash_table; =20 /* * struct lock_seq_stat: @@ -148,7 +149,14 @@ struct lock_contention { bool save_callstack; }; =20 -#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 m= ax_stack_depth); =20 int lock_contention_prepare(struct lock_contention *con); int lock_contention_start(void); @@ -156,25 +164,4 @@ int lock_contention_stop(void); int lock_contention_read(struct lock_contention *con); int lock_contention_finish(struct lock_contention *con); =20 -#else /* !HAVE_BPF_SKEL */ - -static inline int lock_contention_prepare(struct lock_contention *con __ma= ybe_unused) -{ - return 0; -} - -static inline int lock_contention_start(void) { return 0; } -static inline int lock_contention_stop(void) { return 0; } -static inline int lock_contention_finish(struct lock_contention *con __may= be_unused) -{ - return 0; -} - -static inline int lock_contention_read(struct lock_contention *con __maybe= _unused) -{ - return 0; -} - -#endif /* HAVE_BPF_SKEL */ - #endif /* PERF_LOCK_CONTENTION_H */ diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 35d84a96dbec..91fd444615cd 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -18,7 +18,6 @@ #include "mmap.h" #include "util/kwork.h" #include "util/sample.h" -#include "util/lock-contention.h" #include #include "../builtin.h" =20 @@ -1311,22 +1310,6 @@ struct kwork_work *perf_kwork_add_work(struct perf_k= work *kwork __maybe_unused, return NULL; } =20 -bool match_callstack_filter(struct machine *machine __maybe_unused, u64 *c= allstack __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 *n= ame __maybe_unused, - int flags __maybe_unused) -{ - return NULL; -} - int cmd_inject(int argc __maybe_unused, const char *argv[] __maybe_unused) { return -1; --=20 2.47.0.163.g1226f6d8fa-goog