All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Zijlstra <peterz@infradead.org>
To: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Jiri Olsa <jolsa@redhat.com>, Namhyung Kim <namhyung@kernel.org>,
	Andi Kleen <ak@linux.intel.com>,
	Kan Liang <kan.liang@linux.intel.com>,
	linux-kernel@vger.kernel.org,
	Stephane Eranian <eranian@google.com>
Subject: Re: [PATCH v2] perf test x86: address multiplexing in rdpmc test
Date: Sun, 22 Mar 2020 11:18:48 +0100	[thread overview]
Message-ID: <20200322101848.GF2452@worktop.programming.kicks-ass.net> (raw)
In-Reply-To: <20200321173710.127770-1-irogers@google.com>

On Sat, Mar 21, 2020 at 10:37:10AM -0700, Ian Rogers wrote:

> +static u64 mmap_read_self(void *addr, u64 *running)
>  {
>  	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;
> +	u64 count, cyc = 0, time_offset = 0, enabled, delta;
>  
>  	do {
>  		seq = pc->lock;
>  		barrier();
>  
>  		enabled = pc->time_enabled;
> -		running = pc->time_running;
> -
> -		if (enabled != running) {
> +		*running = pc->time_running;
> +
> +		if (*running == 0) {
> +			/*
> +			 * Counter won't have a value as due to multiplexing the
> +			 * event wasn't scheduled.
> +			 */
> +			return 0;
> +		}

I still think adding code for an error case here is a bad idea. And only
passing running as an argument is inconsistent.

Also, then I had a look at what the compiler made of that function and
cried.

Here's something a little better. Much of it copied from linux/math64.h
and asm/div64.h.

---
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
index 1ea916656a2d..386a6dacb21e 100644
--- a/tools/perf/arch/x86/tests/rdpmc.c
+++ b/tools/perf/arch/x86/tests/rdpmc.c
@@ -34,20 +34,98 @@ static u64 rdtsc(void)
 	return low | ((u64)high) << 32;
 }

-static u64 mmap_read_self(void *addr)
+#ifdef __x86_64__
+static inline u64 mul_u64_u64_div64(u64 a, u64 b, u64 c)
+{
+	u64 q;
+
+	asm ("mulq %2; divq %3" : "=a" (q)
+				: "a" (a), "rm" (b), "rm" (c)
+				: "rdx");
+
+	return q;
+}
+#define mul_u64_u64_div64 mul_u64_u64_div64
+#endif
+
+#ifdef __SIZEOF_INT128__
+
+static inline u64 mul_u64_u32_shr(u64 a, u32 b, unsigned int shift)
+{
+	return (u64)(((unsigned __int128)a * b) >> shift);
+}
+
+#ifndef mul_u64_u64_div64
+static inline u64 mul_u64_u64_div64(u64 a, u64 b, u64 c)
+{
+	unsigned __int128 m = a;
+	m *= b;
+	return m / c;
+}
+#endif
+
+#else
+
+#ifdef __i386__
+static inline u64 mul_u32_u32(u32 a, u32 b)
+{
+	u32 high, low;
+
+	asm ("mull %[b]" : "=a" (low), "=d" (high)
+			 : [a] "a" (a), [b] "rm" (b) );
+
+	return low | ((u64)high) << 32;
+}
+#else
+static inline u64 mul_u32_u32(u32 a, u32 b)
+{
+	return (u64)a * b;
+}
+#endif
+
+static inline u64 mul_u64_u32_shr(u64 a, u32 b, unsigned int shift)
+{
+	u32 ah, al;
+	u64 ret;
+
+	al = a;
+	ah = a >> 32;
+
+	ret = mul_u32_u32(al, mul) >> shift;
+	if (ah)
+		ret += mul_u32_u32(ah, mul) << (32 - shift);
+
+	return ret;
+}
+
+#ifndef mul_u64_u64_div64
+static inline u64 mul_u64_u64_div64(u64 a, u64 b, u64 c)
+{
+	u64 quot, rem;
+
+	quot = a / c;
+	rem = a % c;
+
+	return qout * b + (rem * b) / c;
+}
+#endif
+
+#endif
+
+static u64 mmap_read_self(void *addr, u64 *enabled, u64 *running)
 {
 	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;
+	u64 count, cyc = 0, time_offset = 0;

 	do {
 		seq = pc->lock;
 		barrier();

-		enabled = pc->time_enabled;
-		running = pc->time_running;
+		*enabled = pc->time_enabled;
+		*running = pc->time_running;

-		if (enabled != running) {
+		if (*enabled != *running) {
 			cyc = rdtsc();
 			time_mult = pc->time_mult;
 			time_shift = pc->time_shift;
@@ -62,21 +140,13 @@ static u64 mmap_read_self(void *addr)
 		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 (*enabled != *running) {
+		u64 delta = time_offset + mul_u64_u32_shr(cyc, time_mult, time_shift);
+		*enabled += delta;
 		if (idx)
-			running += delta;
+			*running += delta;

-		quot = count / running;
-		rem = count % running;
-		count = quot * enabled + (rem * enabled) / running;
+		count = mul_u64_u64_div64(count, *enabled, *running);
 	}

 	return count;
@@ -130,14 +200,18 @@ static int __test__rdpmc(void)
 	}

 	for (n = 0; n < 6; n++) {
-		u64 stamp, now, delta;
+		u64 stamp, now, delta, enabled, running;

-		stamp = mmap_read_self(addr);
+		stamp = mmap_read_self(addr, &enabled, &running);

 		for (i = 0; i < loops; i++)
 			tmp++;

-		now = mmap_read_self(addr);
+		now = mmap_read_self(addr, &enabled, &running);
+
+		if (enabled && !running)
+			goto out_error;
+
 		loops *= 10;

 		delta = now - stamp;
@@ -155,6 +229,11 @@ static int __test__rdpmc(void)
 		return -1;

 	return 0;
+
+out_error:
+	close(fd);
+	pr_err("counter never ran; you loose\n");
+	return -1;
 }

 int test__rdpmc(struct test *test __maybe_unused, int subtest __maybe_unused)


  reply	other threads:[~2020-03-22 10:19 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-21 17:37 [PATCH v2] perf test x86: address multiplexing in rdpmc test Ian Rogers
2020-03-22 10:18 ` Peter Zijlstra [this message]
2020-03-22 23:18   ` Andi Kleen
2020-03-23 12:29     ` Peter Zijlstra
2020-03-23  0:14   ` Ian Rogers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200322101848.GF2452@worktop.programming.kicks-ass.net \
    --to=peterz@infradead.org \
    --cc=acme@kernel.org \
    --cc=ak@linux.intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=eranian@google.com \
    --cc=irogers@google.com \
    --cc=jolsa@redhat.com \
    --cc=kan.liang@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.