All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Tidy user rdpmc documentation and testing
@ 2022-07-19 22:39 Ian Rogers
  2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Ian Rogers @ 2022-07-19 22:39 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring
  Cc: Stephane Eranian, Ian Rogers

libperf's perf_mmap__read_self and the addition of arm64 support mean
that the perf_event.h and the rdpmc perf test have become
stale. Refresh the documentation in perf_event.h, remove the x86 rdpmc
test and port the libperf test as a non-architecture specific test.

A comment is added to perf_event.h to avoid a divide by zero when
scaling counts if the running time is 0. This was previously discussed
in this thread:
https://lore.kernel.org/lkml/CAP-5=fVRdqvswtyQMg5cB+ntTGda+SAYskjTQednEH-AeZo13g@mail.gmail.com/

v3. Incorporates fixes from Rob Herring <robh@kernel.org> to make the
    perf_event.h comments better. It drops the already merged sanitizer fix.
v2. Alters the skip in test_stat_user_read for open to always be a
    skip as perf_event_open may fail with EACCES (permissions), ENOSYS
    (not supported) and ENOENT (hypervisor). Adds Rob Herring's
    acked-by on patch 3.

Ian Rogers (3):
  perf: Align user space counter reading with code
  perf test: Remove x86 rdpmc test
  perf test: Add user space counter reading tests

 include/uapi/linux/perf_event.h        |  35 +++--
 tools/include/uapi/linux/perf_event.h  |  35 +++--
 tools/perf/arch/x86/tests/Build        |   1 -
 tools/perf/arch/x86/tests/arch-tests.c |   2 -
 tools/perf/arch/x86/tests/rdpmc.c      | 182 -------------------------
 tools/perf/tests/mmap-basic.c          | 127 ++++++++++++++++-
 6 files changed, 170 insertions(+), 212 deletions(-)
 delete mode 100644 tools/perf/arch/x86/tests/rdpmc.c

-- 
2.37.0.170.g444d1eabd0-goog


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

* [PATCH v3 1/3] perf: Align user space counter reading with code
  2022-07-19 22:39 [PATCH v3 0/3] Tidy user rdpmc documentation and testing Ian Rogers
@ 2022-07-19 22:39 ` Ian Rogers
  2022-07-19 23:05   ` Rob Herring
                     ` (2 more replies)
  2022-07-19 22:39 ` [PATCH v3 2/3] perf test: Remove x86 rdpmc test Ian Rogers
  2022-07-19 22:39 ` [PATCH v3 3/3] perf test: Add user space counter reading tests Ian Rogers
  2 siblings, 3 replies; 13+ messages in thread
From: Ian Rogers @ 2022-07-19 22:39 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring
  Cc: Stephane Eranian, Ian Rogers

Align the user space counter reading documentation with the code in
perf_mmap__read_self. Previously the documentation was based on the perf
rdpmc test, but now general purpose code is provided by libperf.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 include/uapi/linux/perf_event.h       | 35 +++++++++++++++++----------
 tools/include/uapi/linux/perf_event.h | 35 +++++++++++++++++----------
 2 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index d37629dbad72..6826dabb7e03 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -538,9 +538,13 @@ struct perf_event_mmap_page {
 	 *
 	 *     if (pc->cap_usr_time && enabled != running) {
 	 *       cyc = rdtsc();
-	 *       time_offset = pc->time_offset;
 	 *       time_mult   = pc->time_mult;
 	 *       time_shift  = pc->time_shift;
+	 *       time_offset = pc->time_offset;
+	 *       if (pc->cap_user_time_short) {
+	 *         time_cycles = pc->time_cycles;
+	 *         time_mask = pc->time_mask;
+	 *       }
 	 *     }
 	 *
 	 *     index = pc->index;
@@ -548,6 +552,9 @@ struct perf_event_mmap_page {
 	 *     if (pc->cap_user_rdpmc && index) {
 	 *       width = pc->pmc_width;
 	 *       pmc = rdpmc(index - 1);
+	 *       pmc <<= 64 - width;
+	 *       pmc >>= 64 - width;
+	 *       count += pmc;
 	 *     }
 	 *
 	 *     barrier();
@@ -590,25 +597,27 @@ struct perf_event_mmap_page {
 	 * If cap_usr_time the below fields can be used to compute the time
 	 * delta since time_enabled (in ns) using rdtsc or similar.
 	 *
-	 *   u64 quot, rem;
-	 *   u64 delta;
-	 *
-	 *   quot = (cyc >> time_shift);
-	 *   rem = cyc & (((u64)1 << time_shift) - 1);
-	 *   delta = time_offset + quot * time_mult +
-	 *              ((rem * time_mult) >> time_shift);
+	 *   cyc = time_cycles + ((cyc - time_cycles) & time_mask);
+	 *   delta = time_offset + mul_u64_u32_shr(cyc, time_mult, time_shift);
 	 *
 	 * Where time_offset,time_mult,time_shift and cyc are read in the
-	 * seqcount loop described above. This delta can then be added to
-	 * enabled and possible running (if index), improving the scaling:
+	 * seqcount loop described above. mul_u64_u32_shr will compute:
+	 *
+	 *   (u64)(((unsigned __int128)cyc * time_mult) >> time_shift)
+	 *
+	 * This delta can then be added to enabled and possible running (if
+	 * index) to improve the scaling. Due to event multiplexing, running
+	 * may be zero and so care is needed to avoid division by zero.
 	 *
 	 *   enabled += delta;
 	 *   if (index)
 	 *     running += delta;
 	 *
-	 *   quot = count / running;
-	 *   rem  = count % running;
-	 *   count = quot * enabled + (rem * enabled) / running;
+	 *   if (running != 0) {
+	 *     quot = count / running;
+	 *     rem  = count % running;
+	 *     count = quot * enabled + (rem * enabled) / running;
+	 *   }
 	 */
 	__u16	time_shift;
 	__u32	time_mult;
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index d37629dbad72..6826dabb7e03 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -538,9 +538,13 @@ struct perf_event_mmap_page {
 	 *
 	 *     if (pc->cap_usr_time && enabled != running) {
 	 *       cyc = rdtsc();
-	 *       time_offset = pc->time_offset;
 	 *       time_mult   = pc->time_mult;
 	 *       time_shift  = pc->time_shift;
+	 *       time_offset = pc->time_offset;
+	 *       if (pc->cap_user_time_short) {
+	 *         time_cycles = pc->time_cycles;
+	 *         time_mask = pc->time_mask;
+	 *       }
 	 *     }
 	 *
 	 *     index = pc->index;
@@ -548,6 +552,9 @@ struct perf_event_mmap_page {
 	 *     if (pc->cap_user_rdpmc && index) {
 	 *       width = pc->pmc_width;
 	 *       pmc = rdpmc(index - 1);
+	 *       pmc <<= 64 - width;
+	 *       pmc >>= 64 - width;
+	 *       count += pmc;
 	 *     }
 	 *
 	 *     barrier();
@@ -590,25 +597,27 @@ struct perf_event_mmap_page {
 	 * If cap_usr_time the below fields can be used to compute the time
 	 * delta since time_enabled (in ns) using rdtsc or similar.
 	 *
-	 *   u64 quot, rem;
-	 *   u64 delta;
-	 *
-	 *   quot = (cyc >> time_shift);
-	 *   rem = cyc & (((u64)1 << time_shift) - 1);
-	 *   delta = time_offset + quot * time_mult +
-	 *              ((rem * time_mult) >> time_shift);
+	 *   cyc = time_cycles + ((cyc - time_cycles) & time_mask);
+	 *   delta = time_offset + mul_u64_u32_shr(cyc, time_mult, time_shift);
 	 *
 	 * Where time_offset,time_mult,time_shift and cyc are read in the
-	 * seqcount loop described above. This delta can then be added to
-	 * enabled and possible running (if index), improving the scaling:
+	 * seqcount loop described above. mul_u64_u32_shr will compute:
+	 *
+	 *   (u64)(((unsigned __int128)cyc * time_mult) >> time_shift)
+	 *
+	 * This delta can then be added to enabled and possible running (if
+	 * index) to improve the scaling. Due to event multiplexing, running
+	 * may be zero and so care is needed to avoid division by zero.
 	 *
 	 *   enabled += delta;
 	 *   if (index)
 	 *     running += delta;
 	 *
-	 *   quot = count / running;
-	 *   rem  = count % running;
-	 *   count = quot * enabled + (rem * enabled) / running;
+	 *   if (running != 0) {
+	 *     quot = count / running;
+	 *     rem  = count % running;
+	 *     count = quot * enabled + (rem * enabled) / running;
+	 *   }
 	 */
 	__u16	time_shift;
 	__u32	time_mult;
-- 
2.37.0.170.g444d1eabd0-goog


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

* [PATCH v3 2/3] perf test: Remove x86 rdpmc test
  2022-07-19 22:39 [PATCH v3 0/3] Tidy user rdpmc documentation and testing Ian Rogers
  2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
@ 2022-07-19 22:39 ` Ian Rogers
  2022-08-01 12:19   ` Arnaldo Carvalho de Melo
  2022-07-19 22:39 ` [PATCH v3 3/3] perf test: Add user space counter reading tests Ian Rogers
  2 siblings, 1 reply; 13+ messages in thread
