linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] perf bench sched pipe: Add -G/--cgroups option
@ 2023-10-13 23:24 Namhyung Kim
  2023-10-14  8:44 ` Ingo Molnar
  0 siblings, 1 reply; 3+ messages in thread
From: Namhyung Kim @ 2023-10-13 23:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Jiri Olsa
  Cc: Ian Rogers, Adrian Hunter, Peter Zijlstra, Ingo Molnar, LKML,
	linux-perf-users

The -G/--cgroups option is to put sender and receiver in different
cgroups in order to measure cgroup context switch overheads.

Users need to make sure the cgroups exist and accessible.

  # perf stat -e context-switches,cgroup-switches \
  > taskset -c 0 perf bench sched pipe -l 10000 > /dev/null

   Performance counter stats for 'taskset -c 0 perf bench sched pipe -l 10000':

              20,001      context-switches
                   2      cgroup-switches

         0.053449651 seconds time elapsed

         0.011286000 seconds user
         0.041869000 seconds sys

  # perf stat -e context-switches,cgroup-switches \
  > taskset -c 0 perf bench sched pipe -l 10000 -G AAA,BBB > /dev/null

   Performance counter stats for 'taskset -c 0 perf bench sched pipe -l 10000 -G AAA,BBB':

              20,001      context-switches
              20,001      cgroup-switches

         0.052768627 seconds time elapsed

         0.006284000 seconds user
         0.046266000 seconds sys

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/Documentation/perf-bench.txt | 19 +++++
 tools/perf/bench/sched-pipe.c           | 93 +++++++++++++++++++++++++
 2 files changed, 112 insertions(+)

diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
index ca5789625cd2..8331bd28b10e 100644
--- a/tools/perf/Documentation/perf-bench.txt
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -124,6 +124,14 @@ Options of *pipe*
 --loop=::
 Specify number of loops.
 
+-G::
+--cgroups=::
+Names of cgroups for sender and receiver, separated by a comma.
+This is useful to check cgroup context switching overhead.
+Note that perf doesn't create nor delete the cgroups, so users should
+make sure that the cgroups exist and are accessible before use.
+
+
 Example of *pipe*
 ^^^^^^^^^^^^^^^^^
 
@@ -141,6 +149,17 @@ Example of *pipe*
         Total time:0.016 sec
                 16.948000 usecs/op
                 59004 ops/sec
+
+% perf bench sched pipe -G AAA,BBB
+(executing 1000000 pipe operations between cgroups)
+# Running 'sched/pipe' benchmark:
+# Executed 1000000 pipe operations between two processes
+
+     Total time: 6.886 [sec]
+
+       6.886208 usecs/op
+         145217 ops/sec
+
 ---------------------
 
 SUITES FOR 'syscall'
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index a960e7a93aec..a98c2e239908 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -11,6 +11,7 @@
  */
 #include <subcmd/parse-options.h>
 #include "bench.h"
+#include "util/cgroup.h"
 
 #include <unistd.h>
 #include <stdio.h>
@@ -19,6 +20,7 @@
 #include <sys/wait.h>
 #include <string.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <assert.h>
 #include <sys/time.h>
 #include <sys/types.h>
@@ -40,9 +42,55 @@ static	int			loops = LOOPS_DEFAULT;
 /* Use processes by default: */
 static bool			threaded;
 
+static struct cgroup *cgrp_send = NULL;
+static struct cgroup *cgrp_recv = NULL;
+
+static int parse_two_cgroups(const struct option *opt __maybe_unused,
+			     const char *str, int unset __maybe_unused)
+{
+	char *p = strdup(str);
+	char *q;
+	int ret = -1;
+
+	if (p == NULL) {
+		fprintf(stderr, "memory allocation failure");
+		return -1;
+	}
+
+	q = strchr(p, ',');
+	if (q == NULL) {
+		fprintf(stderr, "it should have two cgroup names: %s", p);
+		goto out;
+	}
+	*q = '\0';
+
+	cgrp_send = cgroup__new(p, /*do_open=*/true);
+	if (cgrp_send == NULL) {
+		fprintf(stderr, "cannot open sender cgroup: %s", p);
+		goto out;
+	}
+
+	/* skip ',' */
+	q++;
+
+	cgrp_recv = cgroup__new(q, /*do_open=*/true);
+	if (cgrp_recv == NULL) {
+		fprintf(stderr, "cannot open receiver cgroup: %s", q);
+		goto out;
+	}
+	ret = 0;
+
+out:
+	free(p);
+	return ret;
+}
+
 static const struct option options[] = {
 	OPT_INTEGER('l', "loop",	&loops,		"Specify number of loops"),
 	OPT_BOOLEAN('T', "threaded",	&threaded,	"Specify threads/process based task setup"),
+	OPT_CALLBACK('G', "cgroups", NULL, "SEND,RECV",
+		     "Put sender and receivers in given cgroups",
+		     parse_two_cgroups),
 	OPT_END()
 };
 
@@ -51,12 +99,54 @@ static const char * const bench_sched_pipe_usage[] = {
 	NULL
 };
 
+static void enter_cgroup(struct cgroup *cgrp)
+{
+	char buf[32];
+	int fd, len;
+	pid_t pid;
+
+	if (cgrp == NULL)
+		return;
+
+	if (threaded)
+		pid = syscall(__NR_gettid);
+	else
+		pid = getpid();
+
+	snprintf(buf, sizeof(buf), "%d\n", pid);
+	len = strlen(buf);
+
+	/* try cgroup v2 interface first */
+	if (threaded)
+		fd = openat(cgrp->fd, "cgroup.threads", O_WRONLY);
+	else
+		fd = openat(cgrp->fd, "cgroup.procs", O_WRONLY);
+
+	/* try cgroup v1 if failed */
+	if (fd < 0)
+		fd = openat(cgrp->fd, "tasks", O_WRONLY);
+
+	if (fd < 0) {
+		printf("failed to open cgroup file in %s\n", cgrp->name);
+		return;
+	}
+
+	if (write(fd, buf, len) != len)
+		printf("cannot enter to cgroup: %s\n", cgrp->name);
+	close(fd);
+}
+
 static void *worker_thread(void *__tdata)
 {
 	struct thread_data *td = __tdata;
 	int m = 0, i;
 	int ret;
 
+	if (td->nr)
+		enter_cgroup(cgrp_send);
+	else
+		enter_cgroup(cgrp_recv);
+
 	for (i = 0; i < loops; i++) {
 		if (!td->nr) {
 			ret = read(td->pipe_read, &m, sizeof(int));
@@ -147,6 +237,9 @@ int bench_sched_pipe(int argc, const char **argv)
 	gettimeofday(&stop, NULL);
 	timersub(&stop, &start, &diff);
 
+	cgroup__put(cgrp_send);
+	cgroup__put(cgrp_recv);
+
 	switch (bench_format) {
 	case BENCH_FORMAT_DEFAULT:
 		printf("# Executed %d pipe operations between two %s\n\n",
-- 
2.42.0.655.g421f12c284-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] perf bench sched pipe: Add -G/--cgroups option
  2023-10-13 23:24 [PATCH v2] perf bench sched pipe: Add -G/--cgroups option Namhyung Kim
@ 2023-10-14  8:44 ` Ingo Molnar
  2023-10-15 18:53   ` Namhyung Kim
  0 siblings, 1 reply; 3+ messages in thread
From: Ingo Molnar @ 2023-10-14  8:44 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers, Adrian Hunter,
	Peter Zijlstra, LKML, linux-perf-users


* Namhyung Kim <namhyung@kernel.org> wrote:

> +	cgrp_send = cgroup__new(p, /*do_open=*/true);
> +	if (cgrp_send == NULL) {
> +		fprintf(stderr, "cannot open sender cgroup: %s", p);
> +		goto out;
> +	}

Maybe in this case print out a small suggestion of how to create this 
particular cgroup?

Most distro users and even kernel developers don't ever have to create
new cgroups.

Maybe even allow the creation of new cgroups for this testing, if they 
don't already exist? As long as we don't delete any cgroups I don't think 
much harm can be done - and the increase in usability is substantial.

> +static void enter_cgroup(struct cgroup *cgrp)
> +{
> +	char buf[32];
> +	int fd, len;
> +	pid_t pid;
> +
> +	if (cgrp == NULL)
> +		return;
> +
> +	if (threaded)
> +		pid = syscall(__NR_gettid);
> +	else
> +		pid = getpid();
> +
> +	snprintf(buf, sizeof(buf), "%d\n", pid);
> +	len = strlen(buf);
> +
> +	/* try cgroup v2 interface first */
> +	if (threaded)
> +		fd = openat(cgrp->fd, "cgroup.threads", O_WRONLY);
> +	else
> +		fd = openat(cgrp->fd, "cgroup.procs", O_WRONLY);
> +
> +	/* try cgroup v1 if failed */
> +	if (fd < 0)
> +		fd = openat(cgrp->fd, "tasks", O_WRONLY);
> +
> +	if (fd < 0) {
> +		printf("failed to open cgroup file in %s\n", cgrp->name);
> +		return;
> +	}
> +
> +	if (write(fd, buf, len) != len)
> +		printf("cannot enter to cgroup: %s\n", cgrp->name);

The failures here should probably result in termination of the run with an 
error code, not just messages which are easy to skip in automated tests?

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] perf bench sched pipe: Add -G/--cgroups option
  2023-10-14  8:44 ` Ingo Molnar
