linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] perf tools: Backward ring buffer support
@ 2016-05-09  1:47 Wang Nan
  2016-05-09  1:47 ` [PATCH v3 1/2] perf tools: Support reading from backward ring buffer Wang Nan
  2016-05-09  1:47 ` [PATCH v3 2/2] perf tests: Add test to check " Wang Nan
  0 siblings, 2 replies; 6+ messages in thread
From: Wang Nan @ 2016-05-09  1:47 UTC (permalink / raw)
  To: acme; +Cc: linux-kernel, lizefan, pi3orama, Wang Nan

Commit 9ecda41acb97 ("perf/core: Add ::write_backward attribute to
perf event") introduces backward ring buffer. This 2 patches add basic
support for reading from it, and add a new test case for it.

v2 -> v3:
  Improve commit message, add more comments (patch 1/2). patch 1-2/4 in
  v2 have been collected so remove them.

v1 -> v2:
  Patch 1/5 in v1 has been collected by perf/core, so remove it;
  Change function names in patch 2/5 in v1 (1/4 in v2):
      __perf_evlist__mmap_read -> perf_mmap__read

Wang Nan (2):
  perf tools: Support reading from backward ring buffer
  perf tests: Add test to check backward ring buffer

 tools/perf/tests/Build                  |   1 +
 tools/perf/tests/backward-ring-buffer.c | 151 ++++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c         |   4 +
 tools/perf/tests/tests.h                |   1 +
 tools/perf/util/evlist.c                |  50 +++++++++++
 tools/perf/util/evlist.h                |   4 +
 6 files changed, 211 insertions(+)
 create mode 100644 tools/perf/tests/backward-ring-buffer.c

-- 
1.8.3.4

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

* [PATCH v3 1/2] perf tools: Support reading from backward ring buffer
  2016-05-09  1:47 [PATCH v3 0/2] perf tools: Backward ring buffer support Wang Nan
@ 2016-05-09  1:47 ` Wang Nan
  2016-05-10 20:31   ` [tip:perf/core] " tip-bot for Wang Nan
  2016-05-09  1:47 ` [PATCH v3 2/2] perf tests: Add test to check " Wang Nan
  1 sibling, 1 reply; 6+ messages in thread
From: Wang Nan @ 2016-05-09  1:47 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, lizefan, pi3orama, Wang Nan,
	Arnaldo Carvalho de Melo, Peter Zijlstra

perf_evlist__mmap_read_backward() is introduced for reading backward
ring buffer. Since direction for reading such ring buffer is different
from the direction kernel writing to it, and since user need to fetch
most recent record from it, a perf_evlist__mmap_read_catchup() is
introduced to move the reading pointer to the end of the buffer.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/util/evlist.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  4 ++++
 2 files changed, 54 insertions(+)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 17cd014..c4bfe11 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -766,6 +766,56 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 	return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev);
 }
 
+union perf_event *
+perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx)
+{
+	struct perf_mmap *md = &evlist->mmap[idx];
+	u64 head, end;
+	u64 start = md->prev;
+
+	/*
+	 * Check if event was unmapped due to a POLLHUP/POLLERR.
+	 */
+	if (!atomic_read(&md->refcnt))
+		return NULL;
+
+	head = perf_mmap__read_head(md);
+	if (!head)
+		return NULL;
+
+	/*
+	 * 'head' pointer starts from 0. Kernel minus sizeof(record) form
+	 * it each time when kernel writes to it, so in fact 'head' is
+	 * negative. 'end' pointer is made manually by adding the size of
+	 * the ring buffer to 'head' pointer, means the validate data can
+	 * read is the whole ring buffer. If 'end' is positive, the ring
+	 * buffer has not fully filled, so we must adjust 'end' to 0.
+	 *
+	 * However, since both 'head' and 'end' is unsigned, we can't
+	 * simply compare 'end' against 0. Here we compare '-head' and
+	 * the size of the ring buffer, where -head is the number of bytes
+	 * kernel write to the ring buffer.
+	 */
+	if (-head < (u64)(md->mask + 1))
+		end = 0;
+	else
+		end = head + md->mask + 1;
+
+	return perf_mmap__read(md, false, start, end, &md->prev);
+}
+
+void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx)
+{
+	struct perf_mmap *md = &evlist->mmap[idx];
+	u64 head;
+
+	if (!atomic_read(&md->refcnt))
+		return;
+
+	head = perf_mmap__read_head(md);
+	md->prev = head;
+}
+
 static bool perf_mmap__empty(struct perf_mmap *md)
 {
 	return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 208897a..85d1b59 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -129,6 +129,10 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
 
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
 
+union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist,
+						  int idx);
+void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
+
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
 
 int perf_evlist__open(struct perf_evlist *evlist);
-- 
1.8.3.4

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

* [PATCH v3 2/2] perf tests: Add test to check backward ring buffer
  2016-05-09  1:47 [PATCH v3 0/2] perf tools: Backward ring buffer support Wang Nan
  2016-05-09  1:47 ` [PATCH v3 1/2] perf tools: Support reading from backward ring buffer Wang Nan
@ 2016-05-09  1:47 ` Wang Nan
  2016-05-09 21:12   ` Arnaldo Carvalho de Melo
  2016-05-10 20:32   ` [tip:perf/core] " tip-bot for Wang Nan
  1 sibling, 2 replies; 6+ messages in thread
From: Wang Nan @ 2016-05-09  1:47 UTC (permalink / raw)
  To: acme
  Cc: linux-kernel, lizefan, pi3orama, Wang Nan,
	Arnaldo Carvalho de Melo, Peter Zijlstra

This test checks reading from backward ring buffer.

Test result:

 # ~/perf test 'ring buffer'
 45: Test backward reading from ring buffer                   : Ok

Test case is a while loop which calls prctl(PR_SET_NAME) multiple
times. Each prctl should issue 2 events: one PERF_RECORD_SAMPLE,
one PERF_RECORD_COMM.

The first round creates a relative large ring buffer (256 pages). It
can afford all events. Read from it and check the count of each type of
events.

The second round creates a small ring buffer (1 page) and makes it
overwritable. Check the correctness of the buffer.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/tests/Build                  |   1 +
 tools/perf/tests/backward-ring-buffer.c | 151 ++++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c         |   4 +
 tools/perf/tests/tests.h                |   1 +
 4 files changed, 157 insertions(+)
 create mode 100644 tools/perf/tests/backward-ring-buffer.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 449fe97..66a2898 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -38,6 +38,7 @@ perf-y += cpumap.o
 perf-y += stat.o
 perf-y += event_update.o
 perf-y += event-times.o
+perf-y += backward-ring-buffer.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
 	$(call rule_mkdir)
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
new file mode 100644
index 0000000..d9ba991
--- /dev/null
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -0,0 +1,151 @@
+/*
+ * Test backward bit in event attribute, read ring buffer from end to
+ * beginning
+ */
+
+#include <perf.h>
+#include <evlist.h>
+#include <sys/prctl.h>
+#include "tests.h"
+#include "debug.h"
+
+#define NR_ITERS 111
+
+static void testcase(void)
+{
+	int i;
+
+	for (i = 0; i < NR_ITERS; i++) {
+		char proc_name[10];
+
+		snprintf(proc_name, sizeof(proc_name), "p:%d\n", i);
+		prctl(PR_SET_NAME, proc_name);
+	}
+}
+
+static int count_samples(struct perf_evlist *evlist, int *sample_count,
+			 int *comm_count)
+{
+	int i;
+
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		union perf_event *event;
+
+		perf_evlist__mmap_read_catchup(evlist, i);
+		while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) {
+			const u32 type = event->header.type;
+
+			switch (type) {
+			case PERF_RECORD_SAMPLE:
+				(*sample_count)++;
+				break;
+			case PERF_RECORD_COMM:
+				(*comm_count)++;
+				break;
+			default:
+				pr_err("Unexpected record of type %d\n", type);
+				return TEST_FAIL;
+			}
+		}
+	}
+	return TEST_OK;
+}
+
+static int do_test(struct perf_evlist *evlist, int mmap_pages,
+		   int *sample_count, int *comm_count)
+{
+	int err;
+	char sbuf[STRERR_BUFSIZE];
+
+	err = perf_evlist__mmap(evlist, mmap_pages, true);
+	if (err < 0) {
+		pr_debug("perf_evlist__mmap: %s\n",
+			 strerror_r(errno, sbuf, sizeof(sbuf)));
+		return TEST_FAIL;
+	}
+
+	perf_evlist__enable(evlist);
+	testcase();
+	perf_evlist__disable(evlist);
+
+	err = count_samples(evlist, sample_count, comm_count);
+	perf_evlist__munmap(evlist);
+	return err;
+}
+
+
+int test__backward_ring_buffer(int subtest __maybe_unused)
+{
+	int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0;
+	char pid[16], sbuf[STRERR_BUFSIZE];
+	struct perf_evlist *evlist;
+	struct perf_evsel *evsel __maybe_unused;
+	struct parse_events_error parse_error;
+	struct record_opts opts = {
+		.target = {
+			.uid = UINT_MAX,
+			.uses_mmap = true,
+		},
+		.freq	      = 0,
+		.mmap_pages   = 256,
+		.default_interval = 1,
+	};
+
+	snprintf(pid, sizeof(pid), "%d", getpid());
+	pid[sizeof(pid) - 1] = '\0';
+	opts.target.tid = opts.target.pid = pid;
+
+	evlist = perf_evlist__new();
+	if (!evlist) {
+		pr_debug("No ehough memory to create evlist\n");
+		return TEST_FAIL;
+	}
+
+	err = perf_evlist__create_maps(evlist, &opts.target);
+	if (err < 0) {
+		pr_debug("Not enough memory to create thread/cpu maps\n");
+		goto out_delete_evlist;
+	}
+
+	bzero(&parse_error, sizeof(parse_error));
+	err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error);
+	if (err) {
+		pr_debug("Failed to parse tracepoint event, try use root\n");
+		ret = TEST_SKIP;
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__config(evlist, &opts, NULL);
+
+	/* Set backward bit, ring buffer should be writing from end */
+	evlist__for_each(evlist, evsel)
+		evsel->attr.write_backward = 1;
+
+	err = perf_evlist__open(evlist);
+	if (err < 0) {
+		pr_debug("perf_evlist__open: %s\n",
+			 strerror_r(errno, sbuf, sizeof(sbuf)));
+		goto out_delete_evlist;
+	}
+
+	ret = TEST_FAIL;
+	err = do_test(evlist, opts.mmap_pages, &sample_count,
+		      &comm_count);
+	if (err != TEST_OK)
+		goto out_delete_evlist;
+
+	if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
+		pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
+		       sample_count, comm_count);
+		goto out_delete_evlist;
+	}
+
+	err = do_test(evlist, 1, &sample_count, &comm_count);
+	if (err != TEST_OK)
+		goto out_delete_evlist;
+
+	ret = TEST_OK;
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	return ret;
+}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 93c4670..0e95c20 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -208,6 +208,10 @@ static struct test generic_tests[] = {
 		.func = test__event_times,
 	},
 	{
+		.desc = "Test backward reading from ring buffer",
+		.func = test__backward_ring_buffer,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0fc9469..c57e72c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -86,6 +86,7 @@ int test__synthesize_stat(int subtest);
 int test__synthesize_stat_round(int subtest);
 int test__event_update(int subtest);
 int test__event_times(int subtest);
+int test__backward_ring_buffer(int subtest);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
-- 
1.8.3.4

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

* Re: [PATCH v3 2/2] perf tests: Add test to check backward ring buffer
  2016-05-09  1:47 ` [PATCH v3 2/2] perf tests: Add test to check " Wang Nan
@ 2016-05-09 21:12   ` Arnaldo Carvalho de Melo
  2016-05-10 20:32   ` [tip:perf/core] " tip-bot for Wang Nan
  1 sibling, 0 replies; 6+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-05-09 21:12 UTC (permalink / raw)
  To: Wang Nan; +Cc: acme, linux-kernel, lizefan, pi3orama, Peter Zijlstra

Em Mon, May 09, 2016 at 01:47:51AM +0000, Wang Nan escreveu:
> This test checks reading from backward ring buffer.
> 
> Test result:
> 
>  # ~/perf test 'ring buffer'
>  45: Test backward reading from ring buffer                   : Ok

Thanks, applied and also I added a patch to show that bit when using
-vv, i.e.:

      # perf test -vv back
      45: Test backward reading from ring buffer                   :
      --- start ---
      <SNIP>
      ------------------------------------------------------------
      perf_event_attr:
        type                             2
        size                             112
        config                           0x98
        { sample_period, sample_freq }   1
        sample_type                      IP|TID|TIME|CPU|PERIOD|RAW
        disabled                         1
        mmap                             1
        comm                             1
        task                             1
        sample_id_all                    1
        exclude_guest                    1
        mmap2                            1
        comm_exec                        1
        write_backward                   1
      ------------------------------------------------------------
      <SNIP>
 
> Test case is a while loop which calls prctl(PR_SET_NAME) multiple
> times. Each prctl should issue 2 events: one PERF_RECORD_SAMPLE,
> one PERF_RECORD_COMM.
> 
> The first round creates a relative large ring buffer (256 pages). It
> can afford all events. Read from it and check the count of each type of
> events.
> 
> The second round creates a small ring buffer (1 page) and makes it
> overwritable. Check the correctness of the buffer.
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Zefan Li <lizefan@huawei.com>
> Cc: pi3orama@163.com
> ---
>  tools/perf/tests/Build                  |   1 +
>  tools/perf/tests/backward-ring-buffer.c | 151 ++++++++++++++++++++++++++++++++
>  tools/perf/tests/builtin-test.c         |   4 +
>  tools/perf/tests/tests.h                |   1 +
>  4 files changed, 157 insertions(+)
>  create mode 100644 tools/perf/tests/backward-ring-buffer.c
> 
> diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
> index 449fe97..66a2898 100644
> --- a/tools/perf/tests/Build
> +++ b/tools/perf/tests/Build
> @@ -38,6 +38,7 @@ perf-y += cpumap.o
>  perf-y += stat.o
>  perf-y += event_update.o
>  perf-y += event-times.o
> +perf-y += backward-ring-buffer.o
>  
>  $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
>  	$(call rule_mkdir)
> diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
> new file mode 100644
> index 0000000..d9ba991
> --- /dev/null
> +++ b/tools/perf/tests/backward-ring-buffer.c
> @@ -0,0 +1,151 @@
> +/*
> + * Test backward bit in event attribute, read ring buffer from end to
> + * beginning
> + */
> +
> +#include <perf.h>
> +#include <evlist.h>
> +#include <sys/prctl.h>
> +#include "tests.h"
> +#include "debug.h"
> +
> +#define NR_ITERS 111
> +
> +static void testcase(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < NR_ITERS; i++) {
> +		char proc_name[10];
> +
> +		snprintf(proc_name, sizeof(proc_name), "p:%d\n", i);
> +		prctl(PR_SET_NAME, proc_name);
> +	}
> +}
> +
> +static int count_samples(struct perf_evlist *evlist, int *sample_count,
> +			 int *comm_count)
> +{
> +	int i;
> +
> +	for (i = 0; i < evlist->nr_mmaps; i++) {
> +		union perf_event *event;
> +
> +		perf_evlist__mmap_read_catchup(evlist, i);
> +		while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) {
> +			const u32 type = event->header.type;
> +
> +			switch (type) {
> +			case PERF_RECORD_SAMPLE:
> +				(*sample_count)++;
> +				break;
> +			case PERF_RECORD_COMM:
> +				(*comm_count)++;
> +				break;
> +			default:
> +				pr_err("Unexpected record of type %d\n", type);
> +				return TEST_FAIL;
> +			}
> +		}
> +	}
> +	return TEST_OK;
> +}
> +
> +static int do_test(struct perf_evlist *evlist, int mmap_pages,
> +		   int *sample_count, int *comm_count)
> +{
> +	int err;
> +	char sbuf[STRERR_BUFSIZE];
> +
> +	err = perf_evlist__mmap(evlist, mmap_pages, true);
> +	if (err < 0) {
> +		pr_debug("perf_evlist__mmap: %s\n",
> +			 strerror_r(errno, sbuf, sizeof(sbuf)));
> +		return TEST_FAIL;
> +	}
> +
> +	perf_evlist__enable(evlist);
> +	testcase();
> +	perf_evlist__disable(evlist);
> +
> +	err = count_samples(evlist, sample_count, comm_count);
> +	perf_evlist__munmap(evlist);
> +	return err;
> +}
> +
> +
> +int test__backward_ring_buffer(int subtest __maybe_unused)
> +{
> +	int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0;
> +	char pid[16], sbuf[STRERR_BUFSIZE];
> +	struct perf_evlist *evlist;
> +	struct perf_evsel *evsel __maybe_unused;
> +	struct parse_events_error parse_error;
> +	struct record_opts opts = {
> +		.target = {
> +			.uid = UINT_MAX,
> +			.uses_mmap = true,
> +		},
> +		.freq	      = 0,
> +		.mmap_pages   = 256,
> +		.default_interval = 1,
> +	};
> +
> +	snprintf(pid, sizeof(pid), "%d", getpid());
> +	pid[sizeof(pid) - 1] = '\0';
> +	opts.target.tid = opts.target.pid = pid;
> +
> +	evlist = perf_evlist__new();
> +	if (!evlist) {
> +		pr_debug("No ehough memory to create evlist\n");
> +		return TEST_FAIL;
> +	}
> +
> +	err = perf_evlist__create_maps(evlist, &opts.target);
> +	if (err < 0) {
> +		pr_debug("Not enough memory to create thread/cpu maps\n");
> +		goto out_delete_evlist;
> +	}
> +
> +	bzero(&parse_error, sizeof(parse_error));
> +	err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error);
> +	if (err) {
> +		pr_debug("Failed to parse tracepoint event, try use root\n");
> +		ret = TEST_SKIP;
> +		goto out_delete_evlist;
> +	}
> +
> +	perf_evlist__config(evlist, &opts, NULL);
> +
> +	/* Set backward bit, ring buffer should be writing from end */
> +	evlist__for_each(evlist, evsel)
> +		evsel->attr.write_backward = 1;
> +
> +	err = perf_evlist__open(evlist);
> +	if (err < 0) {
> +		pr_debug("perf_evlist__open: %s\n",
> +			 strerror_r(errno, sbuf, sizeof(sbuf)));
> +		goto out_delete_evlist;
> +	}
> +
> +	ret = TEST_FAIL;
> +	err = do_test(evlist, opts.mmap_pages, &sample_count,
> +		      &comm_count);
> +	if (err != TEST_OK)
> +		goto out_delete_evlist;
> +
> +	if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
> +		pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
> +		       sample_count, comm_count);
> +		goto out_delete_evlist;
> +	}
> +
> +	err = do_test(evlist, 1, &sample_count, &comm_count);
> +	if (err != TEST_OK)
> +		goto out_delete_evlist;
> +
> +	ret = TEST_OK;
> +out_delete_evlist:
> +	perf_evlist__delete(evlist);
> +	return ret;
> +}
> diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
> index 93c4670..0e95c20 100644
> --- a/tools/perf/tests/builtin-test.c
> +++ b/tools/perf/tests/builtin-test.c
> @@ -208,6 +208,10 @@ static struct test generic_tests[] = {
>  		.func = test__event_times,
>  	},
>  	{
> +		.desc = "Test backward reading from ring buffer",
> +		.func = test__backward_ring_buffer,
> +	},
> +	{
>  		.func = NULL,
>  	},
>  };
> diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
> index 0fc9469..c57e72c 100644
> --- a/tools/perf/tests/tests.h
> +++ b/tools/perf/tests/tests.h
> @@ -86,6 +86,7 @@ int test__synthesize_stat(int subtest);
>  int test__synthesize_stat_round(int subtest);
>  int test__event_update(int subtest);
>  int test__event_times(int subtest);
> +int test__backward_ring_buffer(int subtest);
>  
>  #if defined(__arm__) || defined(__aarch64__)
>  #ifdef HAVE_DWARF_UNWIND_SUPPORT
> -- 
> 1.8.3.4

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

