From nobody Sun Nov 24 01:16:04 2024 Received: from mail-yw1-f202.google.com (mail-yw1-f202.google.com [209.85.128.202]) (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 D7FC3189BA6 for ; Sat, 9 Nov 2024 06:18:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731133138; cv=none; b=pR6WmtNmmUzNtDhhC1GY7+AxfLxD1MxhUvoji/bVhtYPsMSHZQl3a06Rb+OLmk1UEtNE6rJQtsCihKgM11PkidCqGJjAXKb99fksZfA8NGw4uf/Of+/g1BU2o1KM4hk3//2MfGhybEH4rc4+QyTumVWbefvEga8SABqHq9OR5lA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731133138; c=relaxed/simple; bh=Wf2VDsFtfq7d0fqSAIg4TBCOQAJUYor7+AF0sqv4SgA=; h=Date:In-Reply-To:Message-Id:Mime-Version:References:Subject:From: To:Cc:Content-Type; b=mrlFrjw37eJ/pf5X+PCO32T4t82d025PnajYi28fLzgd8ueZVoocatQLCdtMvwqtH7ItHivLUm8XL9LwxwfjhdoASWq6R37g5ETc43AsZosEqan9NYaoiBjPqDojDhqNQgrmNa7NZmcL/RKbPxnc6pq5Gk0mIo95XpRWs0XqSTE= 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=CpOcW6NB; arc=none smtp.client-ip=209.85.128.202 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="CpOcW6NB" Received: by mail-yw1-f202.google.com with SMTP id 00721157ae682-6ea86f1df79so54995287b3.1 for ; Fri, 08 Nov 2024 22:18:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1731133136; x=1731737936; 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=uPQ3aTez9N2PJdDPdgTJjGEL+gTCQmT4cdEl7SyznXA=; b=CpOcW6NBOfqFa8d9ISh+NJL1Gk5WVCNOzA+4J/02KEfd3+AiS+2uT8DBaUqMeeFt/z 6UfWoMWFFf08gxQkQtQLjeKMJL0BPnYn8GEszOl139UEybgy9alOQGeTcERz9WZseeH/ RTwazblIuhyCMEIfu8IoodcUuCuHWJqCBEsxkQ8oncyvpv4Rh3hX7N5D97hKGJDjIvhH jdFc5vEd9Ty9QroYclQHj2YmKj9dxkejmf1LAB4sixwDAQhFhpOXbCfdU2oWnEwwXhtx 9Uop71uQjIpoao54ky7WANQTKBFGZjQ5L9bJaiWVnXia4rK+GawOsJbgPQX/QCtUmpOZ tHJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1731133136; x=1731737936; 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=uPQ3aTez9N2PJdDPdgTJjGEL+gTCQmT4cdEl7SyznXA=; b=gZQADxsGkUJHYDsNPeeU5FAFqgOYO5HnyeVZfZthmaCFJ9Cziotu0WdOgeFRISI5V8 CMXmr8ETUs8/KCdJZApPIHArMttdHgBVRkJ0/A/1NrdPFXf65to8lFrlhvf6g6Mad5oi Dae/qotp+tXqR8lkEYTNpgNd/wsXOyBbiAnHxqZAKD+cvx96fd1Qx58AlingI2JQUvpu 52RGm4DLjusKxX12fShJTRMeh2xf/6E/t6bH9YHCTxJwhF+4T2dLlLfHCrqAvQL3My+z LQAo441kZa44O4Cvuh+aqbP1UMuTZ2JgQthI1UN9QPSzDTlhbfx+ulXdcZgjM0tqkEuq 2q8g== X-Forwarded-Encrypted: i=1; AJvYcCX3k3R8dRBG+izsAEYkB09kdJwijBTKhm3fWWZLNBKz+g7np35gf0cWqKNrqyehb7PtKzMQnEUJjx9flDY=@vger.kernel.org X-Gm-Message-State: AOJu0YwmxHuEw2FrjmcwWmKGl4/db6KhSomkxeu+rqIi4SK9tQBzQai1 4PpxuDDGjkiVHcT0Ikq82RSzVjAyTzh5azoiCJNADIUH+u7yM4mA/Uq2OqPYDukZ9vQEoAAdr0W L6f782A== X-Google-Smtp-Source: AGHT+IGttmknS5N9QjAmd3P21M+NEtkHBx7mH5NFJkoaUqiMUvoD00tjRMCQiICoczfjyJNEkNb3xvvDGuAo X-Received: from irogers.svl.corp.google.com ([2620:15c:2c5:11:acc2:d48f:a998:5915]) (user=irogers job=sendgmr) by 2002:a05:690c:200f:b0:6ea:34c3:742b with SMTP id 00721157ae682-6eaddfad76amr531597b3.6.1731133135754; Fri, 08 Nov 2024 22:18:55 -0800 (PST) Date: Fri, 8 Nov 2024 22:18:02 -0800 In-Reply-To: <20241109061809.811922-1-irogers@google.com> Message-Id: <20241109061809.811922-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: <20241109061809.811922-1-irogers@google.com> X-Mailer: git-send-email 2.47.0.277.g8800431eea-goog Subject: [PATCH v6 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 --- 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 340544a6f5ec..3c6cd8d81d88 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-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..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.277.g8800431eea-goog