All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Gray <bgray@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: Benjamin Gray <bgray@linux.ibm.com>
Subject: [PATCH v2 5/7] selftests/powerpc/dscr: Improve DSCR explicit random test case
Date: Thu,  6 Apr 2023 14:33:18 +1000	[thread overview]
Message-ID: <20230406043320.125138-6-bgray@linux.ibm.com> (raw)
In-Reply-To: <20230406043320.125138-1-bgray@linux.ibm.com>

The tests currently have a single writer thread updating the system
DSCR with a 1/1000 chance looped only 100 times. So only around one in
10 runs actually do anything.

* Add multiple threads to the dscr_explicit_random_test case.
* Use a barrier to make all the threads start work as simultaneously as
  possible.
* Use a rwlock and make all threads have a reasonable chance to write to
  the DSCR on each iteration.
  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is used to prevent
  writers from starving while all the other threads keep reading.
  Logging the reads/writes shows a decent mix across the whole test.
* Allow all threads a chance to write.
* Make the chance of writing more likely.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 tools/testing/selftests/powerpc/dscr/dscr.h   |   4 -
 .../powerpc/dscr/dscr_default_test.c          | 140 ++++++++----------
 .../powerpc/dscr/dscr_explicit_test.c         |  84 +++++++----
 3 files changed, 113 insertions(+), 115 deletions(-)

diff --git a/tools/testing/selftests/powerpc/dscr/dscr.h b/tools/testing/selftests/powerpc/dscr/dscr.h
index 2c54998d4715..b281659071e8 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr.h
+++ b/tools/testing/selftests/powerpc/dscr/dscr.h
@@ -86,8 +86,4 @@ void set_default_dscr(unsigned long val)
 	}
 }
 
-double uniform_deviate(int seed)
-{
-	return seed * (1.0 / (RAND_MAX + 1.0));
-}
 #endif	/* _SELFTESTS_POWERPC_DSCR_DSCR_H */
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_default_test.c b/tools/testing/selftests/powerpc/dscr/dscr_default_test.c
index 18e533d46c9a..60ab02525b79 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_default_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_default_test.c
@@ -69,105 +69,85 @@ int dscr_default_lockstep_test(void)
 	return 0;
 }
 
