34 #include <sys/types.h>
36 #include <sys/resource.h>
43 " %s [-c #[,#..] -f] path\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"
67 " Note: this program must be run as root in order to enable all tests\n"
70 char *
MAX_MSGS =
"/proc/sys/fs/mqueue/msg_max";
73 #define min(a, b) ((a) < (b) ? (a) : (b))
85 #define TEST1_LOOPS 10000000
86 #define TEST2_LOOPS 100000
102 .longName =
"continuous",
104 .argInfo = POPT_ARG_STRING,
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 "
120 .argDescrip =
"cpu[,cpu]",
125 .argInfo = POPT_ARG_NONE,
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",
139 .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
142 .descrip =
"The name of the path to use in the mqueue "
143 "filesystem for our tests",
144 .argDescrip =
"pathname",
150 static inline void __set(FILE *stream,
int value,
char *
err_msg);
151 void shutdown(
int exit_val,
char *err_cause,
int line_no);
154 static inline int get(FILE *
stream);
156 static inline int try_set(FILE *stream,
int value);
157 static inline void getr(
int type,
struct rlimit *rlim);
158 static inline void setr(
int type,
struct rlimit *rlim);
159 static inline void open_queue(
struct mq_attr *
attr);
162 static inline void __set(FILE *stream,
int value,
char *
err_msg)
165 if (
fprintf(stream,
"%d", value) < 0)
170 void shutdown(
int exit_val,
char *err_cause,
int line_no)
172 static int in_shutdown = 0;
173 int errno_at_shutdown =
errno;
188 perror(
"mq_close() during shutdown");
197 "failed to restore saved_max_msgs");
200 "failed to restore saved_max_msgsize");
202 error(exit_val, errno_at_shutdown,
"%s at %d",
212 fprintf(stderr,
"Caught signal %d in SIGUSR1 handler, "
213 "exiting\n", signum);
215 fprintf(stderr,
"\n\nReturned from shutdown?!?!\n\n");
225 fprintf(stderr,
"Caught signal %d, exiting\n", signum);
227 fprintf(stderr,
"\n\nReturned from shutdown?!?!\n\n");
232 static inline int get(FILE *stream)
236 if (fscanf(stream,
"%d", &value) != 1)
237 shutdown(4,
"Error reading /proc entry", __LINE__);
241 static inline void set(FILE *stream,
int value)
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",
254 static inline int try_set(FILE *stream,
int value)
260 new_value =
get(stream);
261 return new_value ==
value;
264 static inline void getr(
int type,
struct rlimit *rlim)
267 shutdown(6,
"getrlimit()", __LINE__);
270 static inline void setr(
int type,
struct rlimit *rlim)
272 if (setrlimit(type, rlim))
273 shutdown(7,
"setrlimit()", __LINE__);
286 static inline void open_queue(
struct mq_attr *
attr)
289 int perms = DEFFILEMODE;
295 shutdown(1,
"mq_getattr()", __LINE__);
298 "O_NONBLOCK" :
"(null)");
311 printf(
"\tStarted fake continuous mode thread %d on CPU %d\n", i,
325 printf(
"\tStarted continuous mode thread %d on CPU %d\n", i,
328 while (mq_send(
queue, buff,
sizeof(buff), 0) == 0)
330 mq_receive(
queue, buff,
sizeof(buff), &priority);
334 #define drain_queue() \
335 while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
337 #define do_untimed_send() \
339 if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
340 shutdown(3, "Test send failure", __LINE__); \
343 #define do_send_recv() \
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; \
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; \
396 {
"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
398 {
"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
400 {
"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
402 {
"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
422 int prio_out, prio_in;
426 struct timespec res, start, middle, end, send_total, recv_total;
427 unsigned long long nsec;
428 struct test *cur_test;
431 printf(
"\n\tStarted mqueue performance test thread on CPU %d\n",
435 shutdown(2,
"sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
436 if (pthread_getcpuclockid(
cpu_threads[0], &clock) != 0)
437 shutdown(2,
"pthread_getcpuclockid", __LINE__);
439 if (clock_getres(clock, &res))
440 shutdown(2,
"clock_getres()", __LINE__);
448 printf(
"\n\tTest #1: Time send/recv message, queue empty\n");
457 printf(
"\t\tSend msg:\t\t\t%d.%ds total time\n",
459 nsec = ((
unsigned long long)send_total.
tv_sec * 1000000000 +
461 printf(
"\t\t\t\t\t\t%d nsec/msg\n", nsec);
462 printf(
"\t\tRecv msg:\t\t\t%d.%ds total time\n",
464 nsec = ((
unsigned long long)recv_total.
tv_sec * 1000000000 +
466 printf(
"\t\t\t\t\t\t%d nsec/msg\n", nsec);
469 for (cur_test = test2; cur_test->desc !=
NULL; cur_test++) {
477 printf(
"\t\tFilling queue...");
480 for (i = 0; i <
result.mq_maxmsg - 1; i++) {
482 cur_test->func(&prio_out);
487 printf(
"done.\t\t%lld.%llds\n", nsec / 1000000000,
493 cur_test->func(&prio_out);
496 printf(
"\t\tSend msg:\t\t\t%d.%ds total time\n",
498 nsec = ((
unsigned long long)send_total.
tv_sec * 1000000000 +
500 printf(
"\t\t\t\t\t\t%d nsec/msg\n", nsec);
501 printf(
"\t\tRecv msg:\t\t\t%d.%ds total time\n",
503 nsec = ((
unsigned long long)recv_total.
tv_sec * 1000000000 +
505 printf(
"\t\t\t\t\t\t%d nsec/msg\n", nsec);
506 printf(
"\t\tDraining queue...");
513 printf(
"done.\t\t%lld.%llds\n", nsec / 1000000000,
531 shutdown(2,
"setpriority()", __LINE__);
538 char *
option, *next_option;
541 poptContext popt_context;
548 if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
549 perror(
"sysconf(_SC_NPROCESSORS_ONLN)");
555 perror(
"CPU_ALLOC()");
561 popt_context = poptGetContext(
NULL, argc, (
const char **)argv,
564 while ((rc = poptGetNextOpt(popt_context)) > 0) {
570 next_option =
strchr(option,
',');
575 fprintf(stderr,
"CPU %d exceeds "
576 "cpus online, ignoring.\n",
581 option = ++next_option;
582 }
while (next_option && num_cpus_to_pin <
MAX_CPUS);
588 fprintf(stderr,
"Any given CPU may "
589 "only be given once.\n");
604 if (*option !=
'/') {
620 fprintf(stderr,
"Must pass at least one CPU to continuous "
622 poptPrintUsage(popt_context, stderr, 0);
630 fprintf(stderr,
"Not running as root, but almost all tests "
631 "require root in order to modify\nsystem settings. "
639 shutdown(2,
"Failed to open msg_max", __LINE__);
641 shutdown(2,
"Failed to open msgsize_max", __LINE__);
651 shutdown(2,
"getpriority()", __LINE__);
654 printf(
"\nInitial system state:\n");
656 printf(
"\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur);
657 printf(
"\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
665 printf(
"Adjusted system state for testing:\n");
667 printf(
"\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
668 printf(
"\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
670 printf(
"\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
672 printf(
"\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
694 shutdown(1,
"sigaction(SIGUSR1)", __LINE__);
697 shutdown(1,
"sigaction(SIGHUP)", __LINE__);
699 shutdown(1,
"sigaction(SIGINT)", __LINE__);
701 shutdown(1,
"sigaction(SIGQUIT)", __LINE__);
703 shutdown(1,
"sigaction(SIGTERM)", __LINE__);
712 pthread_attr_t thread_attr;
724 pthread_attr_init(&thread_attr);
727 if (pthread_create(&
cpu_threads[i], &thread_attr, thread_func,
729 shutdown(1,
"pthread_create()", __LINE__);
730 pthread_attr_destroy(&thread_attr);
735 shutdown((
long)retval,
"perf_test_thread()", __LINE__);