selftests/powerpc/dscr: Add lockstep test cases to DSCR explicit tests
Add new cases to the relevant tests that use explicitly synchronized threads to test the behaviour across context switches with less randomness. By locking the participants to the same CPU we guarantee a context switch occurs each time they make progress, which is a likely failure point if the kernel is not tracking the thread local DSCR correctly. The random case is left in to keep exercising potential edge cases. Signed-off-by: Benjamin Gray <bgray@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20230406043320.125138-5-bgray@linux.ibm.com
This commit is contained in:
parent
6ff4dc2548
commit
fda8158870
|
@ -9,5 +9,6 @@ top_srcdir = ../../../../..
|
||||||
include ../../lib.mk
|
include ../../lib.mk
|
||||||
|
|
||||||
$(OUTPUT)/dscr_default_test: LDLIBS += -lpthread
|
$(OUTPUT)/dscr_default_test: LDLIBS += -lpthread
|
||||||
|
$(OUTPUT)/dscr_explicit_test: LDLIBS += -lpthread
|
||||||
|
|
||||||
$(TEST_GEN_PROGS): ../harness.c ../utils.c
|
$(TEST_GEN_PROGS): ../harness.c ../utils.c
|
||||||
|
|
|
@ -9,8 +9,66 @@
|
||||||
* Copyright 2012, Anton Blanchard, IBM Corporation.
|
* Copyright 2012, Anton Blanchard, IBM Corporation.
|
||||||
* Copyright 2015, Anshuman Khandual, IBM Corporation.
|
* Copyright 2015, Anshuman Khandual, IBM Corporation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include "dscr.h"
|
#include "dscr.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (int i = 0; i < COUNT; i++) {
|
||||||
|
FAIL_IF_EXIT(sem_wait(writer_sem));
|
||||||
|
|
||||||
|
set_default_dscr(expected_dscr);
|
||||||
|
expected_dscr = (expected_dscr + 1) % DSCR_MAX;
|
||||||
|
|
||||||
|
FAIL_IF_EXIT(sem_post(reader_sem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dscr_default_lockstep_test(void)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
for (int i = 0; i < COUNT ; i++) {
|
||||||
|
FAIL_IF(sem_wait(reader_sem));
|
||||||
|
|
||||||
|
FAIL_IF(get_dscr() != expected_dscr);
|
||||||
|
FAIL_IF(get_dscr_usr() != expected_dscr);
|
||||||
|
|
||||||
|
expected_dscr = (expected_dscr + 1) % DSCR_MAX;
|
||||||
|
|
||||||
|
FAIL_IF(sem_post(writer_sem));
|
||||||
|
}
|
||||||
|
|
||||||
|
FAIL_IF(pthread_join(writer, NULL));
|
||||||
|
FAIL_IF(sem_destroy(reader_sem));
|
||||||
|
FAIL_IF(sem_destroy(writer_sem));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned long dscr; /* System DSCR default */
|
static unsigned long dscr; /* System DSCR default */
|
||||||
static unsigned long sequence;
|
static unsigned long sequence;
|
||||||
static unsigned long result[THREADS];
|
static unsigned long result[THREADS];
|
||||||
|
@ -57,16 +115,13 @@ static void *do_test(void *in)
|
||||||
pthread_exit(&result[thread]);
|
pthread_exit(&result[thread]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dscr_default(void)
|
int dscr_default_random_test(void)
|
||||||
{
|
{
|
||||||
pthread_t threads[THREADS];
|
pthread_t threads[THREADS];
|
||||||
unsigned long i, *status[THREADS];
|
unsigned long i, *status[THREADS];
|
||||||
unsigned long orig_dscr_default;
|
|
||||||
|
|
||||||
SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
|
SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
|
||||||
|
|
||||||
orig_dscr_default = get_default_dscr();
|
|
||||||
|
|
||||||
/* Initial DSCR default */
|
/* Initial DSCR default */
|
||||||
dscr = 1;
|
dscr = 1;
|
||||||
set_default_dscr(dscr);
|
set_default_dscr(dscr);
|
||||||
|
@ -75,7 +130,7 @@ int dscr_default(void)
|
||||||
for (i = 0; i < THREADS; i++) {
|
for (i = 0; i < THREADS; i++) {
|
||||||
if (pthread_create(&threads[i], NULL, do_test, (void *)i)) {
|
if (pthread_create(&threads[i], NULL, do_test, (void *)i)) {
|
||||||
perror("pthread_create() failed");
|
perror("pthread_create() failed");
|
||||||
goto fail;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,23 +159,31 @@ int dscr_default(void)
|
||||||
for (i = 0; i < THREADS; i++) {
|
for (i = 0; i < THREADS; i++) {
|
||||||
if (pthread_join(threads[i], (void **)&(status[i]))) {
|
if (pthread_join(threads[i], (void **)&(status[i]))) {
|
||||||
perror("pthread_join() failed");
|
perror("pthread_join() failed");
|
||||||
goto fail;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*status[i]) {
|
if (*status[i]) {
|
||||||
printf("%ldth thread failed to join with %ld status\n",
|
printf("%ldth thread failed to join with %ld status\n",
|
||||||
i, *status[i]);
|
i, *status[i]);
|
||||||
goto fail;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set_default_dscr(orig_dscr_default);
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
|
||||||
set_default_dscr(orig_dscr_default);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,78 @@
|
||||||
* Copyright 2012, Anton Blanchard, IBM Corporation.
|
* Copyright 2012, Anton Blanchard, IBM Corporation.
|
||||||
* Copyright 2015, Anshuman Khandual, IBM Corporation.
|
* Copyright 2015, Anshuman Khandual, IBM Corporation.
|
||||||
*/
|
*/
|
||||||
#include "dscr.h"
|
|
||||||
|
|
||||||
int dscr_explicit(void)
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "dscr.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
void *dscr_explicit_lockstep_thread(void *args)
|
||||||
|
{
|
||||||
|
sem_t *prev = (sem_t *)args;
|
||||||
|
sem_t *next = (sem_t *)args + 1;
|
||||||
|
unsigned long expected_dscr = 0;
|
||||||
|
|
||||||
|
set_dscr(expected_dscr);
|
||||||
|
srand(gettid());
|
||||||
|
|
||||||
|
for (int i = 0; i < COUNT; i++) {
|
||||||
|
FAIL_IF_EXIT(sem_wait(prev));
|
||||||
|
|
||||||
|
FAIL_IF_EXIT(expected_dscr != get_dscr());
|
||||||
|
FAIL_IF_EXIT(expected_dscr != get_dscr_usr());
|
||||||
|
|
||||||
|
expected_dscr = (expected_dscr + 1) % DSCR_MAX;
|
||||||
|
set_dscr(expected_dscr);
|
||||||
|
|
||||||
|
FAIL_IF_EXIT(sem_post(next));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dscr_explicit_lockstep_test(void)
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
sem_t semaphores[2];
|
||||||
|
sem_t *prev = &semaphores[1]; /* reversed prev/next than for the other thread */
|
||||||
|
sem_t *next = &semaphores[0];
|
||||||
|
unsigned long expected_dscr = 0;
|
||||||
|
|
||||||
|
SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
|
||||||
|
|
||||||
|
srand(gettid());
|
||||||
|
set_dscr(expected_dscr);
|
||||||
|
|
||||||
|
FAIL_IF(sem_init(prev, 0, 0));
|
||||||
|
FAIL_IF(sem_init(next, 0, 1)); /* other thread starts first */
|
||||||
|
FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0);
|
||||||
|
FAIL_IF(pthread_create(&thread, NULL, dscr_explicit_lockstep_thread, (void *)semaphores));
|
||||||
|
|
||||||
|
for (int i = 0; i < COUNT; i++) {
|
||||||
|
FAIL_IF(sem_wait(prev));
|
||||||
|
|
||||||
|
FAIL_IF(expected_dscr != get_dscr());
|
||||||
|
FAIL_IF(expected_dscr != get_dscr_usr());
|
||||||
|
|
||||||
|
expected_dscr = (expected_dscr - 1) % DSCR_MAX;
|
||||||
|
set_dscr(expected_dscr);
|
||||||
|
|
||||||
|
FAIL_IF(sem_post(next));
|
||||||
|
}
|
||||||
|
|
||||||
|
FAIL_IF(pthread_join(thread, NULL));
|
||||||
|
FAIL_IF(sem_destroy(prev));
|
||||||
|
FAIL_IF(sem_destroy(next));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dscr_explicit_random_test(void)
|
||||||
{
|
{
|
||||||
unsigned long i, dscr = 0;
|
unsigned long i, dscr = 0;
|
||||||
|
|
||||||
|
@ -66,5 +135,17 @@ int dscr_explicit(void)
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
return test_harness(dscr_explicit, "dscr_explicit_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_explicit_lockstep_test, "dscr_explicit_lockstep_test");
|
||||||
|
err |= test_harness(dscr_explicit_random_test, "dscr_explicit_random_test");
|
||||||
|
|
||||||
|
if (have_hwcap2(PPC_FEATURE2_DSCR))
|
||||||
|
set_default_dscr(orig_dscr_default);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue