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
  42static char *usage =
  43"Usage:\n"
  44"  %s [-c #[,#..] -f] path\n"
  45"\n"
  46"       -c #    Skip most tests and go straight to a high queue depth test\n"
  47"               and then run that test continuously (useful for running at\n"
  48"               the same time as some other workload to see how much the\n"
  49"               cache thrashing caused by adding messages to a very deep\n"
  50"               queue impacts the performance of other programs).  The number\n"
  51"               indicates which CPU core we should bind the process to during\n"
  52"               the run.  If you have more than one physical CPU, then you\n"
  53"               will need one copy per physical CPU package, and you should\n"
  54"               specify the CPU cores to pin ourself to via a comma separated\n"
  55"               list of CPU values.\n"
  56"       -f      Only usable with continuous mode.  Pin ourself to the CPUs\n"
  57"               as requested, then instead of looping doing a high mq\n"
  58"               workload, just busy loop.  This will allow us to lock up a\n"
  59"               single CPU just like we normally would, but without actually\n"
  60"               thrashing the CPU cache.  This is to make it easier to get\n"
  61"               comparable numbers from some other workload running on the\n"
  62"               other CPUs.  One set of numbers with # CPUs locked up running\n"
  63"               an mq workload, and another set of numbers with those same\n"
  64"               CPUs locked away from the test workload, but not doing\n"
  65"               anything to trash the cache like the mq workload might.\n"
  66"       path    Path name of the message queue to create\n"
  67"\n"
  68"       Note: this program must be run as root in order to enable all tests\n"
  69"\n";
  70
  71char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
  72char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
  73
  74#define min(a, b) ((a) < (b) ? (a) : (b))
  75#define MAX_CPUS 64
  76char *cpu_option_string;
  77int cpus_to_pin[MAX_CPUS];
  78int num_cpus_to_pin;
  79pthread_t cpu_threads[MAX_CPUS];
  80pthread_t main_thread;
  81cpu_set_t *cpu_set;
  82int cpu_set_size;
  83int cpus_online;
  84
  85#define MSG_SIZE 16
  86#define TEST1_LOOPS 10000000
  87#define TEST2_LOOPS 100000
  88int continuous_mode;
  89int continuous_mode_fake;
  90
  91struct rlimit saved_limits, cur_limits;
  92int saved_max_msgs, saved_max_msgsize;
  93int cur_max_msgs, cur_max_msgsize;
  94FILE *max_msgs, *max_msgsize;
  95int cur_nice;
  96char *queue_path = "/mq_perf_tests";
  97mqd_t queue = -1;
  98struct mq_attr result;
  99int mq_prio_max;
 100
 101const struct poptOption options[] = {
 102        {
 103                .longName = "continuous",
 104                .shortName = 'c',
 105                .argInfo = POPT_ARG_STRING,
 106                .arg = &cpu_option_string,
 107                .val = 'c',
 108                .descrip = "Run continuous tests at a high queue depth in "
 109                        "order to test the effects of cache thrashing on "
 110                        "other tasks on the system.  This test is intended "
 111                        "to be run on one core of each physical CPU while "
 112                        "some other CPU intensive task is run on all the other "
 113                        "cores of that same physical CPU and the other task "
 114                        "is timed.  It is assumed that the process of adding "
 115                        "messages to the message queue in a tight loop will "
 116                        "impact that other task to some degree.  Once the "
 117                        "tests are performed in this way, you should then "
 118                        "re-run the tests using fake mode in order to check "
 119                        "the difference in time required to perform the CPU "
 120                        "intensive task",
 121                .argDescrip = "cpu[,cpu]",
 122        },
 123        {
 124                .longName = "fake",
 125                .shortName = 'f',
 126                .argInfo = POPT_ARG_NONE,
 127                .arg = &continuous_mode_fake,
 128                .val = 0,
 129                .descrip = "Tie up the CPUs that we would normally tie up in"
 130                        "continuous mode, but don't actually do any mq stuff, "
 131                        "just keep the CPU busy so it can't be used to process "
 132                        "system level tasks as this would free up resources on "
 133                        "the other CPU cores and skew the comparison between "
 134                        "the no-mqueue work and mqueue work tests",
 135                .argDescrip = NULL,
 136        },
 137        {
 138                .longName = "path",
 139                .shortName = 'p',
 140                .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
 141                .arg = &queue_path,
 142                .val = 'p',
 143                .descrip = "The name of the path to use in the mqueue "
 144                        "filesystem for our tests",
 145                .argDescrip = "pathname",
 146        },
 147        POPT_AUTOHELP
 148        POPT_TABLEEND
 149};
 150
 151static inline void __set(FILE *stream, int value, char *err_msg);
 152void shutdown(int exit_val, char *err_cause, int line_no);
 153void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
 154void sig_action(int signum, siginfo_t *info, void *context);
 155static inline int get(FILE *stream);
 156static inline void set(FILE *stream, int value);
 157static inline int try_set(FILE *stream, int value);
 158static inline void getr(int type, struct rlimit *rlim);
 159static inline void setr(int type, struct rlimit *rlim);
 160static inline void open_queue(struct mq_attr *attr);
 161void increase_limits(void);
 162
 163static inline void __set(FILE *stream, int value, char *err_msg)
 164{
 165        rewind(stream);
 166        if (fprintf(stream, "%d", value) < 0)
 167                perror(err_msg);
 168}
 169
 170
 171void shutdown(int exit_val, char *err_cause, int line_no)
 172{
 173        static int in_shutdown = 0;
 174        int errno_at_shutdown = errno;
 175        int i;
 176
 177        /* In case we get called by multiple threads or from an sighandler */
 178        if (in_shutdown++)
 179                return;
 180
 181        for (i = 0; i < num_cpus_to_pin; i++)
 182                if (cpu_threads[i]) {
 183                        pthread_kill(cpu_threads[i], SIGUSR1);
 184                        pthread_join(cpu_threads[i], NULL);
 185                }
 186
 187        if (queue != -1)
 188                if (mq_close(queue))
 189                        perror("mq_close() during shutdown");
 190        if (queue_path)
 191                /*
 192                 * Be silent if this fails, if we cleaned up already it's
 193                 * expected to fail
 194                 */
 195                mq_unlink(queue_path);
 196        if (saved_max_msgs)
 197                __set(max_msgs, saved_max_msgs,
 198                      "failed to restore saved_max_msgs");
 199        if (saved_max_msgsize)
 200                __set(max_msgsize, saved_max_msgsize,
 201                      "failed to restore saved_max_msgsize");
 202        if (exit_val)
 203                error(exit_val, errno_at_shutdown, "%s at %d",
 204                      err_cause, line_no);
 205        exit(0);
 206}
 207
 208void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
 209{
 210        if (pthread_self() != main_thread)
 211                pthread_exit(0);
 212        else {
 213                fprintf(stderr, "Caught signal %d in SIGUSR1 handler, "
 214                                "exiting\n", signum);
 215                shutdown(0, "", 0);
 216                fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
 217                exit(0);
 218        }
 219}
 220
 221void sig_action(int signum, siginfo_t *info, void *context)
 222{
 223        if (pthread_self() != main_thread)
 224                pthread_kill(main_thread, signum);
 225        else {
 226                fprintf(stderr, "Caught signal %d, exiting\n", signum);
 227                shutdown(0, "", 0);
 228                fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
 229                exit(0);
 230        }
 231}
 232
 233static inline int get(FILE *stream)
 234{
 235        int value;
 236        rewind(stream);
 237        if (fscanf(stream, "%d", &value) != 1)
 238                shutdown(4, "Error reading /proc entry", __LINE__);
 239        return value;
 240}
 241
 242static inline void set(FILE *stream, int value)
 243{
 244        int new_value;
 245
 246        rewind(stream);
 247        if (fprintf(stream, "%d", value) < 0)
 248                return shutdown(5, "Failed writing to /proc file", __LINE__);
 249        new_value = get(stream);
 250        if (new_value != value)
 251                return shutdown(5, "We didn't get what we wrote to /proc back",
 252                                __LINE__);
 253}
 254
 255static inline int try_set(FILE *stream, int value)
 256{
 257        int new_value;
 258
 259        rewind(stream);
 260        fprintf(stream, "%d", value);
 261        new_value = get(stream);
 262        return new_value == value;
 263}
 264
 265static inline void getr(int type, struct rlimit *rlim)
 266{
 267        if (getrlimit(type, rlim))
 268                shutdown(6, "getrlimit()", __LINE__);
 269}
 270
 271static inline void setr(int type, struct rlimit *rlim)
 272{
 273        if (setrlimit(type, rlim))
 274                shutdown(7, "setrlimit()", __LINE__);
 275}
 276
 277/**
 278 * open_queue - open the global queue for testing
 279 * @attr - An attr struct specifying the desired queue traits
 280 * @result - An attr struct that lists the actual traits the queue has
 281 *
 282 * This open is not allowed to fail, failure will result in an orderly
 283 * shutdown of the program.  The global queue_path is used to set what
 284 * queue to open, the queue descriptor is saved in the global queue
 285 * variable.
 286 */
 287static inline void open_queue(struct mq_attr *attr)
 288{
 289        int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK;
 290        int perms = DEFFILEMODE;
 291
 292        queue = mq_open(queue_path, flags, perms, attr);
 293        if (queue == -1)
 294                shutdown(1, "mq_open()", __LINE__);
 295        if (mq_getattr(queue, &result))
 296                shutdown(1, "mq_getattr()", __LINE__);
 297        printf("\n\tQueue %s created:\n", queue_path);
 298        printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
 299               "O_NONBLOCK" : "(null)");
 300        printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
 301        printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
 302        printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
 303}
 304
 305void *fake_cont_thread(void *arg)
 306{
 307        int i;
 308
 309        for (i = 0; i < num_cpus_to_pin; i++)
 310                if (cpu_threads[i] == pthread_self())
 311                        break;
 312        printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
 313               cpus_to_pin[i]);
 314        while (1)
 315                ;
 316}
 317
 318void *cont_thread(void *arg)
 319{
 320        char buff[MSG_SIZE];
 321        int i, priority;
 322
 323        for (i = 0; i < num_cpus_to_pin; i++)
 324                if (cpu_threads[i] == pthread_self())
 325                        break;
 326        printf("\tStarted continuous mode thread %d on CPU %d\n", i,
 327               cpus_to_pin[i]);
 328        while (1) {
 329                while (mq_send(queue, buff, sizeof(buff), 0) == 0)
 330                        ;
 331                mq_receive(queue, buff, sizeof(buff), &priority);
 332        }
 333}
 334
 335#define drain_queue() \
 336        while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
 337
 338#define do_untimed_send() \
 339        do { \
 340                if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
 341                        shutdown(3, "Test send failure", __LINE__); \
 342        } while (0)
 343
 344#define do_send_recv() \
 345        do { \
 346                clock_gettime(clock, &start); \
 347                if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
 348                        shutdown(3, "Test send failure", __LINE__); \
 349                clock_gettime(clock, &middle); \
 350                if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \
 351                        shutdown(3, "Test receive failure", __LINE__); \
 352                clock_gettime(clock, &end); \
 353                nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \
 354                        (middle.tv_nsec - start.tv_nsec); \
 355                send_total.tv_nsec += nsec; \
 356                if (send_total.tv_nsec >= 1000000000) { \
 357                        send_total.tv_sec++; \
 358                        send_total.tv_nsec -= 1000000000; \
 359                } \
 360                nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \
 361                        (end.tv_nsec - middle.tv_nsec); \
 362                recv_total.tv_nsec += nsec; \
 363                if (recv_total.tv_nsec >= 1000000000) { \
 364                        recv_total.tv_sec++; \
 365                        recv_total.tv_nsec -= 1000000000; \
 366                } \
 367        } while (0)
 368
 369struct test {
 370        char *desc;
 371        void (*func)(int *);
 372};
 373
 374void const_prio(int *prio)
 375{
 376        return;
 377}
 378
 379void inc_prio(int *prio)
 380{
 381        if (++*prio == mq_prio_max)
 382                *prio = 0;
 383}
 384
 385void dec_prio(int *prio)
 386{
 387        if (--*prio < 0)
 388                *prio = mq_prio_max - 1;
 389}
 390
 391void random_prio(int *prio)
 392{
 393        *prio = random() % mq_prio_max;
 394}
 395
 396struct test test2[] = {
 397        {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
 398                const_prio},
 399        {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
 400                inc_prio},
 401        {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
 402                dec_prio},
 403        {"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
 404                random_prio},
 405        {NULL, NULL}
 406};
 407
 408/**
 409 * Tests to perform (all done with MSG_SIZE messages):
 410 *
 411 * 1) Time to add/remove message with 0 messages on queue
 412 * 1a) with constant prio
 413 * 2) Time to add/remove message when queue close to capacity:
 414 * 2a) with constant prio
 415 * 2b) with increasing prio
 416 * 2c) with decreasing prio
 417 * 2d) with random prio
 418 * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX)
 419 */
 420void *perf_test_thread(void *arg)
 421{
 422        char buff[MSG_SIZE];
 423        int prio_out, prio_in;
 424        int i;
 425        clockid_t clock;
 426        pthread_t *t;
 427        struct timespec res, start, middle, end, send_total, recv_total;
 428        unsigned long long nsec;
 429        struct test *cur_test;
 430
 431        t = &cpu_threads[0];
 432        printf("\n\tStarted mqueue performance test thread on CPU %d\n",
 433               cpus_to_pin[0]);
 434        mq_prio_max = sysconf(_SC_MQ_PRIO_MAX);
 435        if (mq_prio_max == -1)
 436                shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
 437        if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
 438                shutdown(2, "pthread_getcpuclockid", __LINE__);
 439
 440        if (clock_getres(clock, &res))
 441                shutdown(2, "clock_getres()", __LINE__);
 442
 443        printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
 444        printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
 445               res.tv_nsec > 1 ? "s" : "");
 446
 447
 448
 449        printf("\n\tTest #1: Time send/recv message, queue empty\n");
 450        printf("\t\t(%d iterations)\n", TEST1_LOOPS);
 451        prio_out = 0;
 452        send_total.tv_sec = 0;
 453        send_total.tv_nsec = 0;
 454        recv_total.tv_sec = 0;
 455        recv_total.tv_nsec = 0;
 456        for (i = 0; i < TEST1_LOOPS; i++)
 457                do_send_recv();
 458        printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
 459               send_total.tv_sec, send_total.tv_nsec);
 460        nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
 461                 send_total.tv_nsec) / TEST1_LOOPS;
 462        printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
 463        printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
 464               recv_total.tv_sec, recv_total.tv_nsec);
 465        nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
 466                recv_total.tv_nsec) / TEST1_LOOPS;
 467        printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
 468
 469
 470        for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
 471                printf("%s:\n", cur_test->desc);
 472                printf("\t\t(%d iterations)\n", TEST2_LOOPS);
 473                prio_out = 0;
 474                send_total.tv_sec = 0;
 475                send_total.tv_nsec = 0;
 476                recv_total.tv_sec = 0;
 477                recv_total.tv_nsec = 0;
 478                printf("\t\tFilling queue...");
 479                fflush(stdout);
 480                clock_gettime(clock, &start);
 481                for (i = 0; i < result.mq_maxmsg - 1; i++) {
 482                        do_untimed_send();
 483                        cur_test->func(&prio_out);
 484                }
 485                clock_gettime(clock, &end);
 486                nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
 487                        1000000000) + (end.tv_nsec - start.tv_nsec);
 488                printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
 489                       nsec % 1000000000);
 490                printf("\t\tTesting...");
 491                fflush(stdout);
 492                for (i = 0; i < TEST2_LOOPS; i++) {
 493                        do_send_recv();
 494                        cur_test->func(&prio_out);
 495                }
 496                printf("done.\n");
 497                printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
 498                       send_total.tv_sec, send_total.tv_nsec);
 499                nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
 500                         send_total.tv_nsec) / TEST2_LOOPS;
 501                printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
 502                printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
 503                       recv_total.tv_sec, recv_total.tv_nsec);
 504                nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
 505                        recv_total.tv_nsec) / TEST2_LOOPS;
 506                printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
 507                printf("\t\tDraining queue...");
 508                fflush(stdout);
 509                clock_gettime(clock, &start);
 510                drain_queue();
 511                clock_gettime(clock, &end);
 512                nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
 513                        1000000000) + (end.tv_nsec - start.tv_nsec);
 514                printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
 515                       nsec % 1000000000);
 516        }
 517        return 0;
 518}
 519
 520void increase_limits(void)
 521{
 522        cur_limits.rlim_cur = RLIM_INFINITY;
 523        cur_limits.rlim_max = RLIM_INFINITY;
 524        setr(RLIMIT_MSGQUEUE, &cur_limits);
 525        while (try_set(max_msgs, cur_max_msgs += 10))
 526                ;
 527        cur_max_msgs = get(max_msgs);
 528        while (try_set(max_msgsize, cur_max_msgsize += 1024))
 529                ;
 530        cur_max_msgsize = get(max_msgsize);
 531        if (setpriority(PRIO_PROCESS, 0, -20) != 0)
 532                shutdown(2, "setpriority()", __LINE__);
 533        cur_nice = -20;
 534}
 535
 536int main(int argc, char *argv[])
 537{
 538        struct mq_attr attr;
 539        char *option, *next_option;
 540        int i, cpu, rc;
 541        struct sigaction sa;
 542        poptContext popt_context;
 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%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