From: Ian Rogers @ 2022-07-19 22:39 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring
  Cc: Stephane Eranian, Ian Rogers

This test has been superseded by test_stat_user_read in:
tools/lib/perf/tests/test-evsel.c
The updated test doesn't divide-by-0 when running time of a counter is
0. It also supports ARM64.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/arch/x86/tests/Build        |   1 -
 tools/perf/arch/x86/tests/arch-tests.c |   2 -
 tools/perf/arch/x86/tests/rdpmc.c      | 182 -------------------------
 3 files changed, 185 deletions(-)
 delete mode 100644 tools/perf/arch/x86/tests/rdpmc.c

diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build
index 28d793390198..70b5bcbc15df 100644
--- a/tools/perf/arch/x86/tests/Build
+++ b/tools/perf/arch/x86/tests/Build
@@ -2,7 +2,6 @@ perf-$(CONFIG_DWARF_UNWIND) += regs_load.o
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 
 perf-y += arch-tests.o
-perf-y += rdpmc.o
 perf-y += sample-parsing.o
 perf-$(CONFIG_AUXTRACE) += insn-x86.o intel-pt-pkt-decoder-test.o
 perf-$(CONFIG_X86_64) += bp-modify.o
diff --git a/tools/perf/arch/x86/tests/arch-tests.c b/tools/perf/arch/x86/tests/arch-tests.c
index 64fb73d14d2f..04018b8aa85b 100644
--- a/tools/perf/arch/x86/tests/arch-tests.c
+++ b/tools/perf/arch/x86/tests/arch-tests.c
@@ -3,7 +3,6 @@
 #include "tests/tests.h"
 #include "arch-tests.h"
 
-DEFINE_SUITE("x86 rdpmc", rdpmc);
 #ifdef HAVE_AUXTRACE_SUPPORT
 DEFINE_SUITE("x86 instruction decoder - new instructions", insn_x86);
 DEFINE_SUITE("Intel PT packet decoder", intel_pt_pkt_decoder);
