linux/tools/testing/selftests/timers/posix_timers.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
   3 *
   4 * Licensed under the terms of the GNU GPL License version 2
   5 *
   6 * Selftests for a few posix timers interface.
   7 *
   8 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
   9 */
  10
  11#include <sys/time.h>
  12#include <stdio.h>
  13#include <signal.h>
  14#include <unistd.h>
  15#include <time.h>
  16#include <pthread.h>
  17
  18#define DELAY 2
  19#define USECS_PER_SEC 1000000
  20
  21static volatile int done;
  22
  23/* Busy loop in userspace to elapse ITIMER_VIRTUAL */
  24static void user_loop(void)
  25{
  26        while (!done);
  27}
  28
  29/*
  30 * Try to spend as much time as possible in kernelspace
  31 * to elapse ITIMER_PROF.
  32 */
  33static void kernel_loop(void)
  34{
  35        void *addr = sbrk(0);
  36
  37        while (!done) {
  38                brk(addr + 4096);
  39                brk(addr);
  40        }
  41}
  42
  43/*
  44 * Sleep until ITIMER_REAL expiration.
  45 */
  46static void idle_loop(void)
  47{
  48        pause();
  49}
  50
  51static void sig_handler(int nr)
  52{
  53        done = 1;
  54}
  55
  56/*
  57 * Check the expected timer expiration matches the GTOD elapsed delta since
  58 * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
  59 */
  60static int check_diff(struct timeval start, struct timeval end)
  61{
  62        long long diff;
  63
  64        diff = end.tv_usec - start.tv_usec;
  65        diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
  66
  67        if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
  68                printf("Diff too high: %lld..", diff);
  69                return -1;
  70        }
  71
  72        return 0;
  73}
  74
  75static int check_itimer(int which)
  76{
  77        int err;
  78        struct timeval start, end;
  79        struct itimerval val = {
  80                .it_value.tv_sec = DELAY,
  81        };
  82
  83        printf("Check itimer ");
  84
  85        if (which == ITIMER_VIRTUAL)
  86                printf("virtual... ");
  87        else if (which == ITIMER_PROF)
  88                printf("prof... ");
  89        else if (which == ITIMER_REAL)
  90                printf("real... ");
  91
  92        fflush(stdout);
  93
  94        done = 0;
  95
  96        if (which == ITIMER_VIRTUAL)
  97                signal(SIGVTALRM, sig_handler);
  98        else if (which == ITIMER_PROF)
  99                signal(SIGPROF, sig_handler);
 100        else if (which == ITIMER_REAL)
 101                signal(SIGALRM, sig_handler);
 102
 103        err = gettimeofday(&start, NULL);
 104        if (err < 0) {
 105                perror("Can't call gettimeofday()\n");
 106                return -1;
 107        }
 108
 109        err = setitimer(which, &val, NULL);
 110        if (err < 0) {
 111                perror("Can't set timer\n");
 112                return -1;
 113        }
 114
 115        if (which == ITIMER_VIRTUAL)
 116                user_loop();
 117        else if (which == ITIMER_PROF)
 118                kernel_loop();
 119        else if (which == ITIMER_REAL)
 120                idle_loop();
 121
 122        gettimeofday(&end, NULL);
 123        if (err < 0) {
 124                perror("Can't call gettimeofday()\n");
 125                return -1;
 126        }
 127
 128        if (!check_diff(start, end))
 129                printf("[OK]\n");
 130        else
 131                printf("[FAIL]\n");
 132
 133        return 0;
 134}
 135
 136static int check_timer_create(int which)
 137{
 138        int err;
 139        timer_t id;
 140        struct timeval start, end;
 141        struct itimerspec val = {
 142                .it_value.tv_sec = DELAY,
 143        };
 144
 145        printf("Check timer_create() ");
 146        if (which == CLOCK_THREAD_CPUTIME_ID) {
 147                printf("per thread... ");
 148        } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
 149                printf("per process... ");
 150        }
 151        fflush(stdout);
 152
 153        done = 0;
 154        err = timer_create(which, NULL, &id);
 155        if (err < 0) {
 156                perror("Can't create timer\n");
 157                return -1;
 158        }
 159        signal(SIGALRM, sig_handler);
 160
 161        err = gettimeofday(&start, NULL);
 162        if (err < 0) {
 163                perror("Can't call gettimeofday()\n");
 164                return -1;
 165        }
 166
 167        err = timer_settime(id, 0, &val, NULL);
 168        if (err < 0) {
 169                perror("Can't set timer\n");
 170                return -1;
 171        }
 172
 173        user_loop();
 174
 175        gettimeofday(&end, NULL);
 176        if (err < 0) {
 177                perror("Can't call gettimeofday()\n");
 178                return -1;
 179        }
 180
 181        if (!check_diff(start, end))
 182                printf("[OK]\n");
 183        else
 184                printf("[FAIL]\n");
 185
 186        return 0;
 187}
 188
 189int main(int argc, char **argv)
 190{
 191        int err;
 192
 193        printf("Testing posix timers. False negative may happen on CPU execution \n");
 194        printf("based timers if other threads run on the CPU...\n");
 195
 196        if (check_itimer(ITIMER_VIRTUAL) < 0)
 197                return -1;
 198
 199        if (check_itimer(ITIMER_PROF) < 0)
 200                return -1;
 201
 202        if (check_itimer(ITIMER_REAL) < 0)
 203                return -1;
 204
 205        if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
 206                return -1;
 207
 208        /*
 209         * It's unfortunately hard to reliably test a timer expiration
 210         * on parallel multithread cputime. We could arm it to expire
 211         * on DELAY * nr_threads, with nr_threads busy looping, then wait
 212         * the normal DELAY since the time is elapsing nr_threads faster.
 213         * But for that we need to ensure we have real physical free CPUs
 214         * to ensure true parallelism. So test only one thread until we
 215         * find a better solution.
 216         */
 217        if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
 218                return -1;
 219
 220        return 0;
 221}
 222