Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This application is Copyright 2012 Red Hat, Inc.
0003  *  Doug Ledford <dledford@redhat.com>
0004  *
0005  * mq_perf_tests is free software: you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation, version 3.
0008  *
0009  * mq_perf_tests is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  * GNU General Public License for more details.
0013  *
0014  * For the full text of the license, see <http://www.gnu.org/licenses/>.
0015  *
0016  * mq_perf_tests.c
0017  *   Tests various types of message queue workloads, concentrating on those
0018  *   situations that invole large message sizes, large message queue depths,
0019  *   or both, and reports back useful metrics about kernel message queue
0020  *   performance.
0021  *
0022  */
0023 #define _GNU_SOURCE
0024 #include <stdio.h>
0025 #include <stdlib.h>
0026 #include <unistd.h>
0027 #include <fcntl.h>
0028 #include <string.h>
0029 #include <limits.h>
0030 #include <errno.h>
0031 #include <signal.h>
0032 #include <pthread.h>
0033 #include <sched.h>
0034 #include <sys/types.h>
0035 #include <sys/time.h>
0036 #include <sys/resource.h>
0037 #include <sys/stat.h>
0038 #include <sys/param.h>
0039 #include <mqueue.h>
0040 #include <popt.h>
0041 #include <error.h>
0042 
0043 #include "../kselftest.h"
0044 
0045 static char *usage =
0046 "Usage:\n"
0047 "  %s [-c #[,#..] -f] path\n"
0048 "\n"
0049 "   -c #    Skip most tests and go straight to a high queue depth test\n"
0050 "       and then run that test continuously (useful for running at\n"
0051 "       the same time as some other workload to see how much the\n"
0052 "       cache thrashing caused by adding messages to a very deep\n"
0053 "       queue impacts the performance of other programs).  The number\n"
0054 "       indicates which CPU core we should bind the process to during\n"
0055 "       the run.  If you have more than one physical CPU, then you\n"
0056 "       will need one copy per physical CPU package, and you should\n"
0057 "       specify the CPU cores to pin ourself to via a comma separated\n"
0058 "       list of CPU values.\n"
0059 "   -f  Only usable with continuous mode.  Pin ourself to the CPUs\n"
0060 "       as requested, then instead of looping doing a high mq\n"
0061 "       workload, just busy loop.  This will allow us to lock up a\n"
0062 "       single CPU just like we normally would, but without actually\n"
0063 "       thrashing the CPU cache.  This is to make it easier to get\n"
0064 "       comparable numbers from some other workload running on the\n"
0065 "       other CPUs.  One set of numbers with # CPUs locked up running\n"
0066 "       an mq workload, and another set of numbers with those same\n"
0067 "       CPUs locked away from the test workload, but not doing\n"
0068 "       anything to trash the cache like the mq workload might.\n"
0069 "   path    Path name of the message queue to create\n"
0070 "\n"
0071 "   Note: this program must be run as root in order to enable all tests\n"
0072 "\n";
0073 
0074 char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
0075 char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
0076 
0077 #define MAX_CPUS 64
0078 char *cpu_option_string;
0079 int cpus_to_pin[MAX_CPUS];
0080 int num_cpus_to_pin;
0081 pthread_t cpu_threads[MAX_CPUS];
0082 pthread_t main_thread;
0083 cpu_set_t *cpu_set;
0084 int cpu_set_size;
0085 int cpus_online;
0086 
0087 #define MSG_SIZE 16
0088 #define TEST1_LOOPS 10000000
0089 #define TEST2_LOOPS 100000
0090 int continuous_mode;
0091 int continuous_mode_fake;
0092 
0093 struct rlimit saved_limits, cur_limits;
0094 int saved_max_msgs, saved_max_msgsize;
0095 int cur_max_msgs, cur_max_msgsize;
0096 FILE *max_msgs, *max_msgsize;
0097 int cur_nice;
0098 char *queue_path = "/mq_perf_tests";
0099 mqd_t queue = -1;
0100 struct mq_attr result;
0101 int mq_prio_max;
0102 
0103 const struct poptOption options[] = {
0104     {
0105         .longName = "continuous",
0106         .shortName = 'c',
0107         .argInfo = POPT_ARG_STRING,
0108         .arg = &cpu_option_string,
0109         .val = 'c',
0110         .descrip = "Run continuous tests at a high queue depth in "
0111             "order to test the effects of cache thrashing on "
0112             "other tasks on the system.  This test is intended "
0113             "to be run on one core of each physical CPU while "
0114             "some other CPU intensive task is run on all the other "
0115             "cores of that same physical CPU and the other task "
0116             "is timed.  It is assumed that the process of adding "
0117             "messages to the message queue in a tight loop will "
0118             "impact that other task to some degree.  Once the "
0119             "tests are performed in this way, you should then "
0120             "re-run the tests using fake mode in order to check "
0121             "the difference in time required to perform the CPU "
0122             "intensive task",
0123         .argDescrip = "cpu[,cpu]",
0124     },
0125     {
0126         .longName = "fake",
0127         .shortName = 'f',
0128         .argInfo = POPT_ARG_NONE,
0129         .arg = &continuous_mode_fake,
0130         .val = 0,
0131         .descrip = "Tie up the CPUs that we would normally tie up in"
0132             "continuous mode, but don't actually do any mq stuff, "
0133             "just keep the CPU busy so it can't be used to process "
0134             "system level tasks as this would free up resources on "
0135             "the other CPU cores and skew the comparison between "
0136             "the no-mqueue work and mqueue work tests",
0137         .argDescrip = NULL,
0138     },
0139     {
0140         .longName = "path",
0141         .shortName = 'p',
0142         .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
0143         .arg = &queue_path,
0144         .val = 'p',
0145         .descrip = "The name of the path to use in the mqueue "
0146             "filesystem for our tests",
0147         .argDescrip = "pathname",
0148     },
0149     POPT_AUTOHELP
0150     POPT_TABLEEND
0151 };
0152 
0153 static inline void __set(FILE *stream, int value, char *err_msg);
0154 void shutdown(int exit_val, char *err_cause, int line_no);
0155 void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
0156 void sig_action(int signum, siginfo_t *info, void *context);
0157 static inline int get(FILE *stream);
0158 static inline void set(FILE *stream, int value);
0159 static inline int try_set(FILE *stream, int value);
0160 static inline void getr(int type, struct rlimit *rlim);
0161 static inline void setr(int type, struct rlimit *rlim);
0162 static inline void open_queue(struct mq_attr *attr);
0163 void increase_limits(void);
0164 
0165 static inline void __set(FILE *stream, int value, char *err_msg)
0166 {
0167     rewind(stream);
0168     if (fprintf(stream, "%d", value) < 0)
0169         perror(err_msg);
0170 }
0171 
0172 
0173 void shutdown(int exit_val, char *err_cause, int line_no)
0174 {
0175     static int in_shutdown = 0;
0176     int errno_at_shutdown = errno;
0177     int i;
0178 
0179     /* In case we get called by multiple threads or from an sighandler */
0180     if (in_shutdown++)
0181         return;
0182 
0183     /* Free the cpu_set allocated using CPU_ALLOC in main function */
0184     CPU_FREE(cpu_set);
0185 
0186     for (i = 0; i < num_cpus_to_pin; i++)
0187         if (cpu_threads[i]) {
0188             pthread_kill(cpu_threads[i], SIGUSR1);
0189             pthread_join(cpu_threads[i], NULL);
0190         }
0191 
0192     if (queue != -1)
0193         if (mq_close(queue))
0194             perror("mq_close() during shutdown");
0195     if (queue_path)
0196         /*
0197          * Be silent if this fails, if we cleaned up already it's
0198          * expected to fail
0199          */
0200         mq_unlink(queue_path);
0201     if (saved_max_msgs)
0202         __set(max_msgs, saved_max_msgs,
0203               "failed to restore saved_max_msgs");
0204     if (saved_max_msgsize)
0205         __set(max_msgsize, saved_max_msgsize,
0206               "failed to restore saved_max_msgsize");
0207     if (exit_val)
0208         error(exit_val, errno_at_shutdown, "%s at %d",
0209               err_cause, line_no);
0210     exit(0);
0211 }
0212 
0213 void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
0214 {
0215     if (pthread_self() != main_thread)
0216         pthread_exit(0);
0217     else {
0218         fprintf(stderr, "Caught signal %d in SIGUSR1 handler, "
0219                 "exiting\n", signum);
0220         shutdown(0, "", 0);
0221         fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
0222         exit(0);
0223     }
0224 }
0225 
0226 void sig_action(int signum, siginfo_t *info, void *context)
0227 {
0228     if (pthread_self() != main_thread)
0229         pthread_kill(main_thread, signum);
0230     else {
0231         fprintf(stderr, "Caught signal %d, exiting\n", signum);
0232         shutdown(0, "", 0);
0233         fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
0234         exit(0);
0235     }
0236 }
0237 
0238 static inline int get(FILE *stream)
0239 {
0240     int value;
0241     rewind(stream);
0242     if (fscanf(stream, "%d", &value) != 1)
0243         shutdown(4, "Error reading /proc entry", __LINE__);
0244     return value;
0245 }
0246 
0247 static inline void set(FILE *stream, int value)
0248 {
0249     int new_value;
0250 
0251     rewind(stream);
0252     if (fprintf(stream, "%d", value) < 0)
0253         return shutdown(5, "Failed writing to /proc file", __LINE__);
0254     new_value = get(stream);
0255     if (new_value != value)
0256         return shutdown(5, "We didn't get what we wrote to /proc back",
0257                 __LINE__);
0258 }
0259 
0260 static inline int try_set(FILE *stream, int value)
0261 {
0262     int new_value;
0263 
0264     rewind(stream);
0265     fprintf(stream, "%d", value);
0266     new_value = get(stream);
0267     return new_value == value;
0268 }
0269 
0270 static inline void getr(int type, struct rlimit *rlim)
0271 {
0272     if (getrlimit(type, rlim))
0273         shutdown(6, "getrlimit()", __LINE__);
0274 }
0275 
0276 static inline void setr(int type, struct rlimit *rlim)
0277 {
0278     if (setrlimit(type, rlim))
0279         shutdown(7, "setrlimit()", __LINE__);
0280 }
0281 
0282 /**
0283  * open_queue - open the global queue for testing
0284  * @attr - An attr struct specifying the desired queue traits
0285  * @result - An attr struct that lists the actual traits the queue has
0286  *
0287  * This open is not allowed to fail, failure will result in an orderly
0288  * shutdown of the program.  The global queue_path is used to set what
0289  * queue to open, the queue descriptor is saved in the global queue
0290  * variable.
0291  */
0292 static inline void open_queue(struct mq_attr *attr)
0293 {
0294     int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK;
0295     int perms = DEFFILEMODE;
0296 
0297     queue = mq_open(queue_path, flags, perms, attr);
0298     if (queue == -1)
0299         shutdown(1, "mq_open()", __LINE__);
0300     if (mq_getattr(queue, &result))
0301         shutdown(1, "mq_getattr()", __LINE__);
0302     printf("\n\tQueue %s created:\n", queue_path);
0303     printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
0304            "O_NONBLOCK" : "(null)");
0305     printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
0306     printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
0307     printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
0308 }
0309 
0310 void *fake_cont_thread(void *arg)
0311 {
0312     int i;
0313 
0314     for (i = 0; i < num_cpus_to_pin; i++)
0315         if (cpu_threads[i] == pthread_self())
0316             break;
0317     printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
0318            cpus_to_pin[i]);
0319     while (1)
0320         ;
0321 }
0322 
0323 void *cont_thread(void *arg)
0324 {
0325     char buff[MSG_SIZE];
0326     int i, priority;
0327 
0328     for (i = 0; i < num_cpus_to_pin; i++)
0329         if (cpu_threads[i] == pthread_self())
0330             break;
0331     printf("\tStarted continuous mode thread %d on CPU %d\n", i,
0332            cpus_to_pin[i]);
0333     while (1) {
0334         while (mq_send(queue, buff, sizeof(buff), 0) == 0)
0335             ;
0336         mq_receive(queue, buff, sizeof(buff), &priority);
0337     }
0338 }
0339 
0340 #define drain_queue() \
0341     while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
0342 
0343 #define do_untimed_send() \
0344     do { \
0345         if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
0346             shutdown(3, "Test send failure", __LINE__); \
0347     } while (0)
0348 
0349 #define do_send_recv() \
0350     do { \
0351         clock_gettime(clock, &start); \
0352         if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
0353             shutdown(3, "Test send failure", __LINE__); \
0354         clock_gettime(clock, &middle); \
0355         if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \
0356             shutdown(3, "Test receive failure", __LINE__); \
0357         clock_gettime(clock, &end); \
0358         nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \
0359             (middle.tv_nsec - start.tv_nsec); \
0360         send_total.tv_nsec += nsec; \
0361         if (send_total.tv_nsec >= 1000000000) { \
0362             send_total.tv_sec++; \
0363             send_total.tv_nsec -= 1000000000; \
0364         } \
0365         nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \
0366             (end.tv_nsec - middle.tv_nsec); \
0367         recv_total.tv_nsec += nsec; \
0368         if (recv_total.tv_nsec >= 1000000000) { \
0369             recv_total.tv_sec++; \
0370             recv_total.tv_nsec -= 1000000000; \
0371         } \
0372     } while (0)
0373 
0374 struct test {
0375     char *desc;
0376     void (*func)(int *);
0377 };
0378 
0379 void const_prio(int *prio)
0380 {
0381     return;
0382 }
0383 
0384 void inc_prio(int *prio)
0385 {
0386     if (++*prio == mq_prio_max)
0387         *prio = 0;
0388 }
0389 
0390 void dec_prio(int *prio)
0391 {
0392     if (--*prio < 0)
0393         *prio = mq_prio_max - 1;
0394 }
0395 
0396 void random_prio(int *prio)
0397 {
0398     *prio = random() % mq_prio_max;
0399 }
0400 
0401 struct test test2[] = {
0402     {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
0403         const_prio},
0404     {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
0405         inc_prio},
0406     {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
0407         dec_prio},
0408     {"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
0409         random_prio},
0410     {NULL, NULL}
0411 };
0412 
0413 /**
0414  * Tests to perform (all done with MSG_SIZE messages):
0415  *
0416  * 1) Time to add/remove message with 0 messages on queue
0417  * 1a) with constant prio
0418  * 2) Time to add/remove message when queue close to capacity:
0419  * 2a) with constant prio
0420  * 2b) with increasing prio
0421  * 2c) with decreasing prio
0422  * 2d) with random prio
0423  * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX)
0424  */
0425 void *perf_test_thread(void *arg)
0426 {
0427     char buff[MSG_SIZE];
0428     int prio_out, prio_in;
0429     int i;
0430     clockid_t clock;
0431     pthread_t *t;
0432     struct timespec res, start, middle, end, send_total, recv_total;
0433     unsigned long long nsec;
0434     struct test *cur_test;
0435 
0436     t = &cpu_threads[0];
0437     printf("\n\tStarted mqueue performance test thread on CPU %d\n",
0438            cpus_to_pin[0]);
0439     mq_prio_max = sysconf(_SC_MQ_PRIO_MAX);
0440     if (mq_prio_max == -1)
0441         shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
0442     if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
0443         shutdown(2, "pthread_getcpuclockid", __LINE__);
0444 
0445     if (clock_getres(clock, &res))
0446         shutdown(2, "clock_getres()", __LINE__);
0447 
0448     printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
0449     printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
0450            res.tv_nsec > 1 ? "s" : "");
0451 
0452 
0453 
0454     printf("\n\tTest #1: Time send/recv message, queue empty\n");
0455     printf("\t\t(%d iterations)\n", TEST1_LOOPS);
0456     prio_out = 0;
0457     send_total.tv_sec = 0;
0458     send_total.tv_nsec = 0;
0459     recv_total.tv_sec = 0;
0460     recv_total.tv_nsec = 0;
0461     for (i = 0; i < TEST1_LOOPS; i++)
0462         do_send_recv();
0463     printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
0464            send_total.tv_sec, send_total.tv_nsec);
0465     nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
0466          send_total.tv_nsec) / TEST1_LOOPS;
0467     printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
0468     printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
0469            recv_total.tv_sec, recv_total.tv_nsec);
0470     nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
0471         recv_total.tv_nsec) / TEST1_LOOPS;
0472     printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
0473 
0474 
0475     for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
0476         printf("%s:\n", cur_test->desc);
0477         printf("\t\t(%d iterations)\n", TEST2_LOOPS);
0478         prio_out = 0;
0479         send_total.tv_sec = 0;
0480         send_total.tv_nsec = 0;
0481         recv_total.tv_sec = 0;
0482         recv_total.tv_nsec = 0;
0483         printf("\t\tFilling queue...");
0484         fflush(stdout);
0485         clock_gettime(clock, &start);
0486         for (i = 0; i < result.mq_maxmsg - 1; i++) {
0487             do_untimed_send();
0488             cur_test->func(&prio_out);
0489         }
0490         clock_gettime(clock, &end);
0491         nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
0492             1000000000) + (end.tv_nsec - start.tv_nsec);
0493         printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
0494                nsec % 1000000000);
0495         printf("\t\tTesting...");
0496         fflush(stdout);
0497         for (i = 0; i < TEST2_LOOPS; i++) {
0498             do_send_recv();
0499             cur_test->func(&prio_out);
0500         }
0501         printf("done.\n");
0502         printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
0503                send_total.tv_sec, send_total.tv_nsec);
0504         nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
0505              send_total.tv_nsec) / TEST2_LOOPS;
0506         printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
0507         printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
0508                recv_total.tv_sec, recv_total.tv_nsec);
0509         nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
0510             recv_total.tv_nsec) / TEST2_LOOPS;
0511         printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
0512         printf("\t\tDraining queue...");
0513         fflush(stdout);
0514         clock_gettime(clock, &start);
0515         drain_queue();
0516         clock_gettime(clock, &end);
0517         nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
0518             1000000000) + (end.tv_nsec - start.tv_nsec);
0519         printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
0520                nsec % 1000000000);
0521     }
0522     return 0;
0523 }
0524 
0525 void increase_limits(void)
0526 {
0527     cur_limits.rlim_cur = RLIM_INFINITY;
0528     cur_limits.rlim_max = RLIM_INFINITY;
0529     setr(RLIMIT_MSGQUEUE, &cur_limits);
0530     while (try_set(max_msgs, cur_max_msgs += 10))
0531         ;
0532     cur_max_msgs = get(max_msgs);
0533     while (try_set(max_msgsize, cur_max_msgsize += 1024))
0534         ;
0535     cur_max_msgsize = get(max_msgsize);
0536     if (setpriority(PRIO_PROCESS, 0, -20) != 0)
0537         shutdown(2, "setpriority()", __LINE__);
0538     cur_nice = -20;
0539 }
0540 
0541 int main(int argc, char *argv[])
0542 {
0543     struct mq_attr attr;
0544     char *option, *next_option;
0545     int i, cpu, rc;
0546     struct sigaction sa;
0547     poptContext popt_context;
0548     void *retval;
0549 
0550     main_thread = pthread_self();
0551     num_cpus_to_pin = 0;
0552 
0553     if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
0554         perror("sysconf(_SC_NPROCESSORS_ONLN)");
0555         exit(1);
0556     }
0557 
0558     if (getuid() != 0)
0559         ksft_exit_skip("Not running as root, but almost all tests "
0560             "require root in order to modify\nsystem settings.  "
0561             "Exiting.\n");
0562 
0563     cpus_online = MIN(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
0564     cpu_set = CPU_ALLOC(cpus_online);
0565     if (cpu_set == NULL) {
0566         perror("CPU_ALLOC()");
0567         exit(1);
0568     }
0569     cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
0570     CPU_ZERO_S(cpu_set_size, cpu_set);
0571 
0572     popt_context = poptGetContext(NULL, argc, (const char **)argv,
0573                       options, 0);
0574 
0575     while ((rc = poptGetNextOpt(popt_context)) > 0) {
0576         switch (rc) {
0577         case 'c':
0578             continuous_mode = 1;
0579             option = cpu_option_string;
0580             do {
0581                 next_option = strchr(option, ',');
0582                 if (next_option)
0583                     *next_option = '\0';
0584                 cpu = atoi(option);
0585                 if (cpu >= cpus_online)
0586                     fprintf(stderr, "CPU %d exceeds "
0587                         "cpus online, ignoring.\n",
0588                         cpu);
0589                 else
0590                     cpus_to_pin[num_cpus_to_pin++] = cpu;
0591                 if (next_option)
0592                     option = ++next_option;
0593             } while (next_option && num_cpus_to_pin < MAX_CPUS);
0594             /* Double check that they didn't give us the same CPU
0595              * more than once */
0596             for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
0597                 if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
0598                         cpu_set)) {
0599                     fprintf(stderr, "Any given CPU may "
0600                         "only be given once.\n");
0601                     goto err_code;
0602                 } else
0603                     CPU_SET_S(cpus_to_pin[cpu],
0604                           cpu_set_size, cpu_set);
0605             }
0606             break;
0607         case 'p':
0608             /*
0609              * Although we can create a msg queue with a
0610              * non-absolute path name, unlink will fail.  So,
0611              * if the name doesn't start with a /, add one
0612              * when we save it.
0613              */
0614             option = queue_path;
0615             if (*option != '/') {
0616                 queue_path = malloc(strlen(option) + 2);
0617                 if (!queue_path) {
0618                     perror("malloc()");
0619                     goto err_code;
0620                 }
0621                 queue_path[0] = '/';
0622                 queue_path[1] = 0;
0623                 strcat(queue_path, option);
0624                 free(option);
0625             }
0626             break;
0627         }
0628     }
0629 
0630     if (continuous_mode && num_cpus_to_pin == 0) {
0631         fprintf(stderr, "Must pass at least one CPU to continuous "
0632             "mode.\n");
0633         poptPrintUsage(popt_context, stderr, 0);
0634         goto err_code;
0635     } else if (!continuous_mode) {
0636         num_cpus_to_pin = 1;
0637         cpus_to_pin[0] = cpus_online - 1;
0638     }
0639 
0640     max_msgs = fopen(MAX_MSGS, "r+");
0641     max_msgsize = fopen(MAX_MSGSIZE, "r+");
0642     if (!max_msgs)
0643         shutdown(2, "Failed to open msg_max", __LINE__);
0644     if (!max_msgsize)
0645         shutdown(2, "Failed to open msgsize_max", __LINE__);
0646 
0647     /* Load up the current system values for everything we can */
0648     getr(RLIMIT_MSGQUEUE, &saved_limits);
0649     cur_limits = saved_limits;
0650     saved_max_msgs = cur_max_msgs = get(max_msgs);
0651     saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
0652     errno = 0;
0653     cur_nice = getpriority(PRIO_PROCESS, 0);
0654     if (errno)
0655         shutdown(2, "getpriority()", __LINE__);
0656 
0657     /* Tell the user our initial state */
0658     printf("\nInitial system state:\n");
0659     printf("\tUsing queue path:\t\t\t%s\n", queue_path);
0660     printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
0661         (long) saved_limits.rlim_cur);
0662     printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
0663         (long) saved_limits.rlim_max);
0664     printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
0665     printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
0666     printf("\tNice value:\t\t\t\t%d\n", cur_nice);
0667     printf("\n");
0668 
0669     increase_limits();
0670 
0671     printf("Adjusted system state for testing:\n");
0672     if (cur_limits.rlim_cur == RLIM_INFINITY) {
0673         printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
0674         printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
0675     } else {
0676         printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
0677                (long) cur_limits.rlim_cur);
0678         printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
0679                (long) cur_limits.rlim_max);
0680     }
0681     printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
0682     printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
0683     printf("\tNice value:\t\t\t\t%d\n", cur_nice);
0684     printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
0685            (continuous_mode_fake ? "fake mode" : "enabled") :
0686            "disabled");
0687     printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
0688     for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
0689             printf(",%d", cpus_to_pin[cpu]);
0690     printf("\n");
0691 
0692     sa.sa_sigaction = sig_action_SIGUSR1;
0693     sigemptyset(&sa.sa_mask);
0694     sigaddset(&sa.sa_mask, SIGHUP);
0695     sigaddset(&sa.sa_mask, SIGINT);
0696     sigaddset(&sa.sa_mask, SIGQUIT);
0697     sigaddset(&sa.sa_mask, SIGTERM);
0698     sa.sa_flags = SA_SIGINFO;
0699     if (sigaction(SIGUSR1, &sa, NULL) == -1)
0700         shutdown(1, "sigaction(SIGUSR1)", __LINE__);
0701     sa.sa_sigaction = sig_action;
0702     if (sigaction(SIGHUP, &sa, NULL) == -1)
0703         shutdown(1, "sigaction(SIGHUP)", __LINE__);
0704     if (sigaction(SIGINT, &sa, NULL) == -1)
0705         shutdown(1, "sigaction(SIGINT)", __LINE__);
0706     if (sigaction(SIGQUIT, &sa, NULL) == -1)
0707         shutdown(1, "sigaction(SIGQUIT)", __LINE__);
0708     if (sigaction(SIGTERM, &sa, NULL) == -1)
0709         shutdown(1, "sigaction(SIGTERM)", __LINE__);
0710 
0711     if (!continuous_mode_fake) {
0712         attr.mq_flags = O_NONBLOCK;
0713         attr.mq_maxmsg = cur_max_msgs;
0714         attr.mq_msgsize = MSG_SIZE;
0715         open_queue(&attr);
0716     }
0717     for (i = 0; i < num_cpus_to_pin; i++) {
0718         pthread_attr_t thread_attr;
0719         void *thread_func;
0720 
0721         if (continuous_mode_fake)
0722             thread_func = &fake_cont_thread;
0723         else if (continuous_mode)
0724             thread_func = &cont_thread;
0725         else
0726             thread_func = &perf_test_thread;
0727 
0728         CPU_ZERO_S(cpu_set_size, cpu_set);
0729         CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
0730         pthread_attr_init(&thread_attr);
0731         pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
0732                         cpu_set);
0733         if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
0734                    NULL))
0735             shutdown(1, "pthread_create()", __LINE__);
0736         pthread_attr_destroy(&thread_attr);
0737     }
0738 
0739     if (!continuous_mode) {
0740         pthread_join(cpu_threads[0], &retval);
0741         shutdown((long)retval, "perf_test_thread()", __LINE__);
0742     } else {
0743         while (1)
0744             sleep(1);
0745     }
0746     shutdown(0, "", 0);
0747 
0748 err_code:
0749     CPU_FREE(cpu_set);
0750     exit(1);
0751 
0752 }