From nobody Sat Nov 23 18:21:42 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 91324153BC1 for ; Tue, 19 Nov 2024 01:18:08 +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=1731979090; cv=none; b=qU6buvJ2SCvEigvR7dcw3mjnZtdeFTZ9V4eEiDuL+vvVFH9TgF36YZSieukviNCPyteD3W1Qth7k25oYLgPASBCmSC+J0XOGYqPkXrw+Wf522zssWWKex5BiaKldalWLbsR1+Urt5O5w9FAOjqxanWuiu7Xdc0DesdhEbvPkikU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731979090; c=relaxed/simple; bh=ekmC66NOVNSgpMr3xsJfryonDUgmY+ot1N0WZtHvs3E=; h=Date:In-Reply-To:Message-Id:Mime-Version:References:Subject:From: To:Cc:Content-Type; b=qwBglir/F3ecevWeH+TXUQYcZgj1I0QinDu3ItphEB7qTlPltUDl2Ujr1+GQQBQ0pXos2i2YbOIIDmdY8SJjCSRV3Oo+Ff7v+4hbkYHPXyV5wGLrvkG3q2yKfSbZIM4ZB47RWYvyhrSr1991zKUQlHaTXMOWlHdFebpBQ3lVqFM= 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=09qNdSFm; 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="09qNdSFm" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-6ea86f1df79so9628167b3.1 for ; Mon, 18 Nov 2024 17:18:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1731979088; x=1732583888; darn=vger.kernel.org; h=cc:to:from:subject:references:mime-version:message-id:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=nLZCOhlOMtG0/qeJgzd25nzSdzp9WmUWu8UlS8oQxf0=; b=09qNdSFm6vMlxFM+hl9ixxMpu9ECOnMWdATrQJYxec61GxHBwzQM0gTwKNwXWVwxeq glywkWWhz14x9NDLN6t+1Ab6xS7c2dG/cMWabIEFb32pteDVLqT7RmrndUjVIZTAhN7G dZwsqfoOUPLsUYWfSUNPJ9wHAXTf42M8NIjPwAgsZjPA7aFZHqMbbRwebjq2+GX2kXkB RKn/Ol0wpAMjLV931Dwr/OBj+1/SMmntE7pGQO1kDJTw1i9LmK5oJUlk7iJYYyo5R30z xIwjIk3vPy2+DMJNvmLnDWqcosqlq6sUnYRHyAHeLNiyHozOSGLnAGgC2EAqte6oNHZM phig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1731979088; x=1732583888; h=cc: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=nLZCOhlOMtG0/qeJgzd25nzSdzp9WmUWu8UlS8oQxf0=; b=SD7pwd+qFvsZRTAXIjF//Y/24luyr44V8lWcsOA+UphswD8BxBV2+GAcmK7fBbJwDy YpCAJv0KfDTtY7UKzv9jX5oGTYOYdeKEcObo4VQtLt+NXrjdMf1BqDWf846bx/HdxJ3r cXaRHqj7Lu0Y3QJ/Pv/8NyEEKPylPbTDCbzj9dnFaKQ+pansx7on1HGjntjF6O98BCcp 51A9tlX10Dx7YeVOFf7bpkIQGSpobtF9ZtL06+XlraihvZQGX0cgsKficKfmjSD/r97J +3RY3exgklHRLuSBYR3Eva+jwVHNjNCmNscEANV/FY4qPbMT2M0sr5wtCZvx9zvTr7R9 7hmg== X-Forwarded-Encrypted: i=1; AJvYcCWL+Qkd4RX4nugYXJmRXFxf2Qnjlwlob2HewWAqn2nTPdnSIK0zWEm8RSlz3wqrs8+eYWqar5i5/lgXC9Q=@vger.kernel.org X-Gm-Message-State: AOJu0Yy1LFVb5eMHLuCYdJSUN3wl89PT3xpw/pV4uyWHdeKCnrUZpebW h2wVevRl5CdcVu9Pawi/GgWxiGPgMJ+Gf0eaRpCjlncXFjYlH8cIfryuuxkoMxsZVFuol4MgXUK oI4DR/A== X-Google-Smtp-Source: AGHT+IHMI4Smzd88oNWzuljvIvishAISCpSxrbVFZGL6LgwOMJQh0gQhJwsZXkMDIxRpQxZuGUUxZYkbAcOi X-Received: from irogers.svl.corp.google.com ([2620:15c:2c5:11:22a4:ded5:5c37:fcc7]) (user=irogers job=sendgmr) by 2002:a81:b289:0:b0:6e2:6f2:efc with SMTP id 00721157ae682-6ee55c5cb1cmr1313467b3.5.1731979087091; Mon, 18 Nov 2024 17:18:07 -0800 (PST) Date: Mon, 18 Nov 2024 17:16:37 -0800 In-Reply-To: <20241119011644.971342-1-irogers@google.com> Message-Id: <20241119011644.971342-16-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241119011644.971342-1-irogers@google.com> X-Mailer: git-send-email 2.47.0.338.g60cca15819-goog Subject: [PATCH v7 15/22] 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 , Josh Poimboeuf , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: Arnaldo Carvalho de Melo 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 Acked-by: Arnaldo Carvalho de Melo Acked-by: Namhyung Kim --- 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 | 143 ++++++++++++++++++++++++++ tools/perf/util/lock-contention.h | 18 +++- tools/perf/util/python.c | 17 --- 6 files changed, 160 insertions(+), 158 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 21b497df440b..f38eb8262370 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -122,6 +122,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-y +=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..92e7b7b572a2 --- /dev/null +++ b/tools/perf/util/lock-contention.c @@ -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 +#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; +} diff --git a/tools/perf/util/lock-contention.h b/tools/perf/util/lock-conte= ntion.h index 1a7248ff3889..bd71fb73825a 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,8 +149,17 @@ 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); =20 +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); + + +#ifdef HAVE_BPF_SKEL int lock_contention_prepare(struct lock_contention *con); int lock_contention_start(void); int lock_contention_stop(void); diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index fa25e7ed8a7f..6851f9b07e04 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.338.g60cca15819-goog