at v5.0-rc7 743 lines 22 kB view raw
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 44static 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 73char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; 74char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; 75 76#define min(a, b) ((a) < (b) ? (a) : (b)) 77#define MAX_CPUS 64 78char *cpu_option_string; 79int cpus_to_pin[MAX_CPUS]; 80int num_cpus_to_pin; 81pthread_t cpu_threads[MAX_CPUS]; 82pthread_t main_thread; 83cpu_set_t *cpu_set; 84int cpu_set_size; 85int cpus_online; 86 87#define MSG_SIZE 16 88#define TEST1_LOOPS 10000000 89#define TEST2_LOOPS 100000 90int continuous_mode; 91int continuous_mode_fake; 92 93struct rlimit saved_limits, cur_limits; 94int saved_max_msgs, saved_max_msgsize; 95int cur_max_msgs, cur_max_msgsize; 96FILE *max_msgs, *max_msgsize; 97int cur_nice; 98char *queue_path = "/mq_perf_tests"; 99mqd_t queue = -1; 100struct mq_attr result; 101int mq_prio_max; 102 103const 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 153static inline void __set(FILE *stream, int value, char *err_msg); 154void shutdown(int exit_val, char *err_cause, int line_no); 155void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context); 156void sig_action(int signum, siginfo_t *info, void *context); 157static inline int get(FILE *stream); 158static inline void set(FILE *stream, int value); 159static inline int try_set(FILE *stream, int value); 160static inline void getr(int type, struct rlimit *rlim); 161static inline void setr(int type, struct rlimit *rlim); 162static inline void open_queue(struct mq_attr *attr); 163void increase_limits(void); 164 165static 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 173void 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 210void 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 223void 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 235static 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 244static 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 257static 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 267static inline void getr(int type, struct rlimit *rlim) 268{ 269 if (getrlimit(type, rlim)) 270 shutdown(6, "getrlimit()", __LINE__); 271} 272 273static 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 */ 289static 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 307void *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 320void *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 371struct test { 372 char *desc; 373 void (*func)(int *); 374}; 375 376void const_prio(int *prio) 377{ 378 return; 379} 380 381void inc_prio(int *prio) 382{ 383 if (++*prio == mq_prio_max) 384 *prio = 0; 385} 386 387void dec_prio(int *prio) 388{ 389 if (--*prio < 0) 390 *prio = mq_prio_max - 1; 391} 392 393void random_prio(int *prio) 394{ 395 *prio = random() % mq_prio_max; 396} 397 398struct 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 */ 422void *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 522void 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 538int 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}