linux/tools/testing/selftests/powerpc/math/fpu_preempt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2015, Cyril Bur, IBM Corp.
   4 *
   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
  37int threads_starting;
  38int running;
  39
  40extern void preempt_fpu(double *darray, int *threads_starting, int *running);
  41
  42void *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
  55int 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
 106int main(int argc, char *argv[])
 107{
 108        return test_harness(test_preempt_fpu, "fpu_preempt");
 109}
 110