]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e5ab8be6 CB |
2 | /* |
3 | * Copyright 2015, Cyril Bur, IBM Corp. | |
4 | * | |
e5ab8be6 CB |
5 | * This test attempts to see if the FPU registers change across preemption. |
6 | * Two things should be noted here a) The check_fpu function in asm only checks | |
7 | * the non volatile registers as it is reused from the syscall test b) There is | |
8 | * no way to be sure preemption happened so this test just uses many threads | |
9 | * and a long wait. As such, a successful test doesn't mean much but a failure | |
10 | * is bad. | |
11 | */ | |
12 | ||
13 | #include <stdio.h> | |
14 | #include <unistd.h> | |
15 | #include <sys/syscall.h> | |
16 | #include <sys/time.h> | |
17 | #include <sys/types.h> | |
18 | #include <sys/wait.h> | |
19 | #include <stdlib.h> | |
20 | #include <pthread.h> | |
21 | ||
22 | #include "utils.h" | |
23 | ||
24 | /* Time to wait for workers to get preempted (seconds) */ | |
25 | #define PREEMPT_TIME 20 | |
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[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, | |
34 | 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, | |
35 | 2.1}; | |
36 | ||
37 | int threads_starting; | |
38 | int running; | |
39 | ||
40 | extern void preempt_fpu(double *darray, int *threads_starting, int *running); | |
41 | ||
42 | void *preempt_fpu_c(void *p) | |
43 | { | |
44 | int i; | |
45 | srand(pthread_self()); | |
46 | for (i = 0; i < 21; i++) | |
47 | darray[i] = rand(); | |
48 | ||
49 | /* Test failed if it ever returns */ | |
50 | preempt_fpu(darray, &threads_starting, &running); | |
51 | ||
52 | return p; | |
53 | } | |
54 | ||
55 | int test_preempt_fpu(void) | |
56 | { | |
57 | int i, rc, threads; | |
58 | pthread_t *tids; | |
59 | ||
60 | threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR; | |
61 | tids = malloc((threads) * sizeof(pthread_t)); | |
62 | FAIL_IF(!tids); | |
63 | ||
64 | running = true; | |
65 | threads_starting = threads; | |
66 | for (i = 0; i < threads; i++) { | |
67 | rc = pthread_create(&tids[i], NULL, preempt_fpu_c, NULL); | |
68 | FAIL_IF(rc); | |
69 | } | |
70 | ||
71 | setbuf(stdout, NULL); | |
72 | /* Not really necessary but nice to wait for every thread to start */ | |
73 | printf("\tWaiting for all workers to start..."); | |
74 | while(threads_starting) | |
75 | asm volatile("": : :"memory"); | |
76 | printf("done\n"); | |
77 | ||
78 | printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME); | |
79 | sleep(PREEMPT_TIME); | |
80 | printf("done\n"); | |
81 | ||
82 | printf("\tStopping workers..."); | |
83 | /* | |
84 | * Working are checking this value every loop. In preempt_fpu 'cmpwi r5,0; bne 2b'. | |
85 | * r5 will have loaded the value of running. | |
86 | */ | |
87 | running = 0; | |
88 | for (i = 0; i < threads; i++) { | |
89 | void *rc_p; | |
90 | pthread_join(tids[i], &rc_p); | |
91 | ||
92 | /* | |
93 | * Harness will say the fail was here, look at why preempt_fpu | |
94 | * returned | |
95 | */ | |
96 | if ((long) rc_p) | |
97 | printf("oops\n"); | |
98 | FAIL_IF((long) rc_p); | |
99 | } | |
100 | printf("done\n"); | |
101 | ||
102 | free(tids); | |
103 | return 0; | |
104 | } | |
105 | ||
106 | int main(int argc, char *argv[]) | |
107 | { | |
108 | return test_harness(test_preempt_fpu, "fpu_preempt"); | |
109 | } |