@@ -14,7 +13,6 @@ DEFINE_SUITE("x86 bp modify", bp_modify);
 DEFINE_SUITE("x86 Sample parsing", x86_sample_parsing);
 
 struct test_suite *arch_tests[] = {
-	&suite__rdpmc,
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
 	&suite__dwarf_unwind,
 #endif
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
deleted file mode 100644
index 498413ad9c97..000000000000
--- a/tools/perf/arch/x86/tests/rdpmc.c
+++ /dev/null
@@ -1,182 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include "perf-sys.h"
-#include "debug.h"
-#include "tests/tests.h"
-#include "cloexec.h"
-#include "event.h"
-#include <internal/lib.h> // page_size
-#include "arch-tests.h"
-
-static u64 rdpmc(unsigned int counter)
-{
-	unsigned int low, high;
-
-	asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
-
-	return low | ((u64)high) << 32;
-}
-
-static u64 rdtsc(void)
-{
-	unsigned int low, high;
-
-	asm volatile("rdtsc" : "=a" (low), "=d" (high));
-
-	return low | ((u64)high) << 32;
-}
-
-static u64 mmap_read_self(void *addr)
-{
-	struct perf_event_mmap_page *pc = addr;
-	u32 seq, idx, time_mult = 0, time_shift = 0;
-	u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
-
-	do {
-		seq = pc->lock;
-		barrier();
-
-		enabled = pc->time_enabled;
-		running = pc->time_running;
-
-		if (enabled != running) {
-			cyc = rdtsc();
-			time_mult = pc->time_mult;
-			time_shift = pc->time_shift;
-			time_offset = pc->time_offset;
-		}
-
-		idx = pc->index;
-		count = pc->offset;
-		if (idx)
-			count += rdpmc(idx - 1);
-
-		barrier();
-	} while (pc->lock != seq);
-
-	if (enabled != running) {
-		u64 quot, rem;
-
-		quot = (cyc >> time_shift);
-		rem = cyc & (((u64)1 << time_shift) - 1);
-		delta = time_offset + quot * time_mult +
-			((rem * time_mult) >> time_shift);
-
-		enabled += delta;
-		if (idx)
-			running += delta;
-
-		quot = count / running;
-		rem = count % running;
-		count = quot * enabled + (rem * enabled) / running;
-	}
-
-	return count;
-}
-
-/*
- * If the RDPMC instruction faults then signal this back to the test parent task:
- */
-static void segfault_handler(int sig __maybe_unused,
-			     siginfo_t *info __maybe_unused,
-			     void *uc __maybe_unused)
-{
-	exit(-1);
-}
-
-static int __test__rdpmc(void)
-{
-	volatile int tmp = 0;
-	u64 i, loops = 1000;
-	int n;
-	int fd;
-	void *addr;
-	struct perf_event_attr attr = {
-		.type = PERF_TYPE_HARDWARE,
-		.config = PERF_COUNT_HW_INSTRUCTIONS,
-		.exclude_kernel = 1,
-	};
-	u64 delta_sum = 0;
-        struct sigaction sa;
-	char sbuf[STRERR_BUFSIZE];
-
-	sigfillset(&sa.sa_mask);
-	sa.sa_sigaction = segfault_handler;
-	sa.sa_flags = 0;
-	sigaction(SIGSEGV, &sa, NULL);
-
-	fd = sys_perf_event_open(&attr, 0, -1, -1,
-				 perf_event_open_cloexec_flag());
-	if (fd < 0) {
-		pr_err("Error: sys_perf_event_open() syscall returned "
-		       "with %d (%s)\n", fd,
-		       str_error_r(errno, sbuf, sizeof(sbuf)));
-		return -1;
-	}
-
-	addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
-	if (addr == (void *)(-1)) {
-		pr_err("Error: mmap() syscall returned with (%s)\n",
-		       str_error_r(errno, sbuf, sizeof(sbuf)));
-		goto out_close;
-	}
-
-	for (n = 0; n < 6; n++) {
-		u64 stamp, now, delta;
-
-		stamp = mmap_read_self(addr);
-
-		for (i = 0; i < loops; i++)
-			tmp++;
-
-		now = mmap_read_self(addr);
-		loops *= 10;
-
-		delta = now - stamp;
-		pr_debug("%14d: %14Lu\n", n, (long long)delta);
-
-		delta_sum += delta;
-	}
-
-	munmap(addr, page_size);
-	pr_debug("   ");
-out_close:
-	close(fd);
-
-	if (!delta_sum)
-		return -1;
-
-	return 0;
-}
-
-int test__rdpmc(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
-{
-	int status = 0;
-	int wret = 0;
-	int ret;
-	int pid;
-
-	pid = fork();
-	if (pid < 0)
-		return -1;
-
-	if (!pid) {
-		ret = __test__rdpmc();
-
-		exit(ret);
-	}
-
-	wret = waitpid(pid, &status, 0);
-	if (wret < 0 || status)
-		return -1;
-
-	return 0;
-}
-- 
2.37.0.170.g444d1eabd0-goog


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

* [PATCH v3 3/3] perf test: Add user space counter reading tests
  2022-07-19 22:39 [PATCH v3 0/3] Tidy user rdpmc documentation and testing Ian Rogers
  2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
  2022-07-19 22:39 ` [PATCH v3 2/3] perf test: Remove x86 rdpmc test Ian Rogers
@ 2022-07-19 22:39 ` Ian Rogers
  2022-07-20 14:57   ` Vince Weaver
  2022-08-01 12:23   ` Arnaldo Carvalho de Melo
  2 siblings, 2 replies; 13+ messages in thread
From: Ian Rogers @ 2022-07-19 22:39 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring
  Cc: Stephane Eranian, Ian Rogers

These tests are based on test_stat_user_read in
tools/lib/perf/tests/test-evsel.c. The tests are modified to skip if
perf_event_open fails or rdpmc isn't supported.

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/tests/mmap-basic.c | 127 +++++++++++++++++++++++++++++++++-
 1 file changed, 126 insertions(+), 1 deletion(-)

diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 30bbe144648a..dfb6173b2a82 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -170,14 +170,139 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
 	return err;
 }
 
+static int test_stat_user_read(int event)
+{
+	struct perf_counts_values counts = { .val = 0 };
+	struct perf_thread_map *threads;
+	struct perf_evsel *evsel;
+	struct perf_event_mmap_page *pc;
+	struct perf_event_attr attr = {
+		.type	= PERF_TYPE_HARDWARE,
+		.config	= event,
+#ifdef __aarch64__
+		.config1 = 0x2,		/* Request user access */
+#endif
+	};
+	int err, i, ret = TEST_FAIL;
+	bool opened = false, mapped = false;
+
+	threads = perf_thread_map__new_dummy();
+	TEST_ASSERT_VAL("failed to create threads", threads);
+
+	perf_thread_map__set_pid(threads, 0, 0);
+
+	evsel = perf_evsel__new(&attr);
+	TEST_ASSERT_VAL("failed to create evsel", evsel);
+
+	err = perf_evsel__open(evsel, NULL, threads);
+	if (err) {
+		pr_err("failed to open evsel: %s\n", strerror(-err));
+		ret = TEST_SKIP;
+		goto out;
+	}
+	opened = true;
+
+	err = perf_evsel__mmap(evsel, 0);
+	if (err) {
+		pr_err("failed to mmap evsel: %s\n", strerror(-err));
+		goto out;
+	}
+	mapped = true;
+
+	pc = perf_evsel__mmap_base(evsel, 0, 0);
+	if (!pc) {
+		pr_err("failed to get mmapped address\n");
+		goto out;
+	}
+
+	if (!pc->cap_user_rdpmc || !pc->index) {
+		pr_err("userspace counter access not %s\n",
+			!pc->cap_user_rdpmc ? "supported" : "enabled");
+		ret = TEST_SKIP;
+		goto out;
+	}
+	if (pc->pmc_width < 32) {
+		pr_err("userspace counter width not set (%d)\n", pc->pmc_width);
+		goto out;
+	}
+
+	perf_evsel__read(evsel, 0, 0, &counts);
+	if (counts.val == 0) {
+		pr_err("failed to read value for evsel\n");
+		goto out;
+	}
+
+	for (i = 0; i < 5; i++) {
+		volatile int count = 0x10000 << i;
+		__u64 start, end, last = 0;
+
+		pr_debug("\tloop = %u, ", count);
+
+		perf_evsel__read(evsel, 0, 0, &counts);
+		start = counts.val;
+
+		while (count--) ;
+
+		perf_evsel__read(evsel, 0, 0, &counts);
+		end = counts.val;
+
+		if ((end - start) < last) {
+			pr_err("invalid counter data: end=%llu start=%llu last= %llu\n",
+				end, start, last);
+			goto out;
+		}
+		last = end - start;
+		pr_debug("count = %llu\n", end - start);
+	}
+	ret = TEST_OK;
+
+out:
+	if (mapped)
+		perf_evsel__munmap(evsel);
+	if (opened)
+		perf_evsel__close(evsel);
+	perf_evsel__delete(evsel);
+
+	perf_thread_map__put(threads);
+	return ret;
+}
+
+static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
+				      int subtest __maybe_unused)
+{
+	return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
+}
+
+static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,
+				       int subtest __maybe_unused)
+{
+	return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
+}
+
 static struct test_case tests__basic_mmap[] = {
 	TEST_CASE_REASON("Read samples using the mmap interface",
 			 basic_mmap,
 			 "permissions"),
+	TEST_CASE_REASON("User space counter reading of instructions",
+			 mmap_user_read_instr,
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+			 "permissions"
+#else
+			 "unsupported"
+#endif
+		),
+	TEST_CASE_REASON("User space counter reading of cycles",
+			 mmap_user_read_cycles,
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+			 "permissions"
+#else
+			 "unsupported"
+#endif
+		),
 	{	.name = NULL, }
 };
 
 struct test_suite suite__basic_mmap = {
-	.desc = "Read samples using the mmap interface",
+	.desc = "mmap interface tests",
 	.test_cases = tests__basic_mmap,
 };
