Changeset View
Changeset View
Standalone View
Standalone View
tools/test/xregs_sig/xregs_sig.c
Show All 38 Lines | |||||||||||
/* SIGALRM interval in seconds. */ | /* SIGALRM interval in seconds. */ | ||||||||||
#ifndef TIMO | #ifndef TIMO | ||||||||||
#define TIMO 5 | #define TIMO 5 | ||||||||||
#endif | #endif | ||||||||||
#ifndef __unused | #ifndef __unused | ||||||||||
#define __unused __attribute__((__unused__)) | #define __unused __attribute__((__unused__)) | ||||||||||
#endif | #endif | ||||||||||
#ifndef nitems | |||||||||||
#define nitems(x) (sizeof((x)) / sizeof((x)[0])) | |||||||||||
#endif | |||||||||||
struct xregs_bank { | |||||||||||
const char *b_name; | |||||||||||
const char *r_name; | |||||||||||
uint32_t regs; | |||||||||||
uint32_t bytes; | |||||||||||
void (*x2c)(uint8_t *); | |||||||||||
void (*c2x)(uint8_t *); | |||||||||||
}; | |||||||||||
#if defined(__amd64__) | #if defined(__amd64__) | ||||||||||
#define XREGSRNAM "xmm" | void cpu_to_xmm(uint8_t *); | ||||||||||
#define NREGS 16 | void xmm_to_cpu(uint8_t *); | ||||||||||
#elif defined(__aarch64__) | |||||||||||
#define XREGSRNAM "q" | |||||||||||
#define NREGS 32 | |||||||||||
#endif | |||||||||||
struct xregsreg { | static const struct xregs_bank xregs_banks[] = { | ||||||||||
kibUnsubmitted Not Done Inline Actions
kib: | |||||||||||
Not Done Inline ActionsAnd what about this? kib: And what about this? | |||||||||||
uint8_t xregs_bytes[16]; | { | ||||||||||
.b_name = "SSE", | |||||||||||
.r_name = "xmm", | |||||||||||
.regs = 16, | |||||||||||
.bytes = 16, | |||||||||||
.x2c = xmm_to_cpu, | |||||||||||
.c2x = cpu_to_xmm, | |||||||||||
}, | |||||||||||
}; | }; | ||||||||||
#elif defined(__aarch64__) | |||||||||||
void cpu_to_vfp(uint8_t *); | |||||||||||
void vfp_to_cpu(uint8_t *); | |||||||||||
struct xregs { | static const struct xregs_bank xregs_banks[] = { | ||||||||||
struct xregsreg xregsreg[NREGS]; | { | ||||||||||
.b_name = "VFP", | |||||||||||
.r_name = "q", | |||||||||||
.regs = 32, | |||||||||||
.bytes = 16, | |||||||||||
.x2c = vfp_to_cpu, | |||||||||||
.c2x = cpu_to_vfp, | |||||||||||
}, | |||||||||||
}; | }; | ||||||||||
#endif | |||||||||||
void cpu_to_xregs(struct xregs *xregs); | |||||||||||
void xregs_to_cpu(struct xregs *xregs); | |||||||||||
static atomic_uint sigs; | static atomic_uint sigs; | ||||||||||
static int max_bank_idx; | |||||||||||
static void | static void | ||||||||||
sigusr1_handler(int sig __unused, siginfo_t *si __unused, void *m __unused) | sigusr1_handler(int sig __unused, siginfo_t *si __unused, void *m __unused) | ||||||||||
{ | { | ||||||||||
atomic_fetch_add_explicit(&sigs, 1, memory_order_relaxed); | atomic_fetch_add_explicit(&sigs, 1, memory_order_relaxed); | ||||||||||
} | } | ||||||||||
static void | static void | ||||||||||
sigalrm_handler(int sig __unused) | sigalrm_handler(int sig __unused) | ||||||||||
{ | { | ||||||||||
struct rusage r; | struct rusage r; | ||||||||||
if (getrusage(RUSAGE_SELF, &r) == 0) { | if (getrusage(RUSAGE_SELF, &r) == 0) { | ||||||||||
printf("%lu vctx %lu nvctx %lu nsigs %u SIGUSR1\n", | printf("%lu vctx %lu nvctx %lu nsigs %u SIGUSR1\n", | ||||||||||
r.ru_nvcsw, r.ru_nivcsw, r.ru_nsignals, sigs); | r.ru_nvcsw, r.ru_nivcsw, r.ru_nsignals, sigs); | ||||||||||
} | } | ||||||||||
alarm(TIMO); | alarm(TIMO); | ||||||||||
} | } | ||||||||||
static struct xregs zero_xregs = {}; | |||||||||||
static void | static void | ||||||||||
fill_xregs(struct xregs *xregs) | fill_xregs(uint8_t *xregs, int bank) | ||||||||||
{ | { | ||||||||||
arc4random_buf(xregs, sizeof(*xregs)); | arc4random_buf(xregs, xregs_banks[bank].regs * xregs_banks[bank].bytes); | ||||||||||
} | } | ||||||||||
static void | static void | ||||||||||
dump_xregs(const struct xregsreg *r) | dump_xregs(const uint8_t *r, int bank) | ||||||||||
{ | { | ||||||||||
unsigned k; | unsigned k; | ||||||||||
for (k = 0; k < nitems(r->xregs_bytes); k++) { | for (k = 0; k < xregs_banks[bank].bytes; k++) { | ||||||||||
if (k != 0) | if (k != 0) | ||||||||||
printf(" "); | printf(" "); | ||||||||||
printf("%02x", r->xregs_bytes[k]); | printf("%02x", r[k]); | ||||||||||
} | } | ||||||||||
printf("\n"); | printf("\n"); | ||||||||||
} | } | ||||||||||
static pthread_mutex_t show_lock; | static pthread_mutex_t show_lock; | ||||||||||
static void | static void | ||||||||||
show_diff(const struct xregs *xregs1, const struct xregs *xregs2) | show_diff(const uint8_t *xregs1, const uint8_t *xregs2, int bank) | ||||||||||
{ | { | ||||||||||
const struct xregsreg *r1, *r2; | const uint8_t *r1, *r2; | ||||||||||
unsigned i, j; | unsigned i, j; | ||||||||||
#if defined(__FreeBSD__) | #if defined(__FreeBSD__) | ||||||||||
printf("thr %d\n", pthread_getthreadid_np()); | printf("thr %d\n", pthread_getthreadid_np()); | ||||||||||
#elif defined(__linux__) | #elif defined(__linux__) | ||||||||||
printf("thr %ld\n", syscall(SYS_gettid)); | printf("thr %ld\n", syscall(SYS_gettid)); | ||||||||||
#endif | #endif | ||||||||||
for (i = 0; i < nitems(xregs1->xregsreg); i++) { | for (i = 0; i < xregs_banks[bank].regs; i++) { | ||||||||||
r1 = &xregs1->xregsreg[i]; | r1 = xregs1 + i * xregs_banks[bank].bytes; | ||||||||||
r2 = &xregs2->xregsreg[i]; | r2 = xregs2 + i * xregs_banks[bank].bytes; | ||||||||||
for (j = 0; j < nitems(r1->xregs_bytes); j++) { | for (j = 0; j < xregs_banks[bank].bytes; j++) { | ||||||||||
if (r1->xregs_bytes[j] != r2->xregs_bytes[j]) { | if (r1[j] != r2[j]) { | ||||||||||
printf("%%%s%u\n", XREGSRNAM, i); | printf("%%%s%u\n", xregs_banks[bank].r_name, i); | ||||||||||
dump_xregs(r1); | dump_xregs(r1, bank); | ||||||||||
dump_xregs(r2); | dump_xregs(r2, bank); | ||||||||||
break; | break; | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
static void | static void | ||||||||||
my_pause(void) | my_pause(void) | ||||||||||
{ | { | ||||||||||
usleep(0); | usleep(0); | ||||||||||
} | } | ||||||||||
static void * | static void * | ||||||||||
worker_thread(void *arg __unused) | worker_thread(void *arg) | ||||||||||
{ | { | ||||||||||
struct xregs xregs, xregs_cpu; | int bank = (uintptr_t)arg; | ||||||||||
int sz = xregs_banks[bank].regs * xregs_banks[bank].bytes; | |||||||||||
uint8_t xregs[sz], xregs_cpu[sz], zero_xregs[sz]; | |||||||||||
fill_xregs(&xregs); | memset(zero_xregs, 0, sz); | ||||||||||
fill_xregs(xregs, bank); | |||||||||||
for (;;) { | for (;;) { | ||||||||||
xregs_to_cpu(&xregs); | xregs_banks[bank].x2c(xregs); | ||||||||||
my_pause(); | my_pause(); | ||||||||||
cpu_to_xregs(&xregs_cpu); | xregs_banks[bank].c2x(xregs_cpu); | ||||||||||
if (memcmp(&xregs, &xregs_cpu, sizeof(struct xregs)) != 0) { | if (memcmp(xregs, xregs_cpu, sz) != 0) { | ||||||||||
pthread_mutex_lock(&show_lock); | pthread_mutex_lock(&show_lock); | ||||||||||
show_diff(&xregs, &xregs_cpu); | show_diff(xregs, xregs_cpu, bank); | ||||||||||
abort(); | abort(); | ||||||||||
pthread_mutex_unlock(&show_lock); | pthread_mutex_unlock(&show_lock); | ||||||||||
} | } | ||||||||||
xregs_to_cpu(&zero_xregs); | xregs_banks[bank].x2c(zero_xregs); | ||||||||||
my_pause(); | my_pause(); | ||||||||||
cpu_to_xregs(&xregs_cpu); | xregs_banks[bank].c2x(xregs_cpu); | ||||||||||
if (memcmp(&zero_xregs, &xregs_cpu, sizeof(struct xregs)) != 0) { | if (memcmp(zero_xregs, xregs_cpu, sz) != 0) { | ||||||||||
pthread_mutex_lock(&show_lock); | pthread_mutex_lock(&show_lock); | ||||||||||
show_diff(&zero_xregs, &xregs_cpu); | show_diff(zero_xregs, xregs_cpu, bank); | ||||||||||
abort(); | abort(); | ||||||||||
pthread_mutex_unlock(&show_lock); | pthread_mutex_unlock(&show_lock); | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
return (NULL); | return (NULL); | ||||||||||
} | } | ||||||||||
int | int | ||||||||||
main(void) | main(void) | ||||||||||
{ | { | ||||||||||
struct sigaction sa; | struct sigaction sa; | ||||||||||
int error, i, ncpu; | int error, i, ncpu, bank; | ||||||||||
max_bank_idx = 0; | |||||||||||
bzero(&sa, sizeof(sa)); | bzero(&sa, sizeof(sa)); | ||||||||||
sa.sa_handler = sigalrm_handler; | sa.sa_handler = sigalrm_handler; | ||||||||||
if (sigaction(SIGALRM, &sa, NULL) == -1) { | if (sigaction(SIGALRM, &sa, NULL) == -1) { | ||||||||||
fprintf(stderr, "sigaction SIGALRM %s\n", strerror(errno)); | fprintf(stderr, "sigaction SIGALRM %s\n", strerror(errno)); | ||||||||||
exit(1); | exit(1); | ||||||||||
} | } | ||||||||||
bzero(&sa, sizeof(sa)); | bzero(&sa, sizeof(sa)); | ||||||||||
sa.sa_sigaction = sigusr1_handler; | sa.sa_sigaction = sigusr1_handler; | ||||||||||
sa.sa_flags = SA_SIGINFO; | sa.sa_flags = SA_SIGINFO; | ||||||||||
if (sigaction(SIGUSR1, &sa, NULL) == -1) { | if (sigaction(SIGUSR1, &sa, NULL) == -1) { | ||||||||||
fprintf(stderr, "sigaction SIGUSR1 %s\n", strerror(errno)); | fprintf(stderr, "sigaction SIGUSR1 %s\n", strerror(errno)); | ||||||||||
exit(1); | exit(1); | ||||||||||
} | } | ||||||||||
error = pthread_mutex_init(&show_lock, NULL); | error = pthread_mutex_init(&show_lock, NULL); | ||||||||||
if (error != 0) { | if (error != 0) { | ||||||||||
fprintf(stderr, "pthread_mutex_init %s\n", strerror(error)); | fprintf(stderr, "pthread_mutex_init %s\n", strerror(error)); | ||||||||||
exit(1); | exit(1); | ||||||||||
} | } | ||||||||||
ncpu = sysconf(_SC_NPROCESSORS_ONLN); | ncpu = sysconf(_SC_NPROCESSORS_ONLN); | ||||||||||
if (max_bank_idx == 0) | |||||||||||
ncpu *= 2; | ncpu *= 2; | ||||||||||
bank = 0; | |||||||||||
pthread_t wt[ncpu]; | pthread_t wt[ncpu]; | ||||||||||
nextbank: | |||||||||||
printf("Starting %d threads for registers bank %s sized [%d][%d]\n", ncpu, | |||||||||||
xregs_banks[bank].b_name, xregs_banks[bank].regs, xregs_banks[bank].bytes); | |||||||||||
for (i = 0; i < ncpu; i++) { | for (i = 0; i < ncpu; i++) { | ||||||||||
error = pthread_create(&wt[i], NULL, worker_thread, NULL); | error = pthread_create(&wt[i], NULL, worker_thread, | ||||||||||
(void *)(uintptr_t)bank); | |||||||||||
if (error != 0) { | if (error != 0) { | ||||||||||
fprintf(stderr, "pthread_create %s\n", strerror(error)); | fprintf(stderr, "pthread_create %s\n", strerror(error)); | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
if (++bank <= max_bank_idx) | |||||||||||
goto nextbank; | |||||||||||
alarm(TIMO); | alarm(TIMO); | ||||||||||
for (;;) { | for (;;) { | ||||||||||
for (i = 0; i < ncpu; i++) { | for (i = 0; i < ncpu; i++) { | ||||||||||
my_pause(); | my_pause(); | ||||||||||
pthread_kill(wt[i], SIGUSR1); | pthread_kill(wt[i], SIGUSR1); | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
} | } |