* [tip:perf/core] perf tools: Support reading from backward ring buffer
  2016-05-09  1:47 ` [PATCH v3 1/2] perf tools: Support reading from backward ring buffer Wang Nan
@ 2016-05-10 20:31   ` tip-bot for Wang Nan
  0 siblings, 0 replies; 6+ messages in thread
From: tip-bot for Wang Nan @ 2016-05-10 20:31 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: tglx, lizefan, acme, mingo, wangnan0, hpa, linux-kernel, peterz

Commit-ID:  e24c7520ea9c3e5bb51592c2134aafbf75a3f88a
Gitweb:     http://git.kernel.org/tip/e24c7520ea9c3e5bb51592c2134aafbf75a3f88a
Author:     Wang Nan <wangnan0@huawei.com>
AuthorDate: Mon, 9 May 2016 01:47:50 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 9 May 2016 17:20:53 -0300

perf tools: Support reading from backward ring buffer

perf_evlist__mmap_read_backward() is introduced for reading backward
ring buffer. Since direction for reading such ring buffer is different
from the direction kernel writing to it, and since user need to fetch
most recent record from it, a perf_evlist__mmap_read_catchup() is
introduced to move the reading pointer to the end of the buffer.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1462758471-89706-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/evlist.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h |  4 ++++
 2 files changed, 54 insertions(+)

diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 17cd014..c4bfe11 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -766,6 +766,56 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 	return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev);
 }
 
+union perf_event *
+perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx)
+{
+	struct perf_mmap *md = &evlist->mmap[idx];
+	u64 head, end;
+	u64 start = md->prev;
+
+	/*
+	 * Check if event was unmapped due to a POLLHUP/POLLERR.
+	 */
+	if (!atomic_read(&md->refcnt))
+		return NULL;
+
+	head = perf_mmap__read_head(md);
+	if (!head)
+		return NULL;
+
+	/*
+	 * 'head' pointer starts from 0. Kernel minus sizeof(record) form
+	 * it each time when kernel writes to it, so in fact 'head' is
+	 * negative. 'end' pointer is made manually by adding the size of
+	 * the ring buffer to 'head' pointer, means the validate data can
+	 * read is the whole ring buffer. If 'end' is positive, the ring
+	 * buffer has not fully filled, so we must adjust 'end' to 0.
+	 *
+	 * However, since both 'head' and 'end' is unsigned, we can't
+	 * simply compare 'end' against 0. Here we compare '-head' and
+	 * the size of the ring buffer, where -head is the number of bytes
+	 * kernel write to the ring buffer.
+	 */
+	if (-head < (u64)(md->mask + 1))
+		end = 0;
+	else
+		end = head + md->mask + 1;
+
+	return perf_mmap__read(md, false, start, end, &md->prev);
+}
+
+void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx)
+{
+	struct perf_mmap *md = &evlist->mmap[idx];
+	u64 head;
+
+	if (!atomic_read(&md->refcnt))
+		return;
+
+	head = perf_mmap__read_head(md);
+	md->prev = head;
+}
+
 static bool perf_mmap__empty(struct perf_mmap *md)
 {
 	return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 208897a..85d1b59 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -129,6 +129,10 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
 
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
 
+union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist,
+						  int idx);
+void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
+
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
 
 int perf_evlist__open(struct perf_evlist *evlist);

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

