1 /* 2 * RT signal roundtrip test software 3 * 4 * (C) 2007 Thomas Gleixner <tglx (at) linutronix.de> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License Veriosn 8 * 2 as published by the Free Software Foundation; 9 * 10 */ 11 12 #define VERSION_STRING "V 0.3" 13 14 #include <fcntl.h> 15 #include <getopt.h> 16 #include <pthread.h> 17 #include <signal.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <time.h> 22 #include <unistd.h> 23 24 #include <linux/unistd.h> 25 26 #include <sys/prctl.h> 27 #include <sys/stat.h> 28 #include <sys/types.h> 29 #include <sys/time.h> 30 31 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 32 33 /* Ugly, but .... */ 34 #define gettid() syscall(__NR_gettid) 35 36 #define USEC_PER_SEC 1000000 37 #define NSEC_PER_SEC 1000000000 38 39 /* Must be power of 2 ! */ 40 #define VALBUF_SIZE 16384 41 42 /* Struct to transfer parameters to the thread */ 43 struct thread_param { 44 int id; 45 int prio; 46 int signal; 47 unsigned long max_cycles; 48 struct thread_stat *stats; 49 int bufmsk; 50 }; 51 52 /* Struct for statistics */ 53 struct thread_stat { 54 unsigned long cycles; 55 unsigned long cyclesread; 56 long min; 57 long max; 58 long act; 59 double avg; 60 long *values; 61 pthread_t thread; 62 pthread_t tothread; 63 int threadstarted; 64 int tid; 65 }; 66 67 static int shutdown; 68 static int tracelimit = 0; 69 static int ftrace = 0; 70 static int oldtrace = 0; 71 72 static inline void tsnorm(struct timespec *ts) 73 { 74 while (ts->tv_nsec >= NSEC_PER_SEC) { 75 ts->tv_nsec -= NSEC_PER_SEC; 76 ts->tv_sec++; 77 } 78 } 79 80 static inline long calcdiff(struct timespec t1, struct timespec t2) 81 { 82 long diff; 83 diff = USEC_PER_SEC * ((int) t1.tv_sec - (int) t2.tv_sec); 84 diff += ((int) t1.tv_nsec - (int) t2.tv_nsec) / 1000; 85 return diff; 86 } 87 88 /* 89 * signal thread 90 * 91 */ 92 void *signalthread(void *param) 93 { 94 struct thread_param *par = param; 95 struct sched_param schedp; 96 sigset_t sigset; 97 struct timespec before, after; 98 struct thread_stat *stat = par->stats; 99 int policy = par->prio ? SCHED_FIFO : SCHED_OTHER; 100 int stopped = 0; 101 int first = 1; 102 103 if (tracelimit) { 104 system("echo 1 > /proc/sys/kernel/trace_all_cpus"); 105 system("echo 1 > /proc/sys/kernel/trace_freerunning"); 106 system("echo 0 > /proc/sys/kernel/trace_print_at_crash"); 107 system("echo 1 > /proc/sys/kernel/trace_user_triggered"); 108 system("echo -1 > /proc/sys/kernel/trace_user_trigger_irq"); 109 system("echo 0 > /proc/sys/kernel/trace_verbose"); 110 system("echo 0 > /proc/sys/kernel/preempt_thresh"); 111 system("echo 0 > /proc/sys/kernel/wakeup_timing"); 112 system("echo 0 > /proc/sys/kernel/preempt_max_latency"); 113 if (ftrace) 114 system("echo 1 > /proc/sys/kernel/mcount_enabled"); 115 116 system("echo 1 > /proc/sys/kernel/trace_enabled"); 117 } 118 119 stat->tid = gettid(); 120 121 sigemptyset(&sigset); 122 sigaddset(&sigset, par->signal); 123 sigprocmask(SIG_BLOCK, &sigset, NULL); 124 125 memset(&schedp, 0, sizeof(schedp)); 126 schedp.sched_priority = par->prio; 127 sched_setscheduler(0, policy, &schedp); 128 129 stat->threadstarted++; 130 131 if (tracelimit) { 132 if (oldtrace) 133 gettimeofday(0,(struct timezone *)1); 134 else 135 prctl(0, 1); 136 } 137 138 clock_gettime(CLOCK_MONOTONIC, &before); 139 140 while (!shutdown) { 141 struct timespec now; 142 long diff; 143 int sigs; 144 145 if (sigwait(&sigset, &sigs) < 0) 146 goto out; 147 148 clock_gettime(CLOCK_MONOTONIC, &after); 149 150 /* 151 * If it is the first thread, sleep after every 16 152 * round trips. 153 */ 154 if (!par->id && !(stat->cycles & 0x0F)) 155 usleep(10000); 156 157 /* Get current time */ 158 clock_gettime(CLOCK_MONOTONIC, &now); 159 pthread_kill(stat->tothread, SIGUSR1); 160 161 /* Skip the first cycle */ 162 if (first) { 163 first = 0; 164 before = now; 165 continue; 166 } 167 168 diff = calcdiff(after, before); 169 before = now; 170 if (diff < stat->min) 171 stat->min = diff; 172 if (diff > stat->max) 173 stat->max = diff; 174 stat->avg += (double) diff; 175 176 if (!stopped && tracelimit && (diff > tracelimit)) { 177 stopped++; 178 if (oldtrace) 179 gettimeofday(0,0); 180 else 181 prctl(0, 0); 182 shutdown++; 183 } 184 stat->act = diff; 185 stat->cycles++; 186 187 if (par->bufmsk) 188 stat->values[stat->cycles & par->bufmsk] = diff; 189 190 if (par->max_cycles && par->max_cycles == stat->cycles) 191 break; 192 } 193 194 out: 195 /* switch to normal */ 196 schedp.sched_priority = 0; 197 sched_setscheduler(0, SCHED_OTHER, &schedp); 198 199 stat->threadstarted = -1; 200 201 return NULL; 202 } 203 204 205 /* Print usage information */ 206 static void display_help(void) 207 { 208 printf("signaltest %s\n", VERSION_STRING); 209 printf("Usage:\n" 210 "signaltest <options>\n\n" 211 "-b USEC --breaktrace=USEC send break trace command when latency > USEC\n" 212 "-f function trace (when -b is active)\n" 213 "-l LOOPS --loops=LOOPS number of loops: default=0(endless)\n" 214 "-p PRIO --prio=PRIO priority of highest prio thread\n" 215 "-q --quiet print only a summary on exit\n" 216 "-t NUM --threads=NUM number of threads: default=2\n" 217 "-v --verbose output values on stdout for statistics\n" 218 " format: n:c:v n=tasknum c=count v=value in us\n"); 219 exit(0); 220 } 221 222 static int priority; 223 static int num_threads = 2; 224 static int max_cycles; 225 static int verbose; 226 static int quiet; 227 228 /* Process commandline options */ 229 static void process_options (int argc, char *argv[]) 230 { 231 int error = 0; 232 for (;;) { 233 int option_index = 0; 234 /** Options for getopt */ 235 static struct option long_options[] = { 236 {"breaktrace", required_argument, NULL, 'b'}, 237 {"ftrace", no_argument, NULL, 'f'}, 238 {"loops", required_argument, NULL, 'l'}, 239 {"priority", required_argument, NULL, 'p'}, 240 {"quiet", no_argument, NULL, 'q'}, 241 {"threads", required_argument, NULL, 't'}, 242 {"verbose", no_argument, NULL, 'v'}, 243 {"help", no_argument, NULL, '?'}, 244 {NULL, 0, NULL, 0} 245 }; 246 int c = getopt_long (argc, argv, "b:fl:p:qt:v", 247 long_options, &option_index); 248 if (c == -1) 249 break; 250 switch (c) { 251 case 'b': tracelimit = atoi(optarg); break; 252 case 'l': max_cycles = atoi(optarg); break; 253 case 'p': priority = atoi(optarg); break; 254 case 'q': quiet = 1; break; 255 case 't': num_threads = atoi(optarg); break; 256 case 'v': verbose = 1; break; 257 case '?': error = 1; break; 258 } 259 } 260 261 if (priority < 0 || priority > 99) 262 error = 1; 263 264 if (num_threads < 2) 265 error = 1; 266 267 if (error) 268 display_help (); 269 } 270 271 static void check_kernel(void) 272 { 273 size_t len; 274 char ver[256]; 275 int fd, maj, min, sub; 276 277 fd = open("/proc/version", O_RDONLY, 0666); 278 len = read(fd, ver, 255); 279 close(fd); 280 ver[len-1] = 0x0; 281 sscanf(ver, "Linux version %d.%d.%d", &maj, &min, &sub); 282 if (maj == 2 && min == 6 && sub < 18) 283 oldtrace = 1; 284 } 285 286 static void sighand(int sig) 287 { 288 shutdown = 1; 289 } 290 291 static void print_stat(struct thread_param *par, int index, int verbose) 292 { 293 struct thread_stat *stat = par->stats; 294 295 if (!verbose) { 296 if (quiet != 1) { 297 printf("T:%2d (%5d) P:%2d C:%7lu " 298 "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld\n", 299 index, stat->tid, par->prio, 300 stat->cycles, stat->min, stat->act, 301 stat->cycles ? 302 (long)(stat->avg/stat->cycles) : 0, stat->max); 303 } 304 } else { 305 while (stat->cycles != stat->cyclesread) { 306 long diff = stat->values[stat->cyclesread & par->bufmsk]; 307 printf("%8d:%8lu:%8ld\n", index, stat->cyclesread, diff); 308 stat->cyclesread++; 309 } 310 } 311 } 312 313 int main(int argc, char **argv) 314 { 315 sigset_t sigset; 316 int signum = SIGUSR1; 317 struct thread_param *par; 318 struct thread_stat *stat; 319 int i, ret = -1; 320 321 if (geteuid()) { 322 printf("need to run as root!\n"); 323 exit(-1); 324 } 325 326 process_options(argc, argv); 327 328 check_kernel(); 329 330 sigemptyset(&sigset); 331 sigaddset(&sigset, signum); 332 sigprocmask (SIG_BLOCK, &sigset, NULL); 333 334 signal(SIGINT, sighand); 335 signal(SIGTERM, sighand); 336 337 par = calloc(num_threads, sizeof(struct thread_param)); 338 if (!par) 339 goto out; 340 stat = calloc(num_threads, sizeof(struct thread_stat)); 341 if (!stat) 342 goto outpar; 343 344 for (i = 0; i < num_threads; i++) { 345 if (verbose) { 346 stat[i].values = calloc(VALBUF_SIZE, sizeof(long)); 347 if (!stat[i].values) 348 goto outall; 349 par[i].bufmsk = VALBUF_SIZE - 1; 350 } 351 352 par[i].id = i; 353 par[i].prio = priority; 354 #if 0 355 if (priority) 356 priority--; 357 #endif 358 par[i].signal = signum; 359 par[i].max_cycles = max_cycles; 360 par[i].stats = &stat[i]; 361 stat[i].min = 1000000; 362 stat[i].max = -1000000; 363 stat[i].avg = 0.0; 364 stat[i].threadstarted = 1; 365 pthread_create(&stat[i].thread, NULL, signalthread, &par[i]); 366 } 367 368 while (!shutdown) { 369 int allstarted = 1; 370 371 for (i = 0; i < num_threads; i++) { 372 if (stat[i].threadstarted != 2) 373 allstarted = 0; 374 } 375 if (!allstarted) 376 continue; 377 378 for (i = 0; i < num_threads - 1; i++) 379 stat[i].tothread = stat[i+1].thread; 380 stat[i].tothread = stat[0].thread; 381 break; 382 } 383 pthread_kill(stat[0].thread, signum); 384 385 while (!shutdown) { 386 char lavg[256]; 387 int fd, len, allstopped = 0; 388 389 if (!verbose && !quiet) { 390 fd = open("/proc/loadavg", O_RDONLY, 0666); 391 len = read(fd, &lavg, 255); 392 close(fd); 393 lavg[len-1] = 0x0; 394 printf("%s \n\n", lavg); 395 } 396 397 print_stat(&par[0], 0, verbose); 398 if(max_cycles && stat[0].cycles >= max_cycles) 399 allstopped++; 400 401 usleep(10000); 402 if (shutdown || allstopped) 403 break; 404 if (!verbose && !quiet) 405 printf("\033[%dA", 3); 406 } 407 ret = 0; 408 outall: 409 shutdown = 1; 410 usleep(50000); 411 if (quiet) 412 quiet = 2; 413 for (i = 0; i < num_threads; i++) { 414 if (stat[i].threadstarted > 0) 415 pthread_kill(stat[i].thread, SIGTERM); 416 if (stat[i].threadstarted) { 417 pthread_join(stat[i].thread, NULL); 418 if (quiet) 419 print_stat(&par[i], i, 0); 420 } 421 if (stat[i].values) 422 free(stat[i].values); 423 } 424 free(stat); 425 outpar: 426 free(par); 427 out: 428 exit(ret); 429 } 430