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:
Namhyung Kim 2023-09-06 10:49:02 -07:00 committed by Arnaldo Carvalho de Melo
parent 4d1792d0a2
commit 4fd06bd2dc
7 changed files with 95 additions and 2 deletions

View file

@ -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
--------

View file

@ -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)
};

View file

@ -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;

View file

@ -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;
}

View file

@ -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));

View file

@ -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);

View file

@ -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 {