mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
perf lock contention: Add -G/--cgroup-filter option
The -G/--cgroup-filter is to limit lock contention collection on the tasks in the specific cgroups only. $ sudo ./perf lock con -abt -G /user.slice/.../vte-spawn-52221fb8-b33f-4a52-b5c3-e35d1e6fc0e0.scope \ ./perf bench sched messaging # Running 'sched/messaging' benchmark: # 20 sender and receiver processes per group # 10 groups == 400 processes run Total time: 0.174 [sec] contended total wait max wait avg wait pid comm 4 114.45 us 60.06 us 28.61 us 214847 sched-messaging 2 111.40 us 60.84 us 55.70 us 214848 sched-messaging 2 106.09 us 59.42 us 53.04 us 214837 sched-messaging 1 81.70 us 81.70 us 81.70 us 214709 sched-messaging 68 78.44 us 6.83 us 1.15 us 214633 sched-messaging 69 73.71 us 2.69 us 1.07 us 214632 sched-messaging 4 72.62 us 60.83 us 18.15 us 214850 sched-messaging 2 71.75 us 67.60 us 35.88 us 214840 sched-messaging 2 69.29 us 67.53 us 34.65 us 214804 sched-messaging 2 69.00 us 68.23 us 34.50 us 214826 sched-messaging ... Export cgroup__new() function as it's needed from outside. Reviewed-by: Ian Rogers <irogers@google.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Hao Luo <haoluo@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Song Liu <song@kernel.org> Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20230906174903.346486-5-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
4d1792d0a2
commit
4fd06bd2dc
@ -211,6 +211,10 @@ CONTENTION OPTIONS
|
||||
--lock-cgroup::
|
||||
Show lock contention stat by cgroup. Requires --use-bpf.
|
||||
|
||||
-G::
|
||||
--cgroup-filter=<value>::
|
||||
Show lock contention only in the given cgroups (comma separated list).
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "util/thread.h"
|
||||
#include "util/header.h"
|
||||
#include "util/target.h"
|
||||
#include "util/cgroup.h"
|
||||
#include "util/callchain.h"
|
||||
#include "util/lock-contention.h"
|
||||
#include "util/bpf_skel/lock_data.h"
|
||||
@ -1631,6 +1632,9 @@ static void lock_filter_finish(void)
|
||||
|
||||
zfree(&filters.syms);
|
||||
filters.nr_syms = 0;
|
||||
|
||||
zfree(&filters.cgrps);
|
||||
filters.nr_cgrps = 0;
|
||||
}
|
||||
|
||||
static void sort_contention_result(void)
|
||||
@ -2488,6 +2492,56 @@ static int parse_output(const struct option *opt __maybe_unused, const char *str
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool add_lock_cgroup(char *name)
|
||||
{
|
||||
u64 *tmp;
|
||||
struct cgroup *cgrp;
|
||||
|
||||
cgrp = cgroup__new(name, /*do_open=*/false);
|
||||
if (cgrp == NULL) {
|
||||
pr_err("Failed to create cgroup: %s\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read_cgroup_id(cgrp) < 0) {
|
||||
pr_err("Failed to read cgroup id for %s\n", name);
|
||||
cgroup__put(cgrp);
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = realloc(filters.cgrps, (filters.nr_cgrps + 1) * sizeof(*filters.cgrps));
|
||||
if (tmp == NULL) {
|
||||
pr_err("Memory allocation failure\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp[filters.nr_cgrps++] = cgrp->id;
|
||||
filters.cgrps = tmp;
|
||||
cgroup__put(cgrp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int parse_cgroup_filter(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)) {
|
||||
if (!add_lock_cgroup(tok)) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_lock(int argc, const char **argv)
|
||||
{
|
||||
const struct option lock_options[] = {
|
||||
@ -2562,6 +2616,8 @@ int cmd_lock(int argc, const char **argv)
|
||||
OPT_STRING_NOEMPTY('x', "field-separator", &symbol_conf.field_sep, "separator",
|
||||
"print result in CSV format with custom separator"),
|
||||
OPT_BOOLEAN(0, "lock-cgroup", &show_lock_cgroups, "show lock stats by cgroup"),
|
||||
OPT_CALLBACK('G', "cgroup-filter", NULL, "CGROUPS",
|
||||
"Filter specific cgroups", parse_cgroup_filter),
|
||||
OPT_PARENT(lock_options)
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@ static struct lock_contention_bpf *skel;
|
||||
int lock_contention_prepare(struct lock_contention *con)
|
||||
{
|
||||
int i, fd;
|
||||
int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1;
|
||||
int ncpus = 1, ntasks = 1, ntypes = 1, naddrs = 1, ncgrps = 1;
|
||||
struct evlist *evlist = con->evlist;
|
||||
struct target *target = con->target;
|
||||
|
||||
@ -51,6 +51,8 @@ int lock_contention_prepare(struct lock_contention *con)
|
||||
ntasks = perf_thread_map__nr(evlist->core.threads);
|
||||
if (con->filters->nr_types)
|
||||
ntypes = con->filters->nr_types;
|
||||
if (con->filters->nr_cgrps)
|
||||
ncgrps = con->filters->nr_cgrps;
|
||||
|
||||
/* resolve lock name filters to addr */
|
||||
if (con->filters->nr_syms) {
|
||||
@ -85,6 +87,7 @@ int lock_contention_prepare(struct lock_contention *con)
|
||||
bpf_map__set_max_entries(skel->maps.task_filter, ntasks);
|
||||
bpf_map__set_max_entries(skel->maps.type_filter, ntypes);
|
||||
bpf_map__set_max_entries(skel->maps.addr_filter, naddrs);
|
||||
bpf_map__set_max_entries(skel->maps.cgroup_filter, ncgrps);
|
||||
|
||||
if (lock_contention_bpf__load(skel) < 0) {
|
||||
pr_err("Failed to load lock-contention BPF skeleton\n");
|
||||
@ -146,6 +149,16 @@ int lock_contention_prepare(struct lock_contention *con)
|
||||
bpf_map_update_elem(fd, &con->filters->addrs[i], &val, BPF_ANY);
|
||||
}
|
||||
|
||||
if (con->filters->nr_cgrps) {
|
||||
u8 val = 1;
|
||||
|
||||
skel->bss->has_cgroup = 1;
|
||||
fd = bpf_map__fd(skel->maps.cgroup_filter);
|
||||
|
||||
for (i = 0; i < con->filters->nr_cgrps; i++)
|
||||
bpf_map_update_elem(fd, &con->filters->cgrps[i], &val, BPF_ANY);
|
||||
}
|
||||
|
||||
/* these don't work well if in the rodata section */
|
||||
skel->bss->stack_skip = con->stack_skip;
|
||||
skel->bss->aggr_mode = con->aggr_mode;
|
||||
|
@ -92,6 +92,13 @@ struct {
|
||||
__uint(max_entries, 1);
|
||||
} addr_filter SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(key_size, sizeof(__u64));
|
||||
__uint(value_size, sizeof(__u8));
|
||||
__uint(max_entries, 1);
|
||||
} cgroup_filter SEC(".maps");
|
||||
|
||||
struct rw_semaphore___old {
|
||||
struct task_struct *owner;
|
||||
} __attribute__((preserve_access_index));
|
||||
@ -114,6 +121,7 @@ int has_cpu;
|
||||
int has_task;
|
||||
int has_type;
|
||||
int has_addr;
|
||||
int has_cgroup;
|
||||
int needs_callstack;
|
||||
int stack_skip;
|
||||
int lock_owner;
|
||||
@ -194,6 +202,15 @@ static inline int can_record(u64 *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (has_cgroup) {
|
||||
__u8 *ok;
|
||||
__u64 cgrp = get_current_cgroup_id();
|
||||
|
||||
ok = bpf_map_lookup_elem(&cgroup_filter, &cgrp);
|
||||
if (!ok)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct cgroup *cgroup__new(const char *name, bool do_open)
|
||||
struct cgroup *cgroup__new(const char *name, bool do_open)
|
||||
{
|
||||
struct cgroup *cgroup = zalloc(sizeof(*cgroup));
|
||||
|
||||
|
@ -26,6 +26,7 @@ void cgroup__put(struct cgroup *cgroup);
|
||||
struct evlist;
|
||||
struct rblist;
|
||||
|
||||
struct cgroup *cgroup__new(const char *name, bool do_open);
|
||||
struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name);
|
||||
int evlist__expand_cgroup(struct evlist *evlist, const char *cgroups,
|
||||
struct rblist *metric_events, bool open_cgroup);
|
||||
|
@ -9,9 +9,11 @@ struct lock_filter {
|
||||
int nr_types;
|
||||
int nr_addrs;
|
||||
int nr_syms;
|
||||
int nr_cgrps;
|
||||
unsigned int *types;
|
||||
unsigned long *addrs;
|
||||
char **syms;
|
||||
u64 *cgrps;
|
||||
};
|
||||
|
||||
struct lock_stat {
|
||||
|
Loading…
Reference in New Issue
Block a user