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 21 static volatile int done; 22 23 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */ 24 static 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 */ 33 static 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 */ 46 static void idle_loop(void) 47 { 48 pause(); 49 } 50 51 static 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 */ 60 static 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 75 static 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 136 static 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 189 int 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