@ 2023-10-15 18:53   ` Namhyung Kim
  0 siblings, 0 replies; 3+ messages in thread
From: Namhyung Kim @ 2023-10-15 18:53 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers, Adrian Hunter,
	Peter Zijlstra, LKML, linux-perf-users

On Sat, Oct 14, 2023 at 1:44 AM Ingo Molnar <mingo@kernel.org> wrote:
>
>
> * Namhyung Kim <namhyung@kernel.org> wrote:
>
> > +     cgrp_send = cgroup__new(p, /*do_open=*/true);
> > +     if (cgrp_send == NULL) {
> > +             fprintf(stderr, "cannot open sender cgroup: %s", p);
> > +             goto out;
> > +     }
>
> Maybe in this case print out a small suggestion of how to create this
> particular cgroup?
>
> Most distro users and even kernel developers don't ever have to create
> new cgroups.
>
> Maybe even allow the creation of new cgroups for this testing, if they
> don't already exist? As long as we don't delete any cgroups I don't think
> much harm can be done - and the increase in usability is substantial.

I'm not sure if it's ok create a new cgroup and leave it after the use.
Anyway, none of the existing subcommands create new cgroups
IIUC and I think it'd be ok to print a message on how to create one.

>
> > +static void enter_cgroup(struct cgroup *cgrp)
> > +{
> > +     char buf[32];
> > +     int fd, len;
> > +     pid_t pid;
> > +
> > +     if (cgrp == NULL)
> > +             return;
> > +
> > +     if (threaded)
> > +             pid = syscall(__NR_gettid);
> > +     else
> > +             pid = getpid();
> > +
> > +     snprintf(buf, sizeof(buf), "%d\n", pid);
> > +     len = strlen(buf);
> > +
> > +     /* try cgroup v2 interface first */
> > +     if (threaded)
> > +             fd = openat(cgrp->fd, "cgroup.threads", O_WRONLY);
> > +     else
> > +             fd = openat(cgrp->fd, "cgroup.procs", O_WRONLY);
> > +
> > +     /* try cgroup v1 if failed */
> > +     if (fd < 0)
> > +             fd = openat(cgrp->fd, "tasks", O_WRONLY);
> > +
> > +     if (fd < 0) {
> > +             printf("failed to open cgroup file in %s\n", cgrp->name);
> > +             return;
> > +     }
> > +
> > +     if (write(fd, buf, len) != len)
> > +             printf("cannot enter to cgroup: %s\n", cgrp->name);
>
> The failures here should probably result in termination of the run with an
> error code, not just messages which are easy to skip in automated tests?

Right, I'll make the change.

Thanks,
Namhyung

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-10-15 18:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-13 23:24 [PATCH v2] perf bench sched pipe: Add -G/--cgroups option Namhyung Kim
2023-10-14  8:44 ` Ingo Molnar
2023-10-15 18:53   ` Namhyung Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).