linux/tools/testing/selftests/mqueue/mq_perf_tests.c
<<
>>
Prefs
   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
  41static 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
  70char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
  71char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
  72
  73#define min(a, b) ((a) < (b) ? (a) : (b))
  74#define MAX_CPUS 64
  75char *cpu_option_string;
  76int cpus_to_pin[MAX_CPUS];
  77int num_cpus_to_pin;
  78pthread_t cpu_threads[MAX_CPUS];
  79pthread_t main_thread;
  80cpu_set_t *cpu_set;
  81int cpu_set_size;
  82int cpus_online;
  83
  84#define MSG_SIZE 16
  85#define TEST1_LOOPS 10000000
  86#define TEST2_LOOPS 100000
  87int continuous_mode;
  88int continuous_mode_fake;
  89
  90struct rlimit saved_limits, cur_limits;
  91int saved_max_msgs, saved_max_msgsize;
  92int cur_max_msgs, cur_max_msgsize;
  93FILE *max_msgs, *max_msgsize;
  94int cur_nice;
  95char *queue_path = "/mq_perf_tests";
  96mqd_t queue = -1;
  97struct mq_attr result;
  98int mq_prio_max;
  99
 100const 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
 150static inline void __set(FILE *stream, int value, char *err_msg);
 151void shutdown(int exit_val, char *err_cause, int line_no);
 152void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
 153void sig_action(int signum, siginfo_t *info, void *context);
 154static inline int get(FILE *stream);
 155static inline void set(FILE *stream, int value);
 156static inline int try_set(FILE *stream, int value);
 157static inline void getr(int type, struct rlimit *rlim);
 158static inline void setr(int type, struct rlimit *rlim);
 159static inline void open_queue(struct mq_attr *attr);
 160void increase_limits(void);
 161
 162static 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
 170void 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
 207void 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
 220void 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
 232static 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
 241static 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
 254static 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
 264static inline void getr(int type, struct rlimit *rlim)
 265{
 266        if (getrlimit(type, rlim))
 267                shutdown(6, "getrlimit()", __LINE__);
 268}
 269
 270static 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 */
 286static 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%d\n", result.mq_maxmsg);
 300        printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize);
 301        printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs);
 302}
 303
 304void *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
 317void *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
 368struct test {
 369        char *desc;
 370        void (*func)(int *);
 371};
 372
 373void const_prio(int *prio)
 374{
 375        return;
 376}
 377
 378void inc_prio(int *prio)
 379{
 380        if (++*prio == mq_prio_max)
 381                *prio = 0;
 382}
 383
 384void dec_prio(int *prio)
 385{
 386        if (--*prio < 0)
 387                *prio = mq_prio_max - 1;
 388}
 389
 390void random_prio(int *prio)
 391{
 392        *prio = random() % mq_prio_max;
 393}
 394
 395struct 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 */
 419void *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%d 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%d.%ds 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%d nsec/msg\n", nsec);
 462        printf("\t\tRecv msg:\t\t\t%d.%ds 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%d nsec/msg\n", nsec);
 467
 468
 469        for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
 470                printf(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%d.%ds 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%d nsec/msg\n", nsec);
 501                printf("\t\tRecv msg:\t\t\t%d.%ds 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%d 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
 519void 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
 535int main(int argc, char *argv[])
 536{
 537        struct mq_attr attr;
 538        char *option, *next_option;
 539        int i, cpu;
 540        struct sigaction sa;
 541        poptContext popt_context;
 542        char rc;
 543        void *retval;
 544
 545        main_thread = pthread_self();
 546        num_cpus_to_pin = 0;
 547
 548        if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
 549                perror("sysconf(_SC_NPROCESSORS_ONLN)");
 550                exit(1);
 551        }
 552        cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
 553        cpu_set = CPU_ALLOC(cpus_online);
 554        if (cpu_set == NULL) {
 555                perror("CPU_ALLOC()");
 556                exit(1);
 557        }
 558        cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
 559        CPU_ZERO_S(cpu_set_size, cpu_set);
 560
 561        popt_context = poptGetContext(NULL, argc, (const char **)argv,
 562                                      options, 0);
 563
 564        while ((rc = poptGetNextOpt(popt_context)) > 0) {
 565                switch (rc) {
 566                case 'c':
 567                        continuous_mode = 1;
 568                        option = cpu_option_string;
 569                        do {
 570                                next_option = strchr(option, ',');
 571                                if (next_option)
 572                                        *next_option = '\0';
 573                                cpu = atoi(option);
 574                                if (cpu >= cpus_online)
 575                                        fprintf(stderr, "CPU %d exceeds "
 576                                                "cpus online, ignoring.\n",
 577                                                cpu);
 578                                else
 579                                        cpus_to_pin[num_cpus_to_pin++] = cpu;
 580                                if (next_option)
 581                                        option = ++next_option;
 582                        } while (next_option && num_cpus_to_pin < MAX_CPUS);
 583                        /* Double check that they didn't give us the same CPU
 584                         * more than once */
 585                        for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
 586                                if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
 587                                                cpu_set)) {
 588                                        fprintf(stderr, "Any given CPU may "
 589                                                "only be given once.\n");
 590                                        exit(1);
 591                                } else
 592                                        CPU_SET_S(cpus_to_pin[cpu],
 593                                                  cpu_set_size, cpu_set);
 594                        }
 595                        break;
 596                case 'p':
 597                        /*
 598                         * Although we can create a msg queue with a
 599                         * non-absolute path name, unlink will fail.  So,
 600                         * if the name doesn't start with a /, add one
 601                         * when we save it.
 602                         */
 603                        option = queue_path;
 604                        if (*option != '/') {
 605                                queue_path = malloc(strlen(option) + 2);
 606                                if (!queue_path) {
 607                                        perror("malloc()");
 608                                        exit(1);
 609                                }
 610                                queue_path[0] = '/';
 611                                queue_path[1] = 0;
 612                                strcat(queue_path, option);
 613                                free(option);
 614                        }
 615                        break;
 616                }
 617        }
 618
 619        if (continuous_mode && num_cpus_to_pin == 0) {
 620                fprintf(stderr, "Must pass at least one CPU to continuous "
 621                        "mode.\n");
 622                poptPrintUsage(popt_context, stderr, 0);
 623                exit(1);
 624        } else if (!continuous_mode) {
 625                num_cpus_to_pin = 1;
 626                cpus_to_pin[0] = cpus_online - 1;
 627        }
 628
 629        if (getuid() != 0) {
 630                fprintf(stderr, "Not running as root, but almost all tests "
 631                        "require root in order to modify\nsystem settings.  "
 632                        "Exiting.\n");
 633                exit(1);
 634        }
 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%d\n", saved_limits.rlim_cur);
 657        printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
 658        printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
 659        printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
 660        printf("\tNice value:\t\t\t\t%d\n", cur_nice);
 661        printf("\n");
 662
 663        increase_limits();
 664
 665        printf("Adjusted system state for testing:\n");
 666        if (cur_limits.rlim_cur == RLIM_INFINITY) {
 667                printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
 668                printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
 669        } else {
 670                printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
 671                       cur_limits.rlim_cur);
 672                printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
 673                       cur_limits.rlim_max);
 674        }
 675        printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
 676        printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
 677        printf("\tNice value:\t\t\t\t%d\n", cur_nice);
 678        printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
 679               (continuous_mode_fake ? "fake mode" : "enabled") :
 680               "disabled");
 681        printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
 682        for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
 683                        printf(",%d", cpus_to_pin[cpu]);
 684        printf("\n");
 685
 686        sa.sa_sigaction = sig_action_SIGUSR1;
 687        sigemptyset(&sa.sa_mask);
 688        sigaddset(&sa.sa_mask, SIGHUP);
 689        sigaddset(&sa.sa_mask, SIGINT);
 690        sigaddset(&sa.sa_mask, SIGQUIT);
 691        sigaddset(&sa.sa_mask, SIGTERM);
 692        sa.sa_flags = SA_SIGINFO;
 693        if (sigaction(SIGUSR1, &sa, NULL) == -1)
 694                shutdown(1, "sigaction(SIGUSR1)", __LINE__);
 695        sa.sa_sigaction = sig_action;
 696        if (sigaction(SIGHUP, &sa, NULL) == -1)
 697                shutdown(1, "sigaction(SIGHUP)", __LINE__);
 698        if (sigaction(SIGINT, &sa, NULL) == -1)
 699                shutdown(1, "sigaction(SIGINT)", __LINE__);
 700        if (sigaction(SIGQUIT, &sa, NULL) == -1)
 701                shutdown(1, "sigaction(SIGQUIT)", __LINE__);
 702        if (sigaction(SIGTERM, &sa, NULL) == -1)
 703                shutdown(1, "sigaction(SIGTERM)", __LINE__);
 704
 705        if (!continuous_mode_fake) {
 706                attr.mq_flags = O_NONBLOCK;
 707                attr.mq_maxmsg = cur_max_msgs;
 708                attr.mq_msgsize = MSG_SIZE;
 709                open_queue(&attr);
 710        }
 711        for (i = 0; i < num_cpus_to_pin; i++) {
 712                pthread_attr_t thread_attr;
 713                void *thread_func;
 714
 715                if (continuous_mode_fake)
 716                        thread_func = &fake_cont_thread;
 717                else if (continuous_mode)
 718                        thread_func = &cont_thread;
 719                else
 720                        thread_func = &perf_test_thread;
 721
 722                CPU_ZERO_S(cpu_set_size, cpu_set);
 723                CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
 724                pthread_attr_init(&thread_attr);
 725                pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
 726                                            cpu_set);
 727                if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
 728                                   NULL))
 729                        shutdown(1, "pthread_create()", __LINE__);
 730                pthread_attr_destroy(&thread_attr);
 731        }
 732
 733        if (!continuous_mode) {
 734                pthread_join(cpu_threads[0], &retval);
 735                shutdown((long)retval, "perf_test_thread()", __LINE__);
 736        } else {
 737                while (1)
 738                        sleep(1);
 739        }
 740        shutdown(0, "", 0);
 741}
 742