-static unsigned long dscr;		/* System DSCR default */
-static unsigned long sequence;
-static unsigned long result[THREADS];
-
-static void *do_test(void *in)
+struct random_thread_args {
+	pthread_t thread_id;
+	unsigned long *expected_system_dscr;
+	pthread_rwlock_t *rw_lock;
+	pthread_barrier_t *barrier;
+};
+
+static void *dscr_default_random_thread(void *in)
 {
-	unsigned long thread = (unsigned long)in;
-	unsigned long i;
-
-	for (i = 0; i < COUNT; i++) {
-		unsigned long d, cur_dscr, cur_dscr_usr;
-		unsigned long s1, s2;
-
-		s1 = READ_ONCE(sequence);
-		if (s1 & 1)
-			continue;
-		rmb();
-
-		d = dscr;
-		cur_dscr = get_dscr();
-		cur_dscr_usr = get_dscr_usr();
-
-		rmb();
-		s2 = sequence;
+	struct random_thread_args *args = (struct random_thread_args *)in;
+	unsigned long *expected_dscr_p = args->expected_system_dscr;
+	pthread_rwlock_t *rw_lock = args->rw_lock;
+	int err;
 
-		if (s1 != s2)
-			continue;
+	srand(gettid());
 
-		if (cur_dscr != d) {
-			fprintf(stderr, "thread %ld kernel DSCR should be %ld "
-				"but is %ld\n", thread, d, cur_dscr);
-			result[thread] = 1;
-			pthread_exit(&result[thread]);
-		}
+	err = pthread_barrier_wait(args->barrier);
+	FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
 
-		if (cur_dscr_usr != d) {
-			fprintf(stderr, "thread %ld user DSCR should be %ld "
-				"but is %ld\n", thread, d, cur_dscr_usr);
-			result[thread] = 1;
-			pthread_exit(&result[thread]);
+	for (int i = 0; i < COUNT; i++) {
+		unsigned long expected_dscr;
+		unsigned long current_dscr;
+		unsigned long current_dscr_usr;
+
+		FAIL_IF_EXIT(pthread_rwlock_rdlock(rw_lock));
+		expected_dscr = *expected_dscr_p;
+		current_dscr = get_dscr();
+		current_dscr_usr = get_dscr_usr();
+		FAIL_IF_EXIT(pthread_rwlock_unlock(rw_lock));
+
+		FAIL_IF_EXIT(current_dscr != expected_dscr);
+		FAIL_IF_EXIT(current_dscr_usr != expected_dscr);
+
+		if (rand() % 10 == 0) {
+			unsigned long next_dscr;
+
+			FAIL_IF_EXIT(pthread_rwlock_wrlock(rw_lock));
+			next_dscr = (*expected_dscr_p + 1) % DSCR_MAX;
+			set_default_dscr(next_dscr);
+			*expected_dscr_p = next_dscr;
+			FAIL_IF_EXIT(pthread_rwlock_unlock(rw_lock));
 		}
 	}
-	result[thread] = 0;
-	pthread_exit(&result[thread]);
+
+	pthread_exit((void *)0);
 }
 
 int dscr_default_random_test(void)
 {
-	pthread_t threads[THREADS];
-	unsigned long i, *status[THREADS];
+	struct random_thread_args threads[THREADS];
+	unsigned long expected_system_dscr = 0;
+	pthread_rwlockattr_t rwlock_attr;
+	pthread_rwlock_t rw_lock;
+	pthread_barrier_t barrier;
 
 	SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
 
-	/* Initial DSCR default */
-	dscr = 1;
-	set_default_dscr(dscr);
+	FAIL_IF(pthread_rwlockattr_setkind_np(&rwlock_attr,
+					      PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP));
+	FAIL_IF(pthread_rwlock_init(&rw_lock, &rwlock_attr));
+	FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS));
 
-	/* Spawn all testing threads */
-	for (i = 0; i < THREADS; i++) {
-		if (pthread_create(&threads[i], NULL, do_test, (void *)i)) {
-			perror("pthread_create() failed");
-			return 1;
-		}
-	}
+	set_default_dscr(expected_system_dscr);
 
-	srand(getpid());
+	for (int i = 0; i < THREADS; i++) {
+		threads[i].expected_system_dscr = &expected_system_dscr;
+		threads[i].rw_lock = &rw_lock;
+		threads[i].barrier = &barrier;
 
-	/* Keep changing the DSCR default */
-	for (i = 0; i < COUNT; i++) {
-		double ret = uniform_deviate(rand());
-
-		if (ret < 0.0001) {
-			sequence++;
-			wmb();
-
-			dscr++;
-			if (dscr > DSCR_MAX)
-				dscr = 0;
-
-			set_default_dscr(dscr);
-
-			wmb();
-			sequence++;
-		}
+		FAIL_IF(pthread_create(&threads[i].thread_id, NULL,
+				       dscr_default_random_thread, (void *)&threads[i]));
 	}
 
-	/* Individual testing thread exit status */
-	for (i = 0; i < THREADS; i++) {
-		if (pthread_join(threads[i], (void **)&(status[i]))) {
-			perror("pthread_join() failed");
-			return 1;
-		}
+	for (int i = 0; i < THREADS; i++)
+		FAIL_IF(pthread_join(threads[i].thread_id, NULL));
+
+	FAIL_IF(pthread_barrier_destroy(&barrier));
+	FAIL_IF(pthread_rwlock_destroy(&rw_lock));
 
-		if (*status[i]) {
-			printf("%ldth thread failed to join with %ld status\n",
-								i, *status[i]);
-			return 1;
-		}
-	}
 	return 0;
 }
 
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_explicit_test.c b/tools/testing/selftests/powerpc/dscr/dscr_explicit_test.c
index 3b98b9a88207..e2268e9183a8 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_explicit_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_explicit_test.c
@@ -86,50 +86,72 @@ int dscr_explicit_lockstep_test(void)
 	return 0;
 }
 
