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