linux/tools/testing/selftests/powerpc/math/vsx_preempt.c
<<
>>
Prefs
   1/*
   2 * Copyright 2015, Cyril Bur, IBM Corp.
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License
   6 * as published by the Free Software Foundation; either version
   7 * 2 of the License, or (at your option) any later version.
   8 *
   9 * This test attempts to see if the VSX registers change across preemption.
  10 * There is no way to be sure preemption happened so this test just
  11 * uses many threads and a long wait. As such, a successful test
  12 * doesn't mean much but a failure is bad.
  13 */
  14
  15#include <stdio.h>
  16#include <string.h>
  17#include <unistd.h>
  18#include <sys/syscall.h>
  19#include <sys/time.h>
  20#include <sys/types.h>
  21#include <sys/wait.h>
  22#include <stdlib.h>
  23#include <pthread.h>
  24
  25#include "utils.h"
  26
  27/* Time to wait for workers to get preempted (seconds) */
  28#define PREEMPT_TIME 20
  29/*
  30 * Factor by which to multiply number of online CPUs for total number of
  31 * worker threads
  32 */
  33#define THREAD_FACTOR 8
  34
  35/*
  36 * Ensure there is twice the number of non-volatile VMX regs!
  37 * check_vmx() is going to use the other half as space to put the live
  38 * registers before calling vsx_memcmp()
  39 */
  40__thread vector int varray[24] = {
  41        {1, 2, 3, 4 }, {5, 6, 7, 8 }, {9, 10,11,12},
  42        {13,14,15,16}, {17,18,19,20}, {21,22,23,24},
  43        {25,26,27,28}, {29,30,31,32}, {33,34,35,36},
  44        {37,38,39,40}, {41,42,43,44}, {45,46,47,48}
  45};
  46
  47int threads_starting;
  48int running;
  49
  50extern long preempt_vsx(vector int *varray, int *threads_starting, int *running);
  51
  52long vsx_memcmp(vector int *a) {
  53        vector int zero = {0, 0, 0, 0};
  54        int i;
  55
  56        FAIL_IF(a != varray);
  57
  58        for(i = 0; i < 12; i++) {
  59                if (memcmp(&a[i + 12], &zero, sizeof(vector int)) == 0) {
  60                        fprintf(stderr, "Detected zero from the VSX reg %d\n", i + 12);
  61                        return 2;
  62                }
  63        }
  64
  65        if (memcmp(a, &a[12], 12 * sizeof(vector int))) {
  66                long *p = (long *)a;
  67                fprintf(stderr, "VSX mismatch\n");
  68                for (i = 0; i < 24; i=i+2)
  69                        fprintf(stderr, "%d: 0x%08lx%08lx | 0x%08lx%08lx\n",
  70                                        i/2 + i%2 + 20, p[i], p[i + 1], p[i + 24], p[i + 25]);
  71                return 1;
  72        }
  73        return 0;
  74}
  75
  76void *preempt_vsx_c(void *p)
  77{
  78        int i, j;
  79        long rc;
  80        srand(pthread_self());
  81        for (i = 0; i < 12; i++)
  82                for (j = 0; j < 4; j++) {
  83                        varray[i][j] = rand();
  84                        /* Don't want zero because it hides kernel problems */
  85                        if (varray[i][j] == 0)
  86                                j--;
  87                }
  88        rc = preempt_vsx(varray, &threads_starting, &running);
  89        if (rc == 2)
  90                fprintf(stderr, "Caught zeros in VSX compares\n");
  91        return (void *)rc;
  92}
  93
  94int test_preempt_vsx(void)
  95{
  96        int i, rc, threads;
  97        pthread_t *tids;
  98
  99        threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
 100        tids = malloc(threads * sizeof(pthread_t));
 101        FAIL_IF(!tids);
 102
 103        running = true;
 104        threads_starting = threads;
 105        for (i = 0; i < threads; i++) {
 106                rc = pthread_create(&tids[i], NULL, preempt_vsx_c, NULL);
 107                FAIL_IF(rc);
 108        }
 109
 110        setbuf(stdout, NULL);
 111        /* Not really nessesary but nice to wait for every thread to start */
 112        printf("\tWaiting for %d workers to start...", threads_starting);
 113        while(threads_starting)
 114                asm volatile("": : :"memory");
 115        printf("done\n");
 116
 117        printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME);
 118        sleep(PREEMPT_TIME);
 119        printf("done\n");
 120
 121        printf("\tStopping workers...");
 122        /*
 123         * Working are checking this value every loop. In preempt_vsx 'cmpwi r5,0; bne 2b'.
 124         * r5 will have loaded the value of running.
 125         */
 126        running = 0;
 127        for (i = 0; i < threads; i++) {
 128                void *rc_p;
 129                pthread_join(tids[i], &rc_p);
 130
 131                /*
 132                 * Harness will say the fail was here, look at why preempt_vsx
 133                 * returned
 134                 */
 135                if ((long) rc_p)
 136                        printf("oops\n");
 137                FAIL_IF((long) rc_p);
 138        }
 139        printf("done\n");
 140
 141        return 0;
 142}
 143
 144int main(int argc, char *argv[])
 145{
 146        return test_harness(test_preempt_vsx, "vsx_preempt");
 147}
 148