-- 
2.37.0.170.g444d1eabd0-goog


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

* Re: [PATCH v3 1/3] perf: Align user space counter reading with code
  2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
@ 2022-07-19 23:05   ` Rob Herring
  2022-07-20 15:06   ` Vince Weaver
  2022-08-01 12:17   ` Arnaldo Carvalho de Melo
  2 siblings, 0 replies; 13+ messages in thread
From: Rob Herring @ 2022-07-19 23:05 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Stephane Eranian

On Tue, Jul 19, 2022 at 4:39 PM Ian Rogers <irogers@google.com> wrote:
>
> Align the user space counter reading documentation with the code in
> perf_mmap__read_self. Previously the documentation was based on the perf
> rdpmc test, but now general purpose code is provided by libperf.
>
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  include/uapi/linux/perf_event.h       | 35 +++++++++++++++++----------
>  tools/include/uapi/linux/perf_event.h | 35 +++++++++++++++++----------
>  2 files changed, 44 insertions(+), 26 deletions(-)

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v3 3/3] perf test: Add user space counter reading tests
  2022-07-19 22:39 ` [PATCH v3 3/3] perf test: Add user space counter reading tests Ian Rogers
@ 2022-07-20 14:57   ` Vince Weaver
  2022-07-20 15:09     ` Ian Rogers
  2022-08-01 12:23   ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 13+ messages in thread
From: Vince Weaver @ 2022-07-20 14:57 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring, Stephane Eranian

On Tue, 19 Jul 2022, Ian Rogers wrote:

> These tests are based on test_stat_user_read in
> tools/lib/perf/tests/test-evsel.c. The tests are modified to skip if
> perf_event_open fails or rdpmc isn't supported.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>

> +		.type	= PERF_TYPE_HARDWARE,
> +		.config	= event,
> +#ifdef __aarch64__
> +		.config1 = 0x2,		/* Request user access */
> +#endif

should this value have a name rather than being a "magic constant"?

Vince

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

* Re: [PATCH v3 1/3] perf: Align user space counter reading with code
  2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
  2022-07-19 23:05   ` Rob Herring
@ 2022-07-20 15:06   ` Vince Weaver
  2022-07-20 15:18     ` Ian Rogers
  2022-08-04  8:49     ` Ingo Molnar
  2022-08-01 12:17   ` Arnaldo Carvalho de Melo
  2 siblings, 2 replies; 13+ messages in thread
From: Vince Weaver @ 2022-07-20 15:06 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring, Stephane Eranian

On Tue, 19 Jul 2022, Ian Rogers wrote:

> Align the user space counter reading documentation with the code in
> perf_mmap__read_self. Previously the documentation was based on the perf
> rdpmc test, but now general purpose code is provided by libperf.
> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  include/uapi/linux/perf_event.h       | 35 +++++++++++++++++----------
>  tools/include/uapi/linux/perf_event.h | 35 +++++++++++++++++----------
>  2 files changed, 44 insertions(+), 26 deletions(-)
> 
> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> index d37629dbad72..6826dabb7e03 100644
> --- a/include/uapi/linux/perf_event.h
> +++ b/include/uapi/linux/perf_event.h
> @@ -538,9 +538,13 @@ struct perf_event_mmap_page {
>  	 *
>  	 *     if (pc->cap_usr_time && enabled != running) {
>  	 *       cyc = rdtsc();
> -	 *       time_offset = pc->time_offset;
>  	 *       time_mult   = pc->time_mult;
>  	 *       time_shift  = pc->time_shift;
> +	 *       time_offset = pc->time_offset;
> +	 *       if (pc->cap_user_time_short) {
> +	 *         time_cycles = pc->time_cycles;
> +	 *         time_mask = pc->time_mask;
> +	 *       }

From what I've been told, and from what perf_mmap__read_self() actually 
does, many of these MMAP fields need to be accessed by READ_ONCE()
(a GPLv2 only interface) to be correct.

Should we update perf_event.h to reflect this?  Otherwise it's confusing 
when the actual code and the documentation in the header don't match like 
this.  As an example, see the actual code snippets from
perf_mmap__read_self()

		seq = READ_ONCE(pc->lock);
                barrier();

                count->ena = READ_ONCE(pc->time_enabled);
                count->run = READ_ONCE(pc->time_running);

                if (pc->cap_user_time && count->ena != count->run) {
                        cyc = read_timestamp();
                        time_mult = READ_ONCE(pc->time_mult);
                        time_shift = READ_ONCE(pc->time_shift);
                        time_offset = READ_ONCE(pc->time_offset);

                        if (pc->cap_user_time_short) {
                                time_cycles = READ_ONCE(pc->time_cycles);
                                time_mask = READ_ONCE(pc->time_mask);
                        }
                }

                idx = READ_ONCE(pc->index);
                cnt = READ_ONCE(pc->offset);

...


Vince

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

* Re: [PATCH v3 3/3] perf test: Add user space counter reading tests
  2022-07-20 14:57   ` Vince Weaver
@ 2022-07-20 15:09     ` Ian Rogers
  0 siblings, 0 replies; 13+ messages in thread
From: Ian Rogers @ 2022-07-20 15:09 UTC (permalink / raw)
  To: Vince Weaver
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring, Stephane Eranian

On Wed, Jul 20, 2022 at 7:57 AM Vince Weaver <vincent.weaver@maine.edu> wrote:
>
> On Tue, 19 Jul 2022, Ian Rogers wrote:
>
> > These tests are based on test_stat_user_read in
> > tools/lib/perf/tests/test-evsel.c. The tests are modified to skip if
> > perf_event_open fails or rdpmc isn't supported.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
>
> > +             .type   = PERF_TYPE_HARDWARE,
> > +             .config = event,
> > +#ifdef __aarch64__
> > +             .config1 = 0x2,         /* Request user access */
> > +#endif
>
> should this value have a name rather than being a "magic constant"?

Thanks! Firstly, this is just moving code around and so not a
regression introduced by this code:
https://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git/tree/tools/lib/perf/tests/test-evsel.c?h=perf/core#n134
I don't believe there is an existing constant for this purpose. The
kernel isn't using one either:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/kernel/perf_event.c#n309

So I agree with you and hopefully this is something ARM will clean up.

Thanks,
Ian

> Vince

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

* Re: [PATCH v3 1/3] perf: Align user space counter reading with code
  2022-07-20 15:06   ` Vince Weaver
@ 2022-07-20 15:18     ` Ian Rogers
  2022-08-04  8:49     ` Ingo Molnar
  1 sibling, 0 replies; 13+ messages in thread
From: Ian Rogers @ 2022-07-20 15:18 UTC (permalink / raw)
  To: Vince Weaver
  Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Mark Rutland, Alexander Shishkin, Jiri Olsa, Namhyung Kim,
	Kajol Jain, Andi Kleen, Adrian Hunter, Anshuman Khandual,
	linux-kernel, linux-perf-users, Rob Herring, Stephane Eranian

