Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/test/xregs_sig/xregs_sig.c
39536 views
1
/* $Id: avx_sig.c,v 1.12 2021/12/11 22:47:09 kostik Exp $ */
2
/*
3
* Naive test to check that context switches and signal delivery do
4
* not corrupt AVX registers file (%xmm). Run until some
5
* inconsistency detected, then aborts.
6
*
7
* FreeBSD:
8
* ${CC} -Wall -Wextra -O -g -o avx_sig avx_sig.c -lpthread
9
* Linux
10
* ${CC} -D_GNU_SOURCE -Wall -Wextra -O -g -o avx_sig avx_sig.c -lbsd -lpthread
11
*/
12
13
#include <sys/param.h>
14
#include <sys/time.h>
15
#include <sys/resource.h>
16
#include <sys/syscall.h>
17
#include <errno.h>
18
#include <pthread.h>
19
#ifdef __FreeBSD__
20
#include <pthread_np.h>
21
#endif
22
#ifdef __linux__
23
#ifdef __GLIBC__
24
#include <gnu/libc-version.h>
25
#endif
26
#if !defined(__GLIBC__) || (__GLIBC__ * 100 + __GLIBC_MINOR__) < 236
27
#include <bsd/stdlib.h>
28
#endif
29
#endif
30
#include <signal.h>
31
#include <stdatomic.h>
32
#include <stdbool.h>
33
#include <stdint.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
39
/* SIGALRM interval in seconds. */
40
#ifndef TIMO
41
#define TIMO 5
42
#endif
43
44
#ifndef __unused
45
#define __unused __attribute__((__unused__))
46
#endif
47
48
struct xregs_bank {
49
const char *b_name;
50
const char *r_name;
51
uint32_t regs;
52
uint32_t bytes;
53
void (*x2c)(uint8_t *);
54
void (*c2x)(uint8_t *);
55
};
56
57
int xregs_banks_max(void);
58
59
#if defined(__amd64__)
60
void cpu_to_xmm(uint8_t *);
61
void xmm_to_cpu(uint8_t *);
62
void cpu_to_avx(uint8_t *);
63
void avx_to_cpu(uint8_t *);
64
65
static const struct xregs_bank xregs_banks[] = {
66
{
67
.b_name = "SSE",
68
.r_name = "xmm",
69
.regs = 16,
70
.bytes = 16,
71
.x2c = xmm_to_cpu,
72
.c2x = cpu_to_xmm,
73
},
74
{
75
.b_name = "AVX",
76
.r_name = "ymm",
77
.regs = 16,
78
.bytes = 32,
79
.x2c = avx_to_cpu,
80
.c2x = cpu_to_avx,
81
},
82
};
83
#elif defined(__aarch64__)
84
void cpu_to_vfp(uint8_t *);
85
void vfp_to_cpu(uint8_t *);
86
87
static const struct xregs_bank xregs_banks[] = {
88
{
89
.b_name = "VFP",
90
.r_name = "q",
91
.regs = 32,
92
.bytes = 16,
93
.x2c = vfp_to_cpu,
94
.c2x = cpu_to_vfp,
95
},
96
};
97
#endif
98
99
static atomic_uint sigs;
100
static int max_bank_idx;
101
102
103
static void
104
sigusr1_handler(int sig __unused, siginfo_t *si __unused, void *m __unused)
105
{
106
atomic_fetch_add_explicit(&sigs, 1, memory_order_relaxed);
107
}
108
109
static void
110
sigalrm_handler(int sig __unused)
111
{
112
struct rusage r;
113
114
if (getrusage(RUSAGE_SELF, &r) == 0) {
115
printf("%lu vctx %lu nvctx %lu nsigs %u SIGUSR1\n",
116
r.ru_nvcsw, r.ru_nivcsw, r.ru_nsignals, sigs);
117
}
118
alarm(TIMO);
119
}
120
121
122
static void
123
fill_xregs(uint8_t *xregs, int bank)
124
{
125
arc4random_buf(xregs, xregs_banks[bank].regs * xregs_banks[bank].bytes);
126
}
127
128
static void
129
dump_xregs(const uint8_t *r, int bank)
130
{
131
unsigned k;
132
133
for (k = 0; k < xregs_banks[bank].bytes; k++) {
134
if (k != 0)
135
printf(" ");
136
printf("%02x", r[k]);
137
}
138
printf("\n");
139
}
140
141
static pthread_mutex_t show_lock;
142
143
static void
144
show_diff(const uint8_t *xregs1, const uint8_t *xregs2, int bank)
145
{
146
const uint8_t *r1, *r2;
147
unsigned i, j;
148
149
#if defined(__FreeBSD__)
150
printf("thr %d\n", pthread_getthreadid_np());
151
#elif defined(__linux__)
152
printf("thr %ld\n", syscall(SYS_gettid));
153
#endif
154
for (i = 0; i < xregs_banks[bank].regs; i++) {
155
r1 = xregs1 + i * xregs_banks[bank].bytes;
156
r2 = xregs2 + i * xregs_banks[bank].bytes;
157
for (j = 0; j < xregs_banks[bank].bytes; j++) {
158
if (r1[j] != r2[j]) {
159
printf("%%%s%u\n", xregs_banks[bank].r_name, i);
160
dump_xregs(r1, bank);
161
dump_xregs(r2, bank);
162
break;
163
}
164
}
165
}
166
}
167
168
static void
169
my_pause(void)
170
{
171
usleep(0);
172
}
173
174
static void *
175
worker_thread(void *arg)
176
{
177
int bank = (uintptr_t)arg;
178
int sz = xregs_banks[bank].regs * xregs_banks[bank].bytes;
179
uint8_t xregs[sz], xregs_cpu[sz], zero_xregs[sz];
180
181
memset(zero_xregs, 0, sz);
182
183
fill_xregs(xregs, bank);
184
for (;;) {
185
xregs_banks[bank].x2c(xregs);
186
my_pause();
187
xregs_banks[bank].c2x(xregs_cpu);
188
if (memcmp(xregs, xregs_cpu, sz) != 0) {
189
pthread_mutex_lock(&show_lock);
190
show_diff(xregs, xregs_cpu, bank);
191
abort();
192
pthread_mutex_unlock(&show_lock);
193
}
194
195
xregs_banks[bank].x2c(zero_xregs);
196
my_pause();
197
xregs_banks[bank].c2x(xregs_cpu);
198
if (memcmp(zero_xregs, xregs_cpu, sz) != 0) {
199
pthread_mutex_lock(&show_lock);
200
show_diff(zero_xregs, xregs_cpu, bank);
201
abort();
202
pthread_mutex_unlock(&show_lock);
203
}
204
}
205
return (NULL);
206
}
207
208
int
209
main(void)
210
{
211
struct sigaction sa;
212
int error, i, ncpu, bank;
213
214
max_bank_idx = xregs_banks_max();
215
216
bzero(&sa, sizeof(sa));
217
sa.sa_handler = sigalrm_handler;
218
if (sigaction(SIGALRM, &sa, NULL) == -1) {
219
fprintf(stderr, "sigaction SIGALRM %s\n", strerror(errno));
220
exit(1);
221
}
222
223
bzero(&sa, sizeof(sa));
224
sa.sa_sigaction = sigusr1_handler;
225
sa.sa_flags = SA_SIGINFO;
226
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
227
fprintf(stderr, "sigaction SIGUSR1 %s\n", strerror(errno));
228
exit(1);
229
}
230
231
error = pthread_mutex_init(&show_lock, NULL);
232
if (error != 0) {
233
fprintf(stderr, "pthread_mutex_init %s\n", strerror(error));
234
exit(1);
235
}
236
237
ncpu = sysconf(_SC_NPROCESSORS_ONLN);
238
if (max_bank_idx == 0)
239
ncpu *= 2;
240
bank = 0;
241
pthread_t wt[ncpu];
242
nextbank:
243
printf("Starting %d threads for registers bank %s sized [%d][%d]\n", ncpu,
244
xregs_banks[bank].b_name, xregs_banks[bank].regs, xregs_banks[bank].bytes);
245
for (i = 0; i < ncpu; i++) {
246
error = pthread_create(&wt[i], NULL, worker_thread,
247
(void *)(uintptr_t)bank);
248
if (error != 0) {
249
fprintf(stderr, "pthread_create %s\n", strerror(error));
250
}
251
}
252
if (++bank <= max_bank_idx)
253
goto nextbank;
254
255
alarm(TIMO);
256
for (;;) {
257
for (i = 0; i < ncpu; i++) {
258
my_pause();
259
pthread_kill(wt[i], SIGUSR1);
260
}
261
}
262
}
263
264