-int dscr_explicit_random_test(void)
+struct random_thread_args {
+	pthread_t thread_id;
+	bool do_yields;
+	pthread_barrier_t *barrier;
+};
+
+void *dscr_explicit_random_thread(void *in)
 {
-	unsigned long i, dscr = 0;
+	struct random_thread_args *args = (struct random_thread_args *)in;
+	unsigned long expected_dscr = 0;
+	int err;
 
-	SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+	srand(gettid());
 
-	srand(getpid());
-	set_dscr(dscr);
+	err = pthread_barrier_wait(args->barrier);
+	FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
 
-	for (i = 0; i < COUNT; i++) {
-		unsigned long cur_dscr, cur_dscr_usr;
-		double ret = uniform_deviate(rand());
+	for (int i = 0; i < COUNT; i++) {
+		expected_dscr = rand() % DSCR_MAX;
+		set_dscr(expected_dscr);
 
-		if (ret < 0.001) {
-			dscr++;
-			if (dscr > DSCR_MAX)
-				dscr = 0;
+		for (int j = rand() % 5; j > 0; --j) {
+			FAIL_IF_EXIT(get_dscr() != expected_dscr);
+			FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
 
-			set_dscr(dscr);
+			if (args->do_yields && rand() % 2)
+				sched_yield();
 		}
 
-		cur_dscr = get_dscr();
-		if (cur_dscr != dscr) {
-			fprintf(stderr, "Kernel DSCR should be %ld but "
-					"is %ld\n", dscr, cur_dscr);
-			return 1;
-		}
+		expected_dscr = rand() % DSCR_MAX;
+		set_dscr_usr(expected_dscr);
 
-		ret = uniform_deviate(rand());
-		if (ret < 0.001) {
-			dscr++;
-			if (dscr > DSCR_MAX)
-				dscr = 0;
+		for (int j = rand() % 5; j > 0; --j) {
+			FAIL_IF_EXIT(get_dscr() != expected_dscr);
+			FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
 
-			set_dscr_usr(dscr);
+			if (args->do_yields && rand() % 2)
+				sched_yield();
 		}
+	}
 
-		cur_dscr_usr = get_dscr_usr();
-		if (cur_dscr_usr != dscr) {
-			fprintf(stderr, "User DSCR should be %ld but "
-					"is %ld\n", dscr, cur_dscr_usr);
-			return 1;
-		}
+	return NULL;
+}
+
+int dscr_explicit_random_test(void)
+{
+	struct random_thread_args threads[THREADS];
+	pthread_barrier_t barrier;
+
+	SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
+
+	FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS));
+
+	for (int i = 0; i < THREADS; i++) {
+		threads[i].do_yields = i % 2 == 0;
+		threads[i].barrier = &barrier;
+
+		FAIL_IF(pthread_create(&threads[i].thread_id, NULL,
+				       dscr_explicit_random_thread, (void *)&threads[i]));
 	}
+
+	for (int i = 0; i < THREADS; i++)
+		FAIL_IF(pthread_join(threads[i].thread_id, NULL));
+
+	FAIL_IF(pthread_barrier_destroy(&barrier));
+
 	return 0;
 }
 
-- 
2.39.2


  parent reply	other threads:[~2023-04-06  4:39 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-06  4:33 [PATCH v2 0/7] Update DSCR tests Benjamin Gray
2023-04-06  4:33 ` [PATCH v2 1/7] selftests/powerpc/dscr: Correct typos Benjamin Gray
2023-04-06  4:33 ` [PATCH v2 2/7] selftests/powerpc: Move bind_to_cpu() to utils.h Benjamin Gray
2023-04-06  4:33 ` [PATCH v2 3/7] selftests/powerpc: Allow bind_to_cpu() to automatically pick CPU Benjamin Gray
2023-04-06  4:33 ` [PATCH v2 4/7] selftests/powerpc/dscr: Add lockstep test cases to DSCR explicit tests Benjamin Gray
2023-04-06  4:33 ` Benjamin Gray [this message]
2023-04-06  4:33 ` [PATCH v2 6/7] selftests/powerpc/dscr: Speed up DSCR sysfs tests Benjamin Gray
2023-04-06  4:33 ` [PATCH v2 7/7] selftests/powerpc/dscr: Restore timeout to DSCR selftests Benjamin Gray
2023-04-26 12:01 ` [PATCH v2 0/7] Update DSCR tests Michael Ellerman

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=20230406043320.125138-6-bgray@linux.ibm.com \
    --to=bgray@linux.ibm.com \
    --cc=linuxppc-dev@lists.ozlabs.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.