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#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}
 744