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