From: Benjamin Gray <bgray@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org
Cc: Benjamin Gray <bgray@linux.ibm.com>
Subject: [PATCH 3/5] selftests/powerpc/dscr: Improve DSCR explicit random test case
Date: Tue, 7 Mar 2023 11:55:13 +1100 [thread overview]
Message-ID: <20230307005515.174362-4-bgray@linux.ibm.com> (raw)
In-Reply-To: <20230307005515.174362-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 | 5 -
.../powerpc/dscr/dscr_default_test.c | 132 ++++++++----------
.../powerpc/dscr/dscr_explicit_test.c | 94 ++++++++-----
3 files changed, 114 insertions(+), 117 deletions(-)
diff --git a/tools/testing/selftests/powerpc/dscr/dscr.h b/tools/testing/selftests/powerpc/dscr/dscr.h
index 903ee0c83fac..9cd5488ab7c2 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr.h
+++ b/tools/testing/selftests/powerpc/dscr/dscr.h
@@ -88,11 +88,6 @@ void set_default_dscr(unsigned long val)
}
}
-double uniform_deviate(int seed)
-{
- return seed * (1.0 / (RAND_MAX + 1.0));
-}
-
int restrict_to_one_cpu(void)
{
cpu_set_t cpus;
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_default_test.c b/tools/testing/selftests/powerpc/dscr/dscr_default_test.c
index 8b7d0ff8a20a..758823d59daa 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];
+struct random_thread_args {
+ pthread_t thread_id;
+ unsigned long *expected_system_dscr;
+ pthread_rwlock_t *rw_lock;
+ pthread_barrier_t *barrier;
+};
-static void *do_test(void *in)
+static void *dscr_default_random_thread(void *in)
{
- unsigned long thread = (unsigned long)in;
- unsigned long i;
+ 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;
- for (i = 0; i < COUNT; i++) {
- unsigned long d, cur_dscr, cur_dscr_usr;
- unsigned long s1, s2;
+ srand(gettid());
- s1 = READ_ONCE(sequence);
- if (s1 & 1)
- continue;
- rmb();
+ err = pthread_barrier_wait(args->barrier);
+ FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
- d = dscr;
- cur_dscr = get_dscr();
- cur_dscr_usr = get_dscr_usr();
+ for (int i = 0; i < COUNT; i++) {
+ unsigned long expected_dscr;
+ unsigned long current_dscr;
+ unsigned long current_dscr_usr;
- rmb();
- s2 = sequence;
+ 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));
- if (s1 != s2)
- continue;
+ FAIL_IF_EXIT(current_dscr != expected_dscr);
+ FAIL_IF_EXIT(current_dscr_usr != expected_dscr);
- 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]);
- }
+ if (rand() % 10 == 0) {
+ unsigned long next_dscr;
- 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]);
+ 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);
+
+ 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;
+
+ FAIL_IF(pthread_create(&threads[i].thread_id, NULL,
+ dscr_default_random_thread, (void *)&threads[i]));
}
- srand(getpid());
+ for (int i = 0; i < THREADS; i++)
+ FAIL_IF(pthread_join(threads[i].thread_id, NULL));
- /* Keep changing the DSCR default */
- for (i = 0; i < COUNT; i++) {
- double ret = uniform_deviate(rand());
+ FAIL_IF(pthread_barrier_destroy(&barrier));
+ FAIL_IF(pthread_rwlock_destroy(&rw_lock));
- if (ret < 0.0001) {
- sequence++;
- wmb();
-
- dscr++;
- if (dscr > DSCR_MAX)
- dscr = 0;
-
- set_default_dscr(dscr);
-
- wmb();
- sequence++;
- }
- }
-
- /* 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;
- }
-
- 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 28b1ea23e469..9930533730ae 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;
}
+struct random_thread_args {
+ pthread_t thread_id;
+ bool do_yields;
+ pthread_barrier_t *barrier;
+};
+
+void *dscr_explicit_random_thread(void *in)
+{
+ struct random_thread_args *args = (struct random_thread_args *)in;
+ unsigned long expected_dscr = 0;
+ int err;
+
+ srand(gettid());
+
+ err = pthread_barrier_wait(args->barrier);
+ FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
+
+ for (int i = 0; i < COUNT; i++) {
+ expected_dscr = rand() % DSCR_MAX;
+ set_dscr(expected_dscr);
+
+ for (int j = rand() % 5; j > 0; --j) {
+ FAIL_IF_EXIT(get_dscr() != expected_dscr);
+ FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
+
+ if (args->do_yields && rand() % 2)
+ sched_yield();
+ }
+
+ expected_dscr = rand() % DSCR_MAX;
+ set_dscr_usr(expected_dscr);
+
+ for (int j = rand() % 5; j > 0; --j) {
+ FAIL_IF_EXIT(get_dscr() != expected_dscr);
+ FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
+
+ if (args->do_yields && rand() % 2)
+ sched_yield();
+ }
+ }
+
+ return NULL;
+}
+
int dscr_explicit_random_test(void)
{
- unsigned long i, dscr = 0;
+ struct random_thread_args threads[THREADS];
+ pthread_barrier_t barrier;
SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
- srand(getpid());
- set_dscr(dscr);
+ FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS));
- for (i = 0; i < COUNT; i++) {
- unsigned long cur_dscr, cur_dscr_usr;
- double ret = uniform_deviate(rand());
+ for (int i = 0; i < THREADS; i++) {
+ threads[i].do_yields = i % 2 == 0;
+ threads[i].barrier = &barrier;
- if (ret < 0.001) {
- dscr++;
- if (dscr > DSCR_MAX)
- dscr = 0;
-
- set_dscr(dscr);
- }
-
- cur_dscr = get_dscr();
- if (cur_dscr != dscr) {
- fprintf(stderr, "Kernel DSCR should be %ld but "
- "is %ld\n", dscr, cur_dscr);
- return 1;
- }
-
- ret = uniform_deviate(rand());
- if (ret < 0.001) {
- dscr++;
- if (dscr > DSCR_MAX)
- dscr = 0;
-
- set_dscr_usr(dscr);
- }
-
- 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;
- }
+ 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-03-07 1:01 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-07 0:55 [PATCH 0/5] Update DSCR tests Benjamin Gray
2023-03-07 0:55 ` [PATCH 1/5] selftests/powerpc/dscr: Correct typos Benjamin Gray
2023-03-07 0:55 ` [PATCH 2/5] selftests/powerpc/dscr: Add lockstep test cases to DSCR explicit tests Benjamin Gray
2023-03-07 9:59 ` Michael Ellerman
2023-03-07 0:55 ` Benjamin Gray [this message]
2023-03-07 0:55 ` [PATCH 4/5] selftests/powerpc/dscr: Speed up DSCR sysfs tests Benjamin Gray
2023-03-07 0:55 ` [PATCH 5/5] selftests/powerpc/dscr: Restore timeout to DSCR selftests Benjamin Gray
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=20230307005515.174362-4-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.