On Wed, Jul 20, 2022 at 8:06 AM Vince Weaver <vincent.weaver@maine.edu> wrote:
>
> On Tue, 19 Jul 2022, Ian Rogers wrote:
>
> > Align the user space counter reading documentation with the code in
> > perf_mmap__read_self. Previously the documentation was based on the perf
> > rdpmc test, but now general purpose code is provided by libperf.
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >  include/uapi/linux/perf_event.h       | 35 +++++++++++++++++----------
> >  tools/include/uapi/linux/perf_event.h | 35 +++++++++++++++++----------
> >  2 files changed, 44 insertions(+), 26 deletions(-)
> >
> > diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> > index d37629dbad72..6826dabb7e03 100644
> > --- a/include/uapi/linux/perf_event.h
> > +++ b/include/uapi/linux/perf_event.h
> > @@ -538,9 +538,13 @@ struct perf_event_mmap_page {
> >        *
> >        *     if (pc->cap_usr_time && enabled != running) {
> >        *       cyc = rdtsc();
> > -      *       time_offset = pc->time_offset;
> >        *       time_mult   = pc->time_mult;
> >        *       time_shift  = pc->time_shift;
> > +      *       time_offset = pc->time_offset;
> > +      *       if (pc->cap_user_time_short) {
> > +      *         time_cycles = pc->time_cycles;
> > +      *         time_mask = pc->time_mask;
> > +      *       }
>
> From what I've been told, and from what perf_mmap__read_self() actually
> does, many of these MMAP fields need to be accessed by READ_ONCE()
> (a GPLv2 only interface) to be correct.
>
> Should we update perf_event.h to reflect this?  Otherwise it's confusing
> when the actual code and the documentation in the header don't match like
> this.  As an example, see the actual code snippets from
> perf_mmap__read_self()
>
>                 seq = READ_ONCE(pc->lock);
>                 barrier();
>
>                 count->ena = READ_ONCE(pc->time_enabled);
>                 count->run = READ_ONCE(pc->time_running);
>
>                 if (pc->cap_user_time && count->ena != count->run) {
>                         cyc = read_timestamp();
>                         time_mult = READ_ONCE(pc->time_mult);
>                         time_shift = READ_ONCE(pc->time_shift);
>                         time_offset = READ_ONCE(pc->time_offset);
>
>                         if (pc->cap_user_time_short) {
>                                 time_cycles = READ_ONCE(pc->time_cycles);
>                                 time_mask = READ_ONCE(pc->time_mask);
>                         }
>                 }
>
>                 idx = READ_ONCE(pc->index);
>                 cnt = READ_ONCE(pc->offset);
>
> ...

Thanks! So I think what this patch proposes is an improvement,
specifically it aligns it better with the code and deals with the
divide by zero. I think what you're asking for makes sense but as you
point out READ_ONCE probably isn't the correct API for something
outside the kernel. Given the kernel is now C11:
https://lwn.net/Articles/885941/
This opens the possibility of using stdatomic.h, so perhaps we can
move these variables to more correct atomic types. So, I think we can
land this and worry about the atomic API in a follow up.

Thanks,
Ian

> Vince

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

* Re: [PATCH v3 1/3] perf: Align user space counter reading with code
  2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
  2022-07-19 23:05   ` Rob Herring
  2022-07-20 15:06   ` Vince Weaver
@ 2022-08-01 12:17   ` Arnaldo Carvalho de Melo
  2 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-01 12:17 UTC (permalink / raw)
  To: Peter Zijlstra, Ian Rogers
  Cc: Ingo Molnar, Mark Rutland, Alexander Shishkin, Jiri Olsa,
	Namhyung Kim, Kajol Jain, Andi Kleen, Adrian Hunter,
	Anshuman Khandual, linux-kernel, linux-perf-users, Rob Herring,
	Stephane Eranian

Em Tue, Jul 19, 2022 at 03:39:44PM -0700, Ian Rogers escreveu:
> Align the user space counter reading documentation with the code in
> perf_mmap__read_self. Previously the documentation was based on the perf
> rdpmc test, but now general purpose code is provided by libperf.

Peter, can you merge this so as not to make Linus raise eyebrows with me
processing things outside tools/perf/ when asking him to pull perf
userspace?

- Arnaldo
 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  include/uapi/linux/perf_event.h       | 35 +++++++++++++++++----------
>  tools/include/uapi/linux/perf_event.h | 35 +++++++++++++++++----------
>  2 files changed, 44 insertions(+), 26 deletions(-)
> 
> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> index d37629dbad72..6826dabb7e03 100644
> --- a/include/uapi/linux/perf_event.h
> +++ b/include/uapi/linux/perf_event.h
> @@ -538,9 +538,13 @@ struct perf_event_mmap_page {
>  	 *
>  	 *     if (pc->cap_usr_time && enabled != running) {
>  	 *       cyc = rdtsc();
> -	 *       time_offset = pc->time_offset;
>  	 *       time_mult   = pc->time_mult;
>  	 *       time_shift  = pc->time_shift;
> +	 *       time_offset = pc->time_offset;
> +	 *       if (pc->cap_user_time_short) {
> +	 *         time_cycles = pc->time_cycles;
> +	 *         time_mask = pc->time_mask;
> +	 *       }
>  	 *     }
>  	 *
>  	 *     index = pc->index;
> @@ -548,6 +552,9 @@ struct perf_event_mmap_page {
>  	 *     if (pc->cap_user_rdpmc && index) {
>  	 *       width = pc->pmc_width;
>  	 *       pmc = rdpmc(index - 1);
> +	 *       pmc <<= 64 - width;
> +	 *       pmc >>= 64 - width;
> +	 *       count += pmc;
>  	 *     }
>  	 *
>  	 *     barrier();
> @@ -590,25 +597,27 @@ struct perf_event_mmap_page {
>  	 * If cap_usr_time the below fields can be used to compute the time
>  	 * delta since time_enabled (in ns) using rdtsc or similar.
>  	 *
> -	 *   u64 quot, rem;
> -	 *   u64 delta;
> -	 *
> -	 *   quot = (cyc >> time_shift);
> -	 *   rem = cyc & (((u64)1 << time_shift) - 1);
> -	 *   delta = time_offset + quot * time_mult +
> -	 *              ((rem * time_mult) >> time_shift);
> +	 *   cyc = time_cycles + ((cyc - time_cycles) & time_mask);
> +	 *   delta = time_offset + mul_u64_u32_shr(cyc, time_mult, time_shift);
>  	 *
>  	 * Where time_offset,time_mult,time_shift and cyc are read in the
> -	 * seqcount loop described above. This delta can then be added to
> -	 * enabled and possible running (if index), improving the scaling:
> +	 * seqcount loop described above. mul_u64_u32_shr will compute:
> +	 *
> +	 *   (u64)(((unsigned __int128)cyc * time_mult) >> time_shift)
> +	 *
> +	 * This delta can then be added to enabled and possible running (if
> +	 * index) to improve the scaling. Due to event multiplexing, running
> +	 * may be zero and so care is needed to avoid division by zero.
>  	 *
>  	 *   enabled += delta;
>  	 *   if (index)
>  	 *     running += delta;
>  	 *
> -	 *   quot = count / running;
> -	 *   rem  = count % running;
> -	 *   count = quot * enabled + (rem * enabled) / running;
> +	 *   if (running != 0) {
> +	 *     quot = count / running;
> +	 *     rem  = count % running;
> +	 *     count = quot * enabled + (rem * enabled) / running;
> +	 *   }
>  	 */
>  	__u16	time_shift;
>  	__u32	time_mult;
> diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
> index d37629dbad72..6826dabb7e03 100644
> --- a/tools/include/uapi/linux/perf_event.h
> +++ b/tools/include/uapi/linux/perf_event.h
> @@ -538,9 +538,13 @@ struct perf_event_mmap_page {
>  	 *
>  	 *     if (pc->cap_usr_time && enabled != running) {
>  	 *       cyc = rdtsc();
> -	 *       time_offset = pc->time_offset;
>  	 *       time_mult   = pc->time_mult;
>  	 *       time_shift  = pc->time_shift;
> +	 *       time_offset = pc->time_offset;
> +	 *       if (pc->cap_user_time_short) {
> +	 *         time_cycles = pc->time_cycles;
> +	 *         time_mask = pc->time_mask;
> +	 *       }
>  	 *     }
>  	 *
>  	 *     index = pc->index;
> @@ -548,6 +552,9 @@ struct perf_event_mmap_page {
>  	 *     if (pc->cap_user_rdpmc && index) {
>  	 *       width = pc->pmc_width;
>  	 *       pmc = rdpmc(index - 1);
> +	 *       pmc <<= 64 - width;
> +	 *       pmc >>= 64 - width;
> +	 *       count += pmc;
>  	 *     }
>  	 *
>  	 *     barrier();
> @@ -590,25 +597,27 @@ struct perf_event_mmap_page {
>  	 * If cap_usr_time the below fields can be used to compute the time
>  	 * delta since time_enabled (in ns) using rdtsc or similar.
>  	 *
> -	 *   u64 quot, rem;
> -	 *   u64 delta;
> -	 *
> -	 *   quot = (cyc >> time_shift);
> -	 *   rem = cyc & (((u64)1 << time_shift) - 1);
> -	 *   delta = time_offset + quot * time_mult +
> -	 *              ((rem * time_mult) >> time_shift);
> +	 *   cyc = time_cycles + ((cyc - time_cycles) & time_mask);
> +	 *   delta = time_offset + mul_u64_u32_shr(cyc, time_mult, time_shift);
>  	 *
>  	 * Where time_offset,time_mult,time_shift and cyc are read in the
> -	 * seqcount loop described above. This delta can then be added to
> -	 * enabled and possible running (if index), improving the scaling:
> +	 * seqcount loop described above. mul_u64_u32_shr will compute:
> +	 *
> +	 *   (u64)(((unsigned __int128)cyc * time_mult) >> time_shift)
> +	 *
> +	 * This delta can then be added to enabled and possible running (if
> +	 * index) to improve the scaling. Due to event multiplexing, running
> +	 * may be zero and so care is needed to avoid division by zero.
>  	 *
>  	 *   enabled += delta;
>  	 *   if (index)
>  	 *     running += delta;
>  	 *
> -	 *   quot = count / running;
> -	 *   rem  = count % running;
> -	 *   count = quot * enabled + (rem * enabled) / running;
> +	 *   if (running != 0) {
> +	 *     quot = count / running;
> +	 *     rem  = count % running;
> +	 *     count = quot * enabled + (rem * enabled) / running;
> +	 *   }
>  	 */
>  	__u16	time_shift;
>  	__u32	time_mult;
> -- 
> 2.37.0.170.g444d1eabd0-goog

-- 

- Arnaldo

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

* Re: [PATCH v3 2/3] perf test: Remove x86 rdpmc test
  2022-07-19 22:39 ` [PATCH v3 2/3] perf test: Remove x86 rdpmc test Ian Rogers
@ 2022-08-01 12:19   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-01 12:19 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Kajol Jain, Andi Kleen, Adrian Hunter,
	Anshuman Khandual, linux-kernel, linux-perf-users, Rob Herring,
	Stephane Eranian

Em Tue, Jul 19, 2022 at 03:39:45PM -0700, Ian Rogers escreveu:
> This test has been superseded by test_stat_user_read in:
> tools/lib/perf/tests/test-evsel.c
> The updated test doesn't divide-by-0 when running time of a counter is
> 0. It also supports ARM64.

Thanks, applied.

- Arnaldo

 
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/arch/x86/tests/Build        |   1 -
>  tools/perf/arch/x86/tests/arch-tests.c |   2 -
>  tools/perf/arch/x86/tests/rdpmc.c      | 182 -------------------------
>  3 files changed, 185 deletions(-)
>  delete mode 100644 tools/perf/arch/x86/tests/rdpmc.c
> 
> diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build
> index 28d793390198..70b5bcbc15df 100644
> --- a/tools/perf/arch/x86/tests/Build
> +++ b/tools/perf/arch/x86/tests/Build
> @@ -2,7 +2,6 @@ perf-$(CONFIG_DWARF_UNWIND) += regs_load.o
>  perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
>  
>  perf-y += arch-tests.o
> -perf-y += rdpmc.o
>  perf-y += sample-parsing.o
>  perf-$(CONFIG_AUXTRACE) += insn-x86.o intel-pt-pkt-decoder-test.o
>  perf-$(CONFIG_X86_64) += bp-modify.o
> diff --git a/tools/perf/arch/x86/tests/arch-tests.c b/tools/perf/arch/x86/tests/arch-tests.c
> index 64fb73d14d2f..04018b8aa85b 100644
> --- a/tools/perf/arch/x86/tests/arch-tests.c
> +++ b/tools/perf/arch/x86/tests/arch-tests.c
> @@ -3,7 +3,6 @@
>  #include "tests/tests.h"
>  #include "arch-tests.h"
>  
> -DEFINE_SUITE("x86 rdpmc", rdpmc);
>  #ifdef HAVE_AUXTRACE_SUPPORT
>  DEFINE_SUITE("x86 instruction decoder - new instructions", insn_x86);
>  DEFINE_SUITE("Intel PT packet decoder", intel_pt_pkt_decoder);
> @@ -14,7 +13,6 @@ DEFINE_SUITE("x86 bp modify", bp_modify);
>  DEFINE_SUITE("x86 Sample parsing", x86_sample_parsing);
>  
>  struct test_suite *arch_tests[] = {
> -	&suite__rdpmc,
>  #ifdef HAVE_DWARF_UNWIND_SUPPORT
>  	&suite__dwarf_unwind,
>  #endif
> diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
> deleted file mode 100644
> index 498413ad9c97..000000000000
> --- a/tools/perf/arch/x86/tests/rdpmc.c
> +++ /dev/null
> @@ -1,182 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0
> -#include <errno.h>
> -#include <unistd.h>
> -#include <stdlib.h>
> -#include <signal.h>
> -#include <sys/mman.h>
> -#include <sys/types.h>
> -#include <sys/wait.h>
> -#include <linux/string.h>
> -#include <linux/types.h>
> -#include "perf-sys.h"
> -#include "debug.h"
> -#include "tests/tests.h"
> -#include "cloexec.h"
> -#include "event.h"
> -#include <internal/lib.h> // page_size
> -#include "arch-tests.h"
> -
> -static u64 rdpmc(unsigned int counter)
> -{
> -	unsigned int low, high;
> -
> -	asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
> -
> -	return low | ((u64)high) << 32;
> -}
> -
> -static u64 rdtsc(void)
> -{
> -	unsigned int low, high;
> -
> -	asm volatile("rdtsc" : "=a" (low), "=d" (high));
> -
> -	return low | ((u64)high) << 32;
> -}
> -
> -static u64 mmap_read_self(void *addr)
> -{
> -	struct perf_event_mmap_page *pc = addr;
> -	u32 seq, idx, time_mult = 0, time_shift = 0;
> -	u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
> -
> -	do {
> -		seq = pc->lock;
> -		barrier();
> -
> -		enabled = pc->time_enabled;
> -		running = pc->time_running;
> -
> -		if (enabled != running) {
> -			cyc = rdtsc();
> -			time_mult = pc->time_mult;
> -			time_shift = pc->time_shift;
> -			time_offset = pc->time_offset;
> -		}
> -
> -		idx = pc->index;
> -		count = pc->offset;
> -		if (idx)
> -			count += rdpmc(idx - 1);
> -
> -		barrier();
> -	} while (pc->lock != seq);
> -
> -	if (enabled != running) {
> -		u64 quot, rem;
> -
> -		quot = (cyc >> time_shift);
> -		rem = cyc & (((u64)1 << time_shift) - 1);
> -		delta = time_offset + quot * time_mult +
> -			((rem * time_mult) >> time_shift);
> -
> -		enabled += delta;
> -		if (idx)
> -			running += delta;
> -
> -		quot = count / running;
> -		rem = count % running;
> -		count = quot * enabled + (rem * enabled) / running;
> -	}
> -
> -	return count;
> -}
> -
> -/*
> - * If the RDPMC instruction faults then signal this back to the test parent task:
> - */
> -static void segfault_handler(int sig __maybe_unused,
> -			     siginfo_t *info __maybe_unused,
> -			     void *uc __maybe_unused)
> -{
> -	exit(-1);
> -}
> -
> -static int __test__rdpmc(void)
> -{
> -	volatile int tmp = 0;
> -	u64 i, loops = 1000;
> -	int n;
> -	int fd;
> -	void *addr;
> -	struct perf_event_attr attr = {
> -		.type = PERF_TYPE_HARDWARE,
> -		.config = PERF_COUNT_HW_INSTRUCTIONS,
> -		.exclude_kernel = 1,
> -	};
> -	u64 delta_sum = 0;
> -        struct sigaction sa;
> -	char sbuf[STRERR_BUFSIZE];
> -
> -	sigfillset(&sa.sa_mask);
> -	sa.sa_sigaction = segfault_handler;
> -	sa.sa_flags = 0;
> -	sigaction(SIGSEGV, &sa, NULL);
> -
> -	fd = sys_perf_event_open(&attr, 0, -1, -1,
> -				 perf_event_open_cloexec_flag());
> -	if (fd < 0) {
> -		pr_err("Error: sys_perf_event_open() syscall returned "
> -		       "with %d (%s)\n", fd,
> -		       str_error_r(errno, sbuf, sizeof(sbuf)));
> -		return -1;
> -	}
> -
> -	addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
> -	if (addr == (void *)(-1)) {
> -		pr_err("Error: mmap() syscall returned with (%s)\n",
> -		       str_error_r(errno, sbuf, sizeof(sbuf)));
> -		goto out_close;
> -	}
> -
> -	for (n = 0; n < 6; n++) {
> -		u64 stamp, now, delta;
> -
> -		stamp = mmap_read_self(addr);
> -
> -		for (i = 0; i < loops; i++)
> -			tmp++;
> -
> -		now = mmap_read_self(addr);
> -		loops *= 10;
> -
> -		delta = now - stamp;
> -		pr_debug("%14d: %14Lu\n", n, (long long)delta);
> -
> -		delta_sum += delta;
> -	}
> -
> -	munmap(addr, page_size);
> -	pr_debug("   ");
> -out_close:
> -	close(fd);
> -
> -	if (!delta_sum)
> -		return -1;
> -
> -	return 0;
> -}
> -
> -int test__rdpmc(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
> -{
> -	int status = 0;
> -	int wret = 0;
> -	int ret;
> -	int pid;
> -
> -	pid = fork();
> -	if (pid < 0)
> -		return -1;
> -
> -	if (!pid) {
> -		ret = __test__rdpmc();
> -
> -		exit(ret);
> -	}
> -
> -	wret = waitpid(pid, &status, 0);
> -	if (wret < 0 || status)
> -		return -1;
> -
> -	return 0;
> -}
> -- 
> 2.37.0.170.g444d1eabd0-goog

-- 

- Arnaldo

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

* Re: [PATCH v3 3/3] perf test: Add user space counter reading tests
  2022-07-19 22:39 ` [PATCH v3 3/3] perf test: Add user space counter reading tests Ian Rogers
  2022-07-20 14:57   ` Vince Weaver
@ 2022-08-01 12:23   ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 13+ messages in thread
From: Arnaldo Carvalho de Melo @ 2022-08-01 12:23 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Kajol Jain, Andi Kleen, Adrian Hunter,
	Anshuman Khandual, linux-kernel, linux-perf-users, Rob Herring,
	Stephane Eranian

Em Tue, Jul 19, 2022 at 03:39:46PM -0700, Ian Rogers escreveu:
> These tests are based on test_stat_user_read in
> tools/lib/perf/tests/test-evsel.c. The tests are modified to skip if
> perf_event_open fails or rdpmc isn't supported.

Thanks, tested and applied.

- Arnaldo

 
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/tests/mmap-basic.c | 127 +++++++++++++++++++++++++++++++++-
>  1 file changed, 126 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
> index 30bbe144648a..dfb6173b2a82 100644
> --- a/tools/perf/tests/mmap-basic.c
> +++ b/tools/perf/tests/mmap-basic.c
> @@ -170,14 +170,139 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest
>  	return err;
>  }
>  
> +static int test_stat_user_read(int event)
> +{
> +	struct perf_counts_values counts = { .val = 0 };
> +	struct perf_thread_map *threads;
> +	struct perf_evsel *evsel;
> +	struct perf_event_mmap_page *pc;
> +	struct perf_event_attr attr = {
> +		.type	= PERF_TYPE_HARDWARE,
> +		.config	= event,
> +#ifdef __aarch64__
> +		.config1 = 0x2,		/* Request user access */
> +#endif
> +	};
> +	int err, i, ret = TEST_FAIL;
> +	bool opened = false, mapped = false;
> +
> +	threads = perf_thread_map__new_dummy();
> +	TEST_ASSERT_VAL("failed to create threads", threads);
> +
> +	perf_thread_map__set_pid(threads, 0, 0);
> +
> +	evsel = perf_evsel__new(&attr);
> +	TEST_ASSERT_VAL("failed to create evsel", evsel);
> +
> +	err = perf_evsel__open(evsel, NULL, threads);
> +	if (err) {
> +		pr_err("failed to open evsel: %s\n", strerror(-err));
> +		ret = TEST_SKIP;
> +		goto out;
> +	}
> +	opened = true;
> +
> +	err = perf_evsel__mmap(evsel, 0);
> +	if (err) {
> +		pr_err("failed to mmap evsel: %s\n", strerror(-err));
> +		goto out;
> +	}
> +	mapped = true;
> +
> +	pc = perf_evsel__mmap_base(evsel, 0, 0);
> +	if (!pc) {
> +		pr_err("failed to get mmapped address\n");
> +		goto out;
> +	}
> +
> +	if (!pc->cap_user_rdpmc || !pc->index) {
> +		pr_err("userspace counter access not %s\n",
> +			!pc->cap_user_rdpmc ? "supported" : "enabled");
> +		ret = TEST_SKIP;
> +		goto out;
> +	}
> +	if (pc->pmc_width < 32) {
> +		pr_err("userspace counter width not set (%d)\n", pc->pmc_width);
> +		goto out;
> +	}
> +
> +	perf_evsel__read(evsel, 0, 0, &counts);
> +	if (counts.val == 0) {
> +		pr_err("failed to read value for evsel\n");
> +		goto out;
> +	}
> +
> +	for (i = 0; i < 5; i++) {
> +		volatile int count = 0x10000 << i;
> +		__u64 start, end, last = 0;
> +
> +		pr_debug("\tloop = %u, ", count);
> +
> +		perf_evsel__read(evsel, 0, 0, &counts);
> +		start = counts.val;
> +
> +		while (count--) ;
> +
> +		perf_evsel__read(evsel, 0, 0, &counts);
> +		end = counts.val;
> +
> +		if ((end - start) < last) {
> +			pr_err("invalid counter data: end=%llu start=%llu last= %llu\n",
> +				end, start, last);
> +			goto out;
> +		}
> +		last = end - start;
> +		pr_debug("count = %llu\n", end - start);
> +	}
> +	ret = TEST_OK;
> +
> +out:
> +	if (mapped)
> +		perf_evsel__munmap(evsel);
> +	if (opened)
> +		perf_evsel__close(evsel);
> +	perf_evsel__delete(evsel);
> +
> +	perf_thread_map__put(threads);
> +	return ret;
> +}
> +
> +static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,
> +				      int subtest __maybe_unused)
> +{
> +	return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);
> +}
> +
> +static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,
> +				       int subtest __maybe_unused)
> +{
> +	return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);
> +}
> +
>  static struct test_case tests__basic_mmap[] = {
>  	TEST_CASE_REASON("Read samples using the mmap interface",
>  			 basic_mmap,
>  			 "permissions"),
> +	TEST_CASE_REASON("User space counter reading of instructions",
> +			 mmap_user_read_instr,
> +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
> +			 "permissions"
> +#else
> +			 "unsupported"
> +#endif
> +		),
> +	TEST_CASE_REASON("User space counter reading of cycles",
> +			 mmap_user_read_cycles,
> +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
> +			 "permissions"
> +#else
> +			 "unsupported"
> +#endif
> +		),
>  	{	.name = NULL, }
>  };
>  
>  struct test_suite suite__basic_mmap = {
> -	.desc = "Read samples using the mmap interface",
> +	.desc = "mmap interface tests",
>  	.test_cases = tests__basic_mmap,
>  };
> -- 
> 2.37.0.170.g444d1eabd0-goog