* [tip:perf/core] perf tests: Add test to check backward ring buffer
  2016-05-09  1:47 ` [PATCH v3 2/2] perf tests: Add test to check " Wang Nan
  2016-05-09 21:12   ` Arnaldo Carvalho de Melo
@ 2016-05-10 20:32   ` tip-bot for Wang Nan
  1 sibling, 0 replies; 6+ messages in thread
From: tip-bot for Wang Nan @ 2016-05-10 20:32 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: mingo, hpa, lizefan, acme, tglx, wangnan0, peterz, linux-kernel

Commit-ID:  ee74701ed8add8ad13e642e8618b51fd75add32d
Gitweb:     http://git.kernel.org/tip/ee74701ed8add8ad13e642e8618b51fd75add32d
Author:     Wang Nan <wangnan0@huawei.com>
AuthorDate: Mon, 9 May 2016 01:47:51 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 9 May 2016 18:11:22 -0300

perf tests: Add test to check backward ring buffer

This test checks reading from backward ring buffer.

Test result:

  # ~/perf test 'ring buffer'
  45: Test backward reading from ring buffer                   : Ok

The test case is a while loop which calls prctl(PR_SET_NAME) multiple
times.  Each prctl should issue 2 events: one PERF_RECORD_SAMPLE, one
PERF_RECORD_COMM.

The first round creates a relative large ring buffer (256 pages). It can
afford all events. Read from it and check the count of each type of
events.

The second round creates a small ring buffer (1 page) and makes it
overwritable. Check the correctness of the buffer.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1462758471-89706-3-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/Build                  |   1 +
 tools/perf/tests/backward-ring-buffer.c | 151 ++++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c         |   4 +
 tools/perf/tests/tests.h                |   1 +
 4 files changed, 157 insertions(+)

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 449fe97..66a2898 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -38,6 +38,7 @@ perf-y += cpumap.o
 perf-y += stat.o
 perf-y += event_update.o
 perf-y += event-times.o
+perf-y += backward-ring-buffer.o
 
 $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
 	$(call rule_mkdir)
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c
new file mode 100644
index 0000000..d9ba991
--- /dev/null
+++ b/tools/perf/tests/backward-ring-buffer.c
@@ -0,0 +1,151 @@
+/*
+ * Test backward bit in event attribute, read ring buffer from end to
+ * beginning
+ */
+
+#include <perf.h>
+#include <evlist.h>
+#include <sys/prctl.h>
+#include "tests.h"
+#include "debug.h"
+
+#define NR_ITERS 111
+
+static void testcase(void)
+{
+	int i;
+
+	for (i = 0; i < NR_ITERS; i++) {
+		char proc_name[10];
+
+		snprintf(proc_name, sizeof(proc_name), "p:%d\n", i);
+		prctl(PR_SET_NAME, proc_name);
+	}
+}
+
+static int count_samples(struct perf_evlist *evlist, int *sample_count,
+			 int *comm_count)
+{
+	int i;
+
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		union perf_event *event;
+
+		perf_evlist__mmap_read_catchup(evlist, i);
+		while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) {
+			const u32 type = event->header.type;
+
+			switch (type) {
+			case PERF_RECORD_SAMPLE:
+				(*sample_count)++;
+				break;
+			case PERF_RECORD_COMM:
+				(*comm_count)++;
+				break;
+			default:
+				pr_err("Unexpected record of type %d\n", type);
+				return TEST_FAIL;
+			}
+		}
+	}
+	return TEST_OK;
+}
+
+static int do_test(struct perf_evlist *evlist, int mmap_pages,
+		   int *sample_count, int *comm_count)
+{
+	int err;
+	char sbuf[STRERR_BUFSIZE];
+
+	err = perf_evlist__mmap(evlist, mmap_pages, true);
+	if (err < 0) {
+		pr_debug("perf_evlist__mmap: %s\n",
+			 strerror_r(errno, sbuf, sizeof(sbuf)));
+		return TEST_FAIL;
+	}
+
+	perf_evlist__enable(evlist);
+	testcase();
+	perf_evlist__disable(evlist);
+
+	err = count_samples(evlist, sample_count, comm_count);
+	perf_evlist__munmap(evlist);
+	return err;
+}
+
+
+int test__backward_ring_buffer(int subtest __maybe_unused)
+{
+	int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0;
+	char pid[16], sbuf[STRERR_BUFSIZE];
+	struct perf_evlist *evlist;
+	struct perf_evsel *evsel __maybe_unused;
+	struct parse_events_error parse_error;
+	struct record_opts opts = {
+		.target = {
+			.uid = UINT_MAX,
+			.uses_mmap = true,
+		},
+		.freq	      = 0,
+		.mmap_pages   = 256,
+		.default_interval = 1,
+	};
+
+	snprintf(pid, sizeof(pid), "%d", getpid());
+	pid[sizeof(pid) - 1] = '\0';
+	opts.target.tid = opts.target.pid = pid;
+
+	evlist = perf_evlist__new();
+	if (!evlist) {
+		pr_debug("No ehough memory to create evlist\n");
+		return TEST_FAIL;
+	}
+
+	err = perf_evlist__create_maps(evlist, &opts.target);
+	if (err < 0) {
+		pr_debug("Not enough memory to create thread/cpu maps\n");
+		goto out_delete_evlist;
+	}
+
+	bzero(&parse_error, sizeof(parse_error));
+	err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error);
+	if (err) {
+		pr_debug("Failed to parse tracepoint event, try use root\n");
+		ret = TEST_SKIP;
+		goto out_delete_evlist;
+	}
+
+	perf_evlist__config(evlist, &opts, NULL);
+
+	/* Set backward bit, ring buffer should be writing from end */
+	evlist__for_each(evlist, evsel)
+		evsel->attr.write_backward = 1;
+
+	err = perf_evlist__open(evlist);
+	if (err < 0) {
+		pr_debug("perf_evlist__open: %s\n",
+			 strerror_r(errno, sbuf, sizeof(sbuf)));
+		goto out_delete_evlist;
+	}
+
+	ret = TEST_FAIL;
+	err = do_test(evlist, opts.mmap_pages, &sample_count,
+		      &comm_count);
+	if (err != TEST_OK)
+		goto out_delete_evlist;
+
+	if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
+		pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
+		       sample_count, comm_count);
+		goto out_delete_evlist;
+	}
+
+	err = do_test(evlist, 1, &sample_count, &comm_count);
+	if (err != TEST_OK)
+		goto out_delete_evlist;
+
+	ret = TEST_OK;
+out_delete_evlist:
+	perf_evlist__delete(evlist);
+	return ret;
+}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 93c4670..0e95c20 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -208,6 +208,10 @@ static struct test generic_tests[] = {
 		.func = test__event_times,
 	},
 	{
+		.desc = "Test backward reading from ring buffer",
+		.func = test__backward_ring_buffer,
+	},
+	{
 		.func = NULL,
 	},
 };
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0fc9469..c57e72c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -86,6 +86,7 @@ int test__synthesize_stat(int subtest);
 int test__synthesize_stat_round(int subtest);
 int test__event_update(int subtest);
 int test__event_times(int subtest);
+int test__backward_ring_buffer(int subtest);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT

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

end of thread, other threads:[~2016-05-10 20:32 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-09  1:47 [PATCH v3 0/2] perf tools: Backward ring buffer support Wang Nan
2016-05-09  1:47 ` [PATCH v3 1/2] perf tools: Support reading from backward ring buffer Wang Nan
2016-05-10 20:31   ` [tip:perf/core] " tip-bot for Wang Nan
2016-05-09  1:47 ` [PATCH v3 2/2] perf tests: Add test to check " Wang Nan
2016-05-09 21:12   ` Arnaldo Carvalho de Melo
2016-05-10 20:32   ` [tip:perf/core] " tip-bot for Wang Nan

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).