1 /* 2 * This application is Copyright 2012 Red Hat, Inc. 3 * Doug Ledford <dledford@redhat.com> 4 * 5 * mq_perf_tests is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, version 3. 8 * 9 * mq_perf_tests is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * For the full text of the license, see <http://www.gnu.org/licenses/>. 15 * 16 * mq_perf_tests.c 17 * Tests various types of message queue workloads, concentrating on those 18 * situations that invole large message sizes, large message queue depths, 19 * or both, and reports back useful metrics about kernel message queue 20 * performance. 21 * 22 */ 23 #define _GNU_SOURCE 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 #include <fcntl.h> 28 #include <string.h> 29 #include <limits.h> 30 #include <errno.h> 31 #include <signal.h> 32 #include <pthread.h> 33 #include <sched.h> 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <sys/resource.h> 37 #include <sys/stat.h> 38 #include <mqueue.h> 39 #include <popt.h> 40 41 static char *usage = 42 "Usage:\n" 43 " %s [-c #[,#..] -f] path\n" 44 "\n" 45 " -c # Skip most tests and go straight to a high queue depth test\n" 46 " and then run that test continuously (useful for running at\n" 47 " the same time as some other workload to see how much the\n" 48 " cache thrashing caused by adding messages to a very deep\n" 49 " queue impacts the performance of other programs). The number\n" 50 " indicates which CPU core we should bind the process to during\n" 51 " the run. If you have more than one physical CPU, then you\n" 52 " will need one copy per physical CPU package, and you should\n" 53 " specify the CPU cores to pin ourself to via a comma separated\n" 54 " list of CPU values.\n" 55 " -f Only usable with continuous mode. Pin ourself to the CPUs\n" 56 " as requested, then instead of looping doing a high mq\n" 57 " workload, just busy loop. This will allow us to lock up a\n" 58 " single CPU just like we normally would, but without actually\n" 59 " thrashing the CPU cache. This is to make it easier to get\n" 60 " comparable numbers from some other workload running on the\n" 61 " other CPUs. One set of numbers with # CPUs locked up running\n" 62 " an mq workload, and another set of numbers with those same\n" 63 " CPUs locked away from the test workload, but not doing\n" 64 " anything to trash the cache like the mq workload might.\n" 65 " path Path name of the message queue to create\n" 66 "\n" 67 " Note: this program must be run as root in order to enable all tests\n" 68 "\n"; 69 70 char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; 71 char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; 72 73 #define min(a, b) ((a) < (b) ? (a) : (b)) 74 #define MAX_CPUS 64 75 char *cpu_option_string; 76 int cpus_to_pin[MAX_CPUS]; 77 int num_cpus_to_pin; 78 pthread_t cpu_threads[MAX_CPUS]; 79 pthread_t main_thread; 80 cpu_set_t *cpu_set; 81 int cpu_set_size; 82 int cpus_online; 83 84 #define MSG_SIZE 16 85 #define TEST1_LOOPS 10000000 86 #define TEST2_LOOPS 100000 87 int continuous_mode; 88 int continuous_mode_fake; 89 90 struct rlimit saved_limits, cur_limits; 91 int saved_max_msgs, saved_max_msgsize; 92 int cur_max_msgs, cur_max_msgsize; 93 FILE *max_msgs, *max_msgsize; 94 int cur_nice; 95 char *queue_path = "/mq_perf_tests"; 96 mqd_t queue = -1; 97 struct mq_attr result; 98 int mq_prio_max; 99 100 const struct poptOption options[] = { 101 { 102 .longName = "continuous", 103 .shortName = 'c', 104 .argInfo = POPT_ARG_STRING, 105 .arg = &cpu_option_string, 106 .val = 'c', 107 .descrip = "Run continuous tests at a high queue depth in " 108 "order to test the effects of cache thrashing on " 109 "other tasks on the system. This test is intended " 110 "to be run on one core of each physical CPU while " 111 "some other CPU intensive task is run on all the other " 112 "cores of that same physical CPU and the other task " 113 "is timed. It is assumed that the process of adding " 114 "messages to the message queue in a tight loop will " 115 "impact that other task to some degree. Once the " 116 "tests are performed in this way, you should then " 117 "re-run the tests using fake mode in order to check " 118 "the difference in time required to perform the CPU " 119 "intensive task", 120 .argDescrip = "cpu[,cpu]", 121 }, 122 { 123 .longName = "fake", 124 .shortName = 'f', 125 .argInfo = POPT_ARG_NONE, 126 .arg = &continuous_mode_fake, 127 .val = 0, 128 .descrip = "Tie up the CPUs that we would normally tie up in" 129 "continuous mode, but don't actually do any mq stuff, " 130 "just keep the CPU busy so it can't be used to process " 131 "system level tasks as this would free up resources on " 132 "the other CPU cores and skew the comparison between " 133 "the no-mqueue work and mqueue work tests", 134 .argDescrip = NULL, 135 }, 136 { 137 .longName = "path", 138 .shortName = 'p', 139 .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, 140 .arg = &queue_path, 141 .val = 'p', 142 .descrip = "The name of the path to use in the mqueue " 143 "filesystem for our tests", 144 .argDescrip = "pathname", 145 }, 146 POPT_AUTOHELP 147 POPT_TABLEEND 148 }; 149 150 static inline void __set(FILE *stream, int value, char *err_msg); 151 void shutdown(int exit_val, char *err_cause, int line_no); 152 void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context); 153 void sig_action(int signum, siginfo_t *info, void *context); 154 static inline int get(FILE *stream); 155 static inline void set(FILE *stream, int value); 156 static inline int try_set(FILE *stream, int value); 157 static inline void getr(int type, struct rlimit *rlim); 158 static inline void setr(int type, struct rlimit *rlim); 159 static inline void open_queue(struct mq_attr *attr); 160 void increase_limits(void); 161 162 static inline void __set(FILE *stream, int value, char *err_msg) 163 { 164 rewind(stream); 165 if (fprintf(stream, "%d", value) < 0) 166 perror(err_msg); 167 } 168 169 170 void shutdown(int exit_val, char *err_cause, int line_no) 171 { 172 static int in_shutdown = 0; 173 int errno_at_shutdown = errno; 174 int i; 175 176 /* In case we get called by multiple threads or from an sighandler */ 177 if (in_shutdown++) 178 return; 179 180 for (i = 0; i < num_cpus_to_pin; i++) 181 if (cpu_threads[i]) { 182 pthread_kill(cpu_threads[i], SIGUSR1); 183 pthread_join(cpu_threads[i], NULL); 184 } 185 186 if (queue != -1) 187 if (mq_close(queue)) 188 perror("mq_close() during shutdown"); 189 if (queue_path) 190 /* 191 * Be silent if this fails, if we cleaned up already it's 192 * expected to fail 193 */ 194 mq_unlink(queue_path); 195 if (saved_max_msgs) 196 __set(max_msgs, saved_max_msgs, 197 "failed to restore saved_max_msgs"); 198 if (saved_max_msgsize) 199 __set(max_msgsize, saved_max_msgsize, 200 "failed to restore saved_max_msgsize"); 201 if (exit_val) 202 error(exit_val, errno_at_shutdown, "%s at %d", 203 err_cause, line_no); 204 exit(0); 205 } 206 207 void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context) 208 { 209 if (pthread_self() != main_thread) 210 pthread_exit(0); 211 else { 212 fprintf(stderr, "Caught signal %d in SIGUSR1 handler, " 213 "exiting\n", signum); 214 shutdown(0, "", 0); 215 fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); 216 exit(0); 217 } 218 } 219 220 void sig_action(int signum, siginfo_t *info, void *context) 221 { 222 if (pthread_self() != main_thread) 223 pthread_kill(main_thread, signum); 224 else { 225 fprintf(stderr, "Caught signal %d, exiting\n", signum); 226 shutdown(0, "", 0); 227 fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); 228 exit(0); 229 } 230 } 231 232 static inline int get(FILE *stream) 233 { 234 int value; 235 rewind(stream); 236 if (fscanf(stream, "%d", &value) != 1) 237 shutdown(4, "Error reading /proc entry", __LINE__); 238 return value; 239 } 240 241 static inline void set(FILE *stream, int value) 242 { 243 int new_value; 244 245 rewind(stream); 246 if (fprintf(stream, "%d", value) < 0) 247 return shutdown(5, "Failed writing to /proc file", __LINE__); 248 new_value = get(stream); 249 if (new_value != value) 250 return shutdown(5, "We didn't get what we wrote to /proc back", 251 __LINE__); 252 } 253 254 static inline int try_set(FILE *stream, int value) 255 { 256 int new_value; 257 258 rewind(stream); 259 fprintf(stream, "%d", value); 260 new_value = get(stream); 261 return new_value == value; 262 } 263 264 static inline void getr(int type, struct rlimit *rlim) 265 { 266 if (getrlimit(type, rlim)) 267 shutdown(6, "getrlimit()", __LINE__); 268 } 269 270 static inline void setr(int type, struct rlimit *rlim) 271 { 272 if (setrlimit(type, rlim)) 273 shutdown(7, "setrlimit()", __LINE__); 274 } 275 276 /** 277 * open_queue - open the global queue for testing 278 * @attr - An attr struct specifying the desired queue traits 279 * @result - An attr struct that lists the actual traits the queue has 280 * 281 * This open is not allowed to fail, failure will result in an orderly 282 * shutdown of the program. The global queue_path is used to set what 283 * queue to open, the queue descriptor is saved in the global queue 284 * variable. 285 */ 286 static inline void open_queue(struct mq_attr *attr) 287 { 288 int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK; 289 int perms = DEFFILEMODE; 290 291 queue = mq_open(queue_path, flags, perms, attr); 292 if (queue == -1) 293 shutdown(1, "mq_open()", __LINE__); 294 if (mq_getattr(queue, &result)) 295 shutdown(1, "mq_getattr()", __LINE__); 296 printf("\n\tQueue %s created:\n", queue_path); 297 printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ? 298 "O_NONBLOCK" : "(null)"); 299 printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg); 300 printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize); 301 printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs); 302 } 303 304 void *fake_cont_thread(void *arg) 305 { 306 int i; 307 308 for (i = 0; i < num_cpus_to_pin; i++) 309 if (cpu_threads[i] == pthread_self()) 310 break; 311 printf("\tStarted fake continuous mode thread %d on CPU %d\n", i, 312 cpus_to_pin[i]); 313 while (1) 314 ; 315 } 316 317 void *cont_thread(void *arg) 318 { 319 char buff[MSG_SIZE]; 320 int i, priority; 321 322 for (i = 0; i < num_cpus_to_pin; i++) 323 if (cpu_threads[i] == pthread_self()) 324 break; 325 printf("\tStarted continuous mode thread %d on CPU %d\n", i, 326 cpus_to_pin[i]); 327 while (1) { 328 while (mq_send(queue, buff, sizeof(buff), 0) == 0) 329 ; 330 mq_receive(queue, buff, sizeof(buff), &priority); 331 } 332 } 333 334 #define drain_queue() \ 335 while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE) 336 337 #define do_untimed_send() \ 338 do { \ 339 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ 340 shutdown(3, "Test send failure", __LINE__); \ 341 } while (0) 342 343 #define do_send_recv() \ 344 do { \ 345 clock_gettime(clock, &start); \ 346 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ 347 shutdown(3, "Test send failure", __LINE__); \ 348 clock_gettime(clock, &middle); \ 349 if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \ 350 shutdown(3, "Test receive failure", __LINE__); \ 351 clock_gettime(clock, &end); \ 352 nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \ 353 (middle.tv_nsec - start.tv_nsec); \ 354 send_total.tv_nsec += nsec; \ 355 if (send_total.tv_nsec >= 1000000000) { \ 356 send_total.tv_sec++; \ 357 send_total.tv_nsec -= 1000000000; \ 358 } \ 359 nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \ 360 (end.tv_nsec - middle.tv_nsec); \ 361 recv_total.tv_nsec += nsec; \ 362 if (recv_total.tv_nsec >= 1000000000) { \ 363 recv_total.tv_sec++; \ 364 recv_total.tv_nsec -= 1000000000; \ 365 } \ 366 } while (0) 367 368 struct test { 369 char *desc; 370 void (*func)(int *); 371 }; 372 373 void const_prio(int *prio) 374 { 375 return; 376 } 377 378 void inc_prio(int *prio) 379 { 380 if (++*prio == mq_prio_max) 381 *prio = 0; 382 } 383 384 void dec_prio(int *prio) 385 { 386 if (--*prio < 0) 387 *prio = mq_prio_max - 1; 388 } 389 390 void random_prio(int *prio) 391 { 392 *prio = random() % mq_prio_max; 393 } 394 395 struct test test2[] = { 396 {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n", 397 const_prio}, 398 {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n", 399 inc_prio}, 400 {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n", 401 dec_prio}, 402 {"\n\tTest #2d: Time send/recv message, queue full, random prio\n", 403 random_prio}, 404 {NULL, NULL} 405 }; 406 407 /** 408 * Tests to perform (all done with MSG_SIZE messages): 409 * 410 * 1) Time to add/remove message with 0 messages on queue 411 * 1a) with constant prio 412 * 2) Time to add/remove message when queue close to capacity: 413 * 2a) with constant prio 414 * 2b) with increasing prio 415 * 2c) with decreasing prio 416 * 2d) with random prio 417 * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX) 418 */ 419 void *perf_test_thread(void *arg) 420 { 421 char buff[MSG_SIZE]; 422 int prio_out, prio_in; 423 int i; 424 clockid_t clock; 425 pthread_t *t; 426 struct timespec res, start, middle, end, send_total, recv_total; 427 unsigned long long nsec; 428 struct test *cur_test; 429 430 t = &cpu_threads[0]; 431 printf("\n\tStarted mqueue performance test thread on CPU %d\n", 432 cpus_to_pin[0]); 433 mq_prio_max = sysconf(_SC_MQ_PRIO_MAX); 434 if (mq_prio_max == -1) 435 shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__); 436 if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0) 437 shutdown(2, "pthread_getcpuclockid", __LINE__); 438 439 if (clock_getres(clock, &res)) 440 shutdown(2, "clock_getres()", __LINE__); 441 442 printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max); 443 printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec, 444 res.tv_nsec > 1 ? "s" : ""); 445 446 447 448 printf("\n\tTest #1: Time send/recv message, queue empty\n"); 449 printf("\t\t(%d iterations)\n", TEST1_LOOPS); 450 prio_out = 0; 451 send_total.tv_sec = 0; 452 send_total.tv_nsec = 0; 453 recv_total.tv_sec = 0; 454 recv_total.tv_nsec = 0; 455 for (i = 0; i < TEST1_LOOPS; i++) 456 do_send_recv(); 457 printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", 458 send_total.tv_sec, send_total.tv_nsec); 459 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + 460 send_total.tv_nsec) / TEST1_LOOPS; 461 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 462 printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", 463 recv_total.tv_sec, recv_total.tv_nsec); 464 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + 465 recv_total.tv_nsec) / TEST1_LOOPS; 466 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 467 468 469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) { 470 printf("%s:\n", cur_test->desc); 471 printf("\t\t(%d iterations)\n", TEST2_LOOPS); 472 prio_out = 0; 473 send_total.tv_sec = 0; 474 send_total.tv_nsec = 0; 475 recv_total.tv_sec = 0; 476 recv_total.tv_nsec = 0; 477 printf("\t\tFilling queue..."); 478 fflush(stdout); 479 clock_gettime(clock, &start); 480 for (i = 0; i < result.mq_maxmsg - 1; i++) { 481 do_untimed_send(); 482 cur_test->func(&prio_out); 483 } 484 clock_gettime(clock, &end); 485 nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * 486 1000000000) + (end.tv_nsec - start.tv_nsec); 487 printf("done.\t\t%lld.%llds\n", nsec / 1000000000, 488 nsec % 1000000000); 489 printf("\t\tTesting..."); 490 fflush(stdout); 491 for (i = 0; i < TEST2_LOOPS; i++) { 492 do_send_recv(); 493 cur_test->func(&prio_out); 494 } 495 printf("done.\n"); 496 printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", 497 send_total.tv_sec, send_total.tv_nsec); 498 nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + 499 send_total.tv_nsec) / TEST2_LOOPS; 500 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 501 printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", 502 recv_total.tv_sec, recv_total.tv_nsec); 503 nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + 504 recv_total.tv_nsec) / TEST2_LOOPS; 505 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); 506 printf("\t\tDraining queue..."); 507 fflush(stdout); 508 clock_gettime(clock, &start); 509 drain_queue(); 510 clock_gettime(clock, &end); 511 nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * 512 1000000000) + (end.tv_nsec - start.tv_nsec); 513 printf("done.\t\t%lld.%llds\n", nsec / 1000000000, 514 nsec % 1000000000); 515 } 516 return 0; 517 } 518 519 void increase_limits(void) 520 { 521 cur_limits.rlim_cur = RLIM_INFINITY; 522 cur_limits.rlim_max = RLIM_INFINITY; 523 setr(RLIMIT_MSGQUEUE, &cur_limits); 524 while (try_set(max_msgs, cur_max_msgs += 10)) 525 ; 526 cur_max_msgs = get(max_msgs); 527 while (try_set(max_msgsize, cur_max_msgsize += 1024)) 528 ; 529 cur_max_msgsize = get(max_msgsize); 530 if (setpriority(PRIO_PROCESS, 0, -20) != 0) 531 shutdown(2, "setpriority()", __LINE__); 532 cur_nice = -20; 533 } 534 535 int main(int argc, char *argv[]) 536 { 537 struct mq_attr attr; 538 char *option, *next_option; 539 int i, cpu, rc; 540 struct sigaction sa; 541 poptContext popt_context; 542 void *retval; 543 544 main_thread = pthread_self(); 545 num_cpus_to_pin = 0; 546 547 if (sysconf(_SC_NPROCESSORS_ONLN) == -1) { 548 perror("sysconf(_SC_NPROCESSORS_ONLN)"); 549 exit(1); 550 } 551 cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN)); 552 cpu_set = CPU_ALLOC(cpus_online); 553 if (cpu_set == NULL) { 554 perror("CPU_ALLOC()"); 555 exit(1); 556 } 557 cpu_set_size = CPU_ALLOC_SIZE(cpus_online); 558 CPU_ZERO_S(cpu_set_size, cpu_set); 559 560 popt_context = poptGetContext(NULL, argc, (const char **)argv, 561 options, 0); 562 563 while ((rc = poptGetNextOpt(popt_context)) > 0) { 564 switch (rc) { 565 case 'c': 566 continuous_mode = 1; 567 option = cpu_option_string; 568 do { 569 next_option = strchr(option, ','); 570 if (next_option) 571 *next_option = '\0'; 572 cpu = atoi(option); 573 if (cpu >= cpus_online) 574 fprintf(stderr, "CPU %d exceeds " 575 "cpus online, ignoring.\n", 576 cpu); 577 else 578 cpus_to_pin[num_cpus_to_pin++] = cpu; 579 if (next_option) 580 option = ++next_option; 581 } while (next_option && num_cpus_to_pin < MAX_CPUS); 582 /* Double check that they didn't give us the same CPU 583 * more than once */ 584 for (cpu = 0; cpu < num_cpus_to_pin; cpu++) { 585 if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size, 586 cpu_set)) { 587 fprintf(stderr, "Any given CPU may " 588 "only be given once.\n"); 589 exit(1); 590 } else 591 CPU_SET_S(cpus_to_pin[cpu], 592 cpu_set_size, cpu_set); 593 } 594 break; 595 case 'p': 596 /* 597 * Although we can create a msg queue with a 598 * non-absolute path name, unlink will fail. So, 599 * if the name doesn't start with a /, add one 600 * when we save it. 601 */ 602 option = queue_path; 603 if (*option != '/') { 604 queue_path = malloc(strlen(option) + 2); 605 if (!queue_path) { 606 perror("malloc()"); 607 exit(1); 608 } 609 queue_path[0] = '/'; 610 queue_path[1] = 0; 611 strcat(queue_path, option); 612 free(option); 613 } 614 break; 615 } 616 } 617 618 if (continuous_mode && num_cpus_to_pin == 0) { 619 fprintf(stderr, "Must pass at least one CPU to continuous " 620 "mode.\n"); 621 poptPrintUsage(popt_context, stderr, 0); 622 exit(1); 623 } else if (!continuous_mode) { 624 num_cpus_to_pin = 1; 625 cpus_to_pin[0] = cpus_online - 1; 626 } 627 628 if (getuid() != 0) { 629 fprintf(stderr, "Not running as root, but almost all tests " 630 "require root in order to modify\nsystem settings. " 631 "Exiting.\n"); 632 exit(1); 633 } 634 635 max_msgs = fopen(MAX_MSGS, "r+"); 636 max_msgsize = fopen(MAX_MSGSIZE, "r+"); 637 if (!max_msgs) 638 shutdown(2, "Failed to open msg_max", __LINE__); 639 if (!max_msgsize) 640 shutdown(2, "Failed to open msgsize_max", __LINE__); 641 642 /* Load up the current system values for everything we can */ 643 getr(RLIMIT_MSGQUEUE, &saved_limits); 644 cur_limits = saved_limits; 645 saved_max_msgs = cur_max_msgs = get(max_msgs); 646 saved_max_msgsize = cur_max_msgsize = get(max_msgsize); 647 errno = 0; 648 cur_nice = getpriority(PRIO_PROCESS, 0); 649 if (errno) 650 shutdown(2, "getpriority()", __LINE__); 651 652 /* Tell the user our initial state */ 653 printf("\nInitial system state:\n"); 654 printf("\tUsing queue path:\t\t\t%s\n", queue_path); 655 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", 656 (long) saved_limits.rlim_cur); 657 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", 658 (long) saved_limits.rlim_max); 659 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize); 660 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs); 661 printf("\tNice value:\t\t\t\t%d\n", cur_nice); 662 printf("\n"); 663 664 increase_limits(); 665 666 printf("Adjusted system state for testing:\n"); 667 if (cur_limits.rlim_cur == RLIM_INFINITY) { 668 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n"); 669 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n"); 670 } else { 671 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", 672 (long) cur_limits.rlim_cur); 673 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", 674 (long) cur_limits.rlim_max); 675 } 676 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize); 677 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs); 678 printf("\tNice value:\t\t\t\t%d\n", cur_nice); 679 printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ? 680 (continuous_mode_fake ? "fake mode" : "enabled") : 681 "disabled"); 682 printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]); 683 for (cpu = 1; cpu < num_cpus_to_pin; cpu++) 684 printf(",%d", cpus_to_pin[cpu]); 685 printf("\n"); 686 687 sa.sa_sigaction = sig_action_SIGUSR1; 688 sigemptyset(&sa.sa_mask); 689 sigaddset(&sa.sa_mask, SIGHUP); 690 sigaddset(&sa.sa_mask, SIGINT); 691 sigaddset(&sa.sa_mask, SIGQUIT); 692 sigaddset(&sa.sa_mask, SIGTERM); 693 sa.sa_flags = SA_SIGINFO; 694 if (sigaction(SIGUSR1, &sa, NULL) == -1) 695 shutdown(1, "sigaction(SIGUSR1)", __LINE__); 696 sa.sa_sigaction = sig_action; 697 if (sigaction(SIGHUP, &sa, NULL) == -1) 698 shutdown(1, "sigaction(SIGHUP)", __LINE__); 699 if (sigaction(SIGINT, &sa, NULL) == -1) 700 shutdown(1, "sigaction(SIGINT)", __LINE__); 701 if (sigaction(SIGQUIT, &sa, NULL) == -1) 702 shutdown(1, "sigaction(SIGQUIT)", __LINE__); 703 if (sigaction(SIGTERM, &sa, NULL) == -1) 704 shutdown(1, "sigaction(SIGTERM)", __LINE__); 705 706 if (!continuous_mode_fake) { 707 attr.mq_flags = O_NONBLOCK; 708 attr.mq_maxmsg = cur_max_msgs; 709 attr.mq_msgsize = MSG_SIZE; 710 open_queue(&attr); 711 } 712 for (i = 0; i < num_cpus_to_pin; i++) { 713 pthread_attr_t thread_attr; 714 void *thread_func; 715 716 if (continuous_mode_fake) 717 thread_func = &fake_cont_thread; 718 else if (continuous_mode) 719 thread_func = &cont_thread; 720 else 721 thread_func = &perf_test_thread; 722 723 CPU_ZERO_S(cpu_set_size, cpu_set); 724 CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set); 725 pthread_attr_init(&thread_attr); 726 pthread_attr_setaffinity_np(&thread_attr, cpu_set_size, 727 cpu_set); 728 if (pthread_create(&cpu_threads[i], &thread_attr, thread_func, 729 NULL)) 730 shutdown(1, "pthread_create()", __LINE__); 731 pthread_attr_destroy(&thread_attr); 732 } 733 734 if (!continuous_mode) { 735 pthread_join(cpu_threads[0], &retval); 736 shutdown((long)retval, "perf_test_thread()", __LINE__); 737 } else { 738 while (1) 739 sleep(1); 740 } 741 shutdown(0, "", 0); 742 } 743