-- 

- Arnaldo

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

* Re: [PATCH v3 1/3] perf: Align user space counter reading with code
  2022-07-20 15:06   ` Vince Weaver
  2022-07-20 15:18     ` Ian Rogers
@ 2022-08-04  8:49     ` Ingo Molnar
  1 sibling, 0 replies; 13+ messages in thread
From: Ingo Molnar @ 2022-08-04  8:49 UTC (permalink / raw)
  To: Vince Weaver
  Cc: Ian Rogers, Peter Zijlstra, Ingo Molnar,
	Arnaldo Carvalho de Melo, Mark Rutland, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Kajol Jain, Andi Kleen, Adrian Hunter,
	Anshuman Khandual, linux-kernel, linux-perf-users, Rob Herring,
	Stephane Eranian


* Vince Weaver <vincent.weaver@maine.edu> wrote:

> On Tue, 19 Jul 2022, Ian Rogers wrote:
> 
> > Align the user space counter reading documentation with the code in
> > perf_mmap__read_self. Previously the documentation was based on the perf
> > rdpmc test, but now general purpose code is provided by libperf.
> > 
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >  include/uapi/linux/perf_event.h       | 35 +++++++++++++++++----------
> >  tools/include/uapi/linux/perf_event.h | 35 +++++++++++++++++----------
> >  2 files changed, 44 insertions(+), 26 deletions(-)
> > 
> > diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> > index d37629dbad72..6826dabb7e03 100644
> > --- a/include/uapi/linux/perf_event.h
> > +++ b/include/uapi/linux/perf_event.h
> > @@ -538,9 +538,13 @@ struct perf_event_mmap_page {
> >  	 *
> >  	 *     if (pc->cap_usr_time && enabled != running) {
> >  	 *       cyc = rdtsc();
> > -	 *       time_offset = pc->time_offset;
> >  	 *       time_mult   = pc->time_mult;
> >  	 *       time_shift  = pc->time_shift;
> > +	 *       time_offset = pc->time_offset;
> > +	 *       if (pc->cap_user_time_short) {
> > +	 *         time_cycles = pc->time_cycles;
> > +	 *         time_mask = pc->time_mask;
> > +	 *       }
> 
> From what I've been told, and from what perf_mmap__read_self() actually 
> does, many of these MMAP fields need to be accessed by READ_ONCE()
> (a GPLv2 only interface) to be correct.

BTW., for this purpose I guess we could add a READ_ONCE() variant to perf 
tooling that reimplements it with more relaxed licensing, so that the 
headers & sample code can be included in GPL-incompatible projects?

READ_ONCE() isn't a super complicated primitive, and we've always been 
permissive with simple primitives.

Thanks,

	Ingo

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

end of thread, other threads:[~2022-08-04  8:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-19 22:39 [PATCH v3 0/3] Tidy user rdpmc documentation and testing Ian Rogers
2022-07-19 22:39 ` [PATCH v3 1/3] perf: Align user space counter reading with code Ian Rogers
2022-07-19 23:05   ` Rob Herring
2022-07-20 15:06   ` Vince Weaver
2022-07-20 15:18     ` Ian Rogers
2022-08-04  8:49     ` Ingo Molnar
2022-08-01 12:17   ` Arnaldo Carvalho de Melo
2022-07-19 22:39 ` [PATCH v3 2/3] perf test: Remove x86 rdpmc test Ian Rogers
2022-08-01 12:19   ` Arnaldo Carvalho de Melo
2022-07-19 22:39 ` [PATCH v3 3/3] perf test: Add user space counter reading tests Ian Rogers
2022-07-20 14:57   ` Vince Weaver
2022-07-20 15:09     ` Ian Rogers
2022-08-01 12:23   ` Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.