diff options
Diffstat (limited to 'tools/testing/selftests/powerpc/dscr/dscr_default_test.c')
-rw-r--r-- | tools/testing/selftests/powerpc/dscr/dscr_default_test.c | 207 |
1 files changed, 125 insertions, 82 deletions
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_default_test.c b/tools/testing/selftests/powerpc/dscr/dscr_default_test.c index e76611e608af..60ab02525b79 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_default_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_default_test.c @@ -9,118 +9,161 @@ * Copyright 2012, Anton Blanchard, IBM Corporation. * Copyright 2015, Anshuman Khandual, IBM Corporation. */ -#include "dscr.h" - -static unsigned long dscr; /* System DSCR default */ -static unsigned long sequence; -static unsigned long result[THREADS]; - -static void *do_test(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; +#define _GNU_SOURCE - s1 = READ_ONCE(sequence); - if (s1 & 1) - continue; - rmb(); +#include "dscr.h" - d = dscr; - cur_dscr = get_dscr(); - cur_dscr_usr = get_dscr_usr(); +#include <pthread.h> +#include <semaphore.h> +#include <unistd.h> - rmb(); - s2 = sequence; +static void *dscr_default_lockstep_writer(void *arg) +{ + sem_t *reader_sem = (sem_t *)arg; + sem_t *writer_sem = (sem_t *)arg + 1; + unsigned long expected_dscr = 0; - if (s1 != s2) - continue; + for (int i = 0; i < COUNT; i++) { + FAIL_IF_EXIT(sem_wait(writer_sem)); - 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]); - } + set_default_dscr(expected_dscr); + expected_dscr = (expected_dscr + 1) % DSCR_MAX; - 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(sem_post(reader_sem)); } - result[thread] = 0; - pthread_exit(&result[thread]); + + return NULL; } -int dscr_default(void) +int dscr_default_lockstep_test(void) { - pthread_t threads[THREADS]; - unsigned long i, *status[THREADS]; - unsigned long orig_dscr_default; + pthread_t writer; + sem_t rw_semaphores[2]; + sem_t *reader_sem = &rw_semaphores[0]; + sem_t *writer_sem = &rw_semaphores[1]; + unsigned long expected_dscr = 0; SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR)); - orig_dscr_default = get_default_dscr(); + FAIL_IF(sem_init(reader_sem, 0, 0)); + FAIL_IF(sem_init(writer_sem, 0, 1)); /* writer starts first */ + FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0); + FAIL_IF(pthread_create(&writer, NULL, dscr_default_lockstep_writer, (void *)rw_semaphores)); - /* Initial DSCR default */ - dscr = 1; - set_default_dscr(dscr); + for (int i = 0; i < COUNT ; i++) { + FAIL_IF(sem_wait(reader_sem)); - /* Spawn all testing threads */ - for (i = 0; i < THREADS; i++) { - if (pthread_create(&threads[i], NULL, do_test, (void *)i)) { - perror("pthread_create() failed"); - goto fail; - } - } + FAIL_IF(get_dscr() != expected_dscr); + FAIL_IF(get_dscr_usr() != expected_dscr); - srand(getpid()); + expected_dscr = (expected_dscr + 1) % DSCR_MAX; - /* Keep changing the DSCR default */ - for (i = 0; i < COUNT; i++) { - double ret = uniform_deviate(rand()); + FAIL_IF(sem_post(writer_sem)); + } - if (ret < 0.0001) { - sequence++; - wmb(); + FAIL_IF(pthread_join(writer, NULL)); + FAIL_IF(sem_destroy(reader_sem)); + FAIL_IF(sem_destroy(writer_sem)); - dscr++; - if (dscr > DSCR_MAX) - dscr = 0; + return 0; +} - set_default_dscr(dscr); +struct random_thread_args { + pthread_t thread_id; + unsigned long *expected_system_dscr; + pthread_rwlock_t *rw_lock; + pthread_barrier_t *barrier; +}; - wmb(); - sequence++; +static void *dscr_default_random_thread(void *in) +{ + 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; + + 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++) { + 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)); } } - /* Individual testing thread exit status */ - for (i = 0; i < THREADS; i++) { - if (pthread_join(threads[i], (void **)&(status[i]))) { - perror("pthread_join() failed"); - goto fail; - } + pthread_exit((void *)0); +} - if (*status[i]) { - printf("%ldth thread failed to join with %ld status\n", - i, *status[i]); - goto fail; - } +int dscr_default_random_test(void) +{ + 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)); + + 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)); + + 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])); } - set_default_dscr(orig_dscr_default); + + 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)); + return 0; -fail: - set_default_dscr(orig_dscr_default); - return 1; } int main(int argc, char *argv[]) { - return test_harness(dscr_default, "dscr_default_test"); + unsigned long orig_dscr_default = 0; + int err = 0; + + if (have_hwcap2(PPC_FEATURE2_DSCR)) + orig_dscr_default = get_default_dscr(); + + err |= test_harness(dscr_default_lockstep_test, "dscr_default_lockstep_test"); + err |= test_harness(dscr_default_random_test, "dscr_default_random_test"); + + if (have_hwcap2(PPC_FEATURE2_DSCR)) + set_default_dscr(orig_dscr_default); + + return err; } |