Merge remote-tracking branches 'spi/topic/orion', 'spi/topic/pxa2xx', 'spi/topic...
[linux-2.6-block.git] / tools / testing / selftests / mqueue / mq_perf_tests.c
CommitLineData
7820b071
DL
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)");
f15fed3d
SK
299 printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
300 printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
301 printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
7820b071
DL
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);
f15fed3d 443 printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
7820b071
DL
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();
f15fed3d 457 printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
7820b071
DL
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;
f15fed3d
SK
461 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
462 printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
7820b071
DL
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;
f15fed3d 466 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
7820b071
DL
467
468
469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
f15fed3d 470 printf("%s:\n", cur_test->desc);
7820b071
DL
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");
f15fed3d 496 printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
7820b071
DL
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;
f15fed3d
SK
500 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
501 printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
7820b071
DL
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;
f15fed3d 505 printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
7820b071
DL
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;
13e634de 539 int i, cpu, rc;
7820b071
DL
540 struct sigaction sa;
541 poptContext popt_context;
7820b071
DL
542 void *retval;
543
544 main_thread = pthread_self();
545 num_cpus_to_pin = 0;
546
547 if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
548 perror("sysconf(_SC_NPROCESSORS_ONLN)");
549 exit(1);
550 }
551 cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
552 cpu_set = CPU_ALLOC(cpus_online);
553 if (cpu_set == NULL) {
554 perror("CPU_ALLOC()");
555 exit(1);
556 }
557 cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
558 CPU_ZERO_S(cpu_set_size, cpu_set);
559
560 popt_context = poptGetContext(NULL, argc, (const char **)argv,
561 options, 0);
562
563 while ((rc = poptGetNextOpt(popt_context)) > 0) {
564 switch (rc) {
565 case 'c':
566 continuous_mode = 1;
567 option = cpu_option_string;
568 do {
569 next_option = strchr(option, ',');
570 if (next_option)
571 *next_option = '\0';
572 cpu = atoi(option);
573 if (cpu >= cpus_online)
574 fprintf(stderr, "CPU %d exceeds "
575 "cpus online, ignoring.\n",
576 cpu);
577 else
578 cpus_to_pin[num_cpus_to_pin++] = cpu;
579 if (next_option)
580 option = ++next_option;
581 } while (next_option && num_cpus_to_pin < MAX_CPUS);
582 /* Double check that they didn't give us the same CPU
583 * more than once */
584 for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
585 if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
586 cpu_set)) {
587 fprintf(stderr, "Any given CPU may "
588 "only be given once.\n");
589 exit(1);
590 } else
591 CPU_SET_S(cpus_to_pin[cpu],
592 cpu_set_size, cpu_set);
593 }
594 break;
595 case 'p':
596 /*
597 * Although we can create a msg queue with a
598 * non-absolute path name, unlink will fail. So,
599 * if the name doesn't start with a /, add one
600 * when we save it.
601 */
602 option = queue_path;
603 if (*option != '/') {
604 queue_path = malloc(strlen(option) + 2);
605 if (!queue_path) {
606 perror("malloc()");
607 exit(1);
608 }
609 queue_path[0] = '/';
610 queue_path[1] = 0;
611 strcat(queue_path, option);
612 free(option);
613 }
614 break;
615 }
616 }
617
618 if (continuous_mode && num_cpus_to_pin == 0) {
619 fprintf(stderr, "Must pass at least one CPU to continuous "
620 "mode.\n");
621 poptPrintUsage(popt_context, stderr, 0);
622 exit(1);
623 } else if (!continuous_mode) {
624 num_cpus_to_pin = 1;
625 cpus_to_pin[0] = cpus_online - 1;
626 }
627
628 if (getuid() != 0) {
629 fprintf(stderr, "Not running as root, but almost all tests "
630 "require root in order to modify\nsystem settings. "
631 "Exiting.\n");
632 exit(1);
633 }
634
635 max_msgs = fopen(MAX_MSGS, "r+");
636 max_msgsize = fopen(MAX_MSGSIZE, "r+");
637 if (!max_msgs)
638 shutdown(2, "Failed to open msg_max", __LINE__);
639 if (!max_msgsize)
640 shutdown(2, "Failed to open msgsize_max", __LINE__);
641
642 /* Load up the current system values for everything we can */
643 getr(RLIMIT_MSGQUEUE, &saved_limits);
644 cur_limits = saved_limits;
645 saved_max_msgs = cur_max_msgs = get(max_msgs);
646 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
647 errno = 0;
648 cur_nice = getpriority(PRIO_PROCESS, 0);
649 if (errno)
650 shutdown(2, "getpriority()", __LINE__);
651
652 /* Tell the user our initial state */
653 printf("\nInitial system state:\n");
654 printf("\tUsing queue path:\t\t\t%s\n", queue_path);
f15fed3d
SK
655 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
656 (long) saved_limits.rlim_cur);
657 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
658 (long) saved_limits.rlim_max);
7820b071
DL
659 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
660 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
661 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
662 printf("\n");
663
664 increase_limits();
665
666 printf("Adjusted system state for testing:\n");
667 if (cur_limits.rlim_cur == RLIM_INFINITY) {
668 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
669 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
670 } else {
f15fed3d
SK
671 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
672 (long) cur_limits.rlim_cur);
673 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
674 (long) cur_limits.rlim_max);
7820b071
DL
675 }
676 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
677 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
678 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
679 printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
680 (continuous_mode_fake ? "fake mode" : "enabled") :
681 "disabled");
682 printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
683 for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
684 printf(",%d", cpus_to_pin[cpu]);
685 printf("\n");
686
687 sa.sa_sigaction = sig_action_SIGUSR1;
688 sigemptyset(&sa.sa_mask);
689 sigaddset(&sa.sa_mask, SIGHUP);
690 sigaddset(&sa.sa_mask, SIGINT);
691 sigaddset(&sa.sa_mask, SIGQUIT);
692 sigaddset(&sa.sa_mask, SIGTERM);
693 sa.sa_flags = SA_SIGINFO;
694 if (sigaction(SIGUSR1, &sa, NULL) == -1)
695 shutdown(1, "sigaction(SIGUSR1)", __LINE__);
696 sa.sa_sigaction = sig_action;
697 if (sigaction(SIGHUP, &sa, NULL) == -1)
698 shutdown(1, "sigaction(SIGHUP)", __LINE__);
699 if (sigaction(SIGINT, &sa, NULL) == -1)
700 shutdown(1, "sigaction(SIGINT)", __LINE__);
701 if (sigaction(SIGQUIT, &sa, NULL) == -1)
702 shutdown(1, "sigaction(SIGQUIT)", __LINE__);
703 if (sigaction(SIGTERM, &sa, NULL) == -1)
704 shutdown(1, "sigaction(SIGTERM)", __LINE__);
705
706 if (!continuous_mode_fake) {
707 attr.mq_flags = O_NONBLOCK;
708 attr.mq_maxmsg = cur_max_msgs;
709 attr.mq_msgsize = MSG_SIZE;
710 open_queue(&attr);
711 }
712 for (i = 0; i < num_cpus_to_pin; i++) {
713 pthread_attr_t thread_attr;
714 void *thread_func;
715
716 if (continuous_mode_fake)
717 thread_func = &fake_cont_thread;
718 else if (continuous_mode)
719 thread_func = &cont_thread;
720 else
721 thread_func = &perf_test_thread;
722
723 CPU_ZERO_S(cpu_set_size, cpu_set);
724 CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
725 pthread_attr_init(&thread_attr);
726 pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
727 cpu_set);
728 if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
729 NULL))
730 shutdown(1, "pthread_create()", __LINE__);
731 pthread_attr_destroy(&thread_attr);
732 }
733
734 if (!continuous_mode) {
735 pthread_join(cpu_threads[0], &retval);
736 shutdown((long)retval, "perf_test_thread()", __LINE__);
737 } else {
738 while (1)
739 sleep(1);
740 }
741 shutdown(0, "", 0);
742}