1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2015, Cyril Bur, IBM Corp. 4 * Copyright 2023, Michael Ellerman, IBM Corp. 5 * 6 * This test attempts to see if the FPU registers change across preemption. 7 * There is no way to be sure preemption happened so this test just uses many 8 * threads and a long wait. As such, a successful test doesn't mean much but 9 * a failure is bad. 10 */ 11 12 #include <stdio.h> 13 #include <unistd.h> 14 #include <sys/syscall.h> 15 #include <sys/time.h> 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <stdlib.h> 19 #include <pthread.h> 20 21 #include "utils.h" 22 #include "fpu.h" 23 24 /* Time to wait for workers to get preempted (seconds) */ 25 #define PREEMPT_TIME 60 26 /* 27 * Factor by which to multiply number of online CPUs for total number of 28 * worker threads 29 */ 30 #define THREAD_FACTOR 8 31 32 33 __thread double darray[32]; 34 35 int threads_starting; 36 int running; 37 38 extern int preempt_fpu(double *darray, int *threads_starting, int *running); 39 40 void *preempt_fpu_c(void *p) 41 { 42 long rc; 43 44 srand(pthread_self()); 45 randomise_darray(darray, ARRAY_SIZE(darray)); 46 rc = preempt_fpu(darray, &threads_starting, &running); 47 48 return (void *)rc; 49 } 50 51 int test_preempt_fpu(void) 52 { 53 int i, rc, threads; 54 pthread_t *tids; 55 56 threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR; 57 tids = malloc((threads) * sizeof(pthread_t)); 58 FAIL_IF(!tids); 59 60 running = true; 61 threads_starting = threads; 62 for (i = 0; i < threads; i++) { 63 rc = pthread_create(&tids[i], NULL, preempt_fpu_c, NULL); 64 FAIL_IF(rc); 65 } 66 67 setbuf(stdout, NULL); 68 /* Not really necessary but nice to wait for every thread to start */ 69 printf("\tWaiting for all workers to start..."); 70 while(threads_starting) 71 asm volatile("": : :"memory"); 72 printf("done\n"); 73 74 printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME); 75 sleep(PREEMPT_TIME); 76 printf("done\n"); 77 78 printf("\tStopping workers..."); 79 /* 80 * Working are checking this value every loop. In preempt_fpu 'cmpwi r5,0; bne 2b'. 81 * r5 will have loaded the value of running. 82 */ 83 running = 0; 84 for (i = 0; i < threads; i++) { 85 void *rc_p; 86 pthread_join(tids[i], &rc_p); 87 88 /* 89 * Harness will say the fail was here, look at why preempt_fpu 90 * returned 91 */ 92 if ((long) rc_p) 93 printf("oops\n"); 94 FAIL_IF((long) rc_p); 95 } 96 printf("done\n"); 97 98 free(tids); 99 return 0; 100 } 101 102 int main(int argc, char *argv[]) 103 { 104 return test_harness(test_preempt_fpu, "fpu_preempt"); 105 } 106