From: Benjamin Gray Date: Thu, 6 Apr 2023 04:33:18 +0000 (+1000) Subject: selftests/powerpc/dscr: Improve DSCR explicit random test case X-Git-Tag: Ubuntu-6.5.0-9.9~2790^2~58 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=3067b89ab62305c54ec15b00a2c4dbaf64809c59;p=mirror_ubuntu-kernels.git selftests/powerpc/dscr: Improve DSCR explicit random test case 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 Signed-off-by: Michael Ellerman Link: https://msgid.link/20230406043320.125138-6-bgray@linux.ibm.com --- 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; }