aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:10:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:10:18 -0400
commit08615d7d85e5aa02c05bf6c4dde87d940e7f85f6 (patch)
tree18906149d313d25914160aca21cedf54b3a7e818 /tools
parent9fdadb2cbaf4b482dfd6086e8bd3d2db071a1702 (diff)
parent0a4dd35c67b144d8ef9432120105f1aab9293ee9 (diff)
Merge branch 'akpm' (Andrew's patch-bomb)
Merge misc patches from Andrew Morton: - the "misc" tree - stuff from all over the map - checkpatch updates - fatfs - kmod changes - procfs - cpumask - UML - kexec - mqueue - rapidio - pidns - some checkpoint-restore feature work. Reluctantly. Most of it delayed a release. I'm still rather worried that we don't have a clear roadmap to completion for this work. * emailed from Andrew Morton <akpm@linux-foundation.org>: (78 patches) kconfig: update compression algorithm info c/r: prctl: add ability to set new mm_struct::exe_file c/r: prctl: extend PR_SET_MM to set up more mm_struct entries c/r: procfs: add arg_start/end, env_start/end and exit_code members to /proc/$pid/stat syscalls, x86: add __NR_kcmp syscall fs, proc: introduce /proc/<pid>/task/<tid>/children entry sysctl: make kernel.ns_last_pid control dependent on CHECKPOINT_RESTORE aio/vfs: cleanup of rw_copy_check_uvector() and compat_rw_copy_check_uvector() eventfd: change int to __u64 in eventfd_signal() fs/nls: add Apple NLS pidns: make killed children autoreap pidns: use task_active_pid_ns in do_notify_parent rapidio/tsi721: add DMA engine support rapidio: add DMA engine support for RIO data transfers ipc/mqueue: add rbtree node caching support tools/selftests: add mq_perf_tests ipc/mqueue: strengthen checks on mqueue creation ipc/mqueue: correct mq_attr_ok test ipc/mqueue: improve performance of send/recv selftests: add mq_open_tests ...
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/Makefile2
-rw-r--r--tools/testing/selftests/kcmp/Makefile29
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c94
-rw-r--r--tools/testing/selftests/mqueue/.gitignore2
-rw-r--r--tools/testing/selftests/mqueue/Makefile10
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c492
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c741
7 files changed, 1369 insertions, 1 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 28bc57ee757c..a4162e15c25f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,4 +1,4 @@
1TARGETS = breakpoints vm 1TARGETS = breakpoints kcmp mqueue vm
2 2
3all: 3all:
4 for TARGET in $(TARGETS); do \ 4 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
new file mode 100644
index 000000000000..dc79b86ea65c
--- /dev/null
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -0,0 +1,29 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
3ifeq ($(ARCH),i386)
4 ARCH := X86
5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := X86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif
11
12CFLAGS += -I../../../../arch/x86/include/generated/
13CFLAGS += -I../../../../include/
14CFLAGS += -I../../../../usr/include/
15CFLAGS += -I../../../../arch/x86/include/
16
17all:
18ifeq ($(ARCH),X86)
19 gcc $(CFLAGS) kcmp_test.c -o run_test
20else
21 echo "Not an x86 target, can't build kcmp selftest"
22endif
23
24run-tests: all
25 ./kcmp_test
26
27clean:
28 rm -fr ./run_test
29 rm -fr ./test-file
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
new file mode 100644
index 000000000000..358cc6bfa35d
--- /dev/null
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -0,0 +1,94 @@
1#define _GNU_SOURCE
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <signal.h>
6#include <limits.h>
7#include <unistd.h>
8#include <errno.h>
9#include <string.h>
10#include <fcntl.h>
11
12#include <linux/unistd.h>
13#include <linux/kcmp.h>
14
15#include <sys/syscall.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/wait.h>
19
20static long sys_kcmp(int pid1, int pid2, int type, int fd1, int fd2)
21{
22 return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2);
23}
24
25int main(int argc, char **argv)
26{
27 const char kpath[] = "kcmp-test-file";
28 int pid1, pid2;
29 int fd1, fd2;
30 int status;
31
32 fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644);
33 pid1 = getpid();
34
35 if (fd1 < 0) {
36 perror("Can't create file");
37 exit(1);
38 }
39
40 pid2 = fork();
41 if (pid2 < 0) {
42 perror("fork failed");
43 exit(1);
44 }
45
46 if (!pid2) {
47 int pid2 = getpid();
48 int ret;
49
50 fd2 = open(kpath, O_RDWR, 0644);
51 if (fd2 < 0) {
52 perror("Can't open file");
53 exit(1);
54 }
55
56 /* An example of output and arguments */
57 printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld "
58 "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld "
59 "INV: %2ld\n",
60 pid1, pid2,
61 sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd2),
62 sys_kcmp(pid1, pid2, KCMP_FILES, 0, 0),
63 sys_kcmp(pid1, pid2, KCMP_VM, 0, 0),
64 sys_kcmp(pid1, pid2, KCMP_FS, 0, 0),
65 sys_kcmp(pid1, pid2, KCMP_SIGHAND, 0, 0),
66 sys_kcmp(pid1, pid2, KCMP_IO, 0, 0),
67 sys_kcmp(pid1, pid2, KCMP_SYSVSEM, 0, 0),
68
69 /* This one should fail */
70 sys_kcmp(pid1, pid2, KCMP_TYPES + 1, 0, 0));
71
72 /* This one should return same fd */
73 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1);
74 if (ret) {
75 printf("FAIL: 0 expected but %d returned\n", ret);
76 ret = -1;
77 } else
78 printf("PASS: 0 returned as expected\n");
79
80 /* Compare with self */
81 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
82 if (ret) {
83 printf("FAIL: 0 expected but %li returned\n", ret);
84 ret = -1;
85 } else
86 printf("PASS: 0 returned as expected\n");
87
88 exit(ret);
89 }
90
91 waitpid(pid2, &status, P_ALL);
92
93 return 0;
94}
diff --git a/tools/testing/selftests/mqueue/.gitignore b/tools/testing/selftests/mqueue/.gitignore
new file mode 100644
index 000000000000..d8d42377205a
--- /dev/null
+++ b/tools/testing/selftests/mqueue/.gitignore
@@ -0,0 +1,2 @@
1mq_open_tests
2mq_perf_tests
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
new file mode 100644
index 000000000000..54c0aad2b47c
--- /dev/null
+++ b/tools/testing/selftests/mqueue/Makefile
@@ -0,0 +1,10 @@
1all:
2 gcc -O2 -lrt mq_open_tests.c -o mq_open_tests
3 gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c
4
5run_tests:
6 ./mq_open_tests /test1
7 ./mq_perf_tests
8
9clean:
10 rm -f mq_open_tests mq_perf_tests
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
new file mode 100644
index 000000000000..711cc2923047
--- /dev/null
+++ b/tools/testing/selftests/mqueue/mq_open_tests.c
@@ -0,0 +1,492 @@
1/*
2 * This application is Copyright 2012 Red Hat, Inc.
3 * Doug Ledford <dledford@redhat.com>
4 *
5 * mq_open_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_open_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_open_tests.c
17 * Tests the various situations that should either succeed or fail to
18 * open a posix message queue and then reports whether or not they
19 * did as they were supposed to.
20 *
21 */
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <string.h>
27#include <limits.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/time.h>
31#include <sys/resource.h>
32#include <sys/stat.h>
33#include <mqueue.h>
34
35static char *usage =
36"Usage:\n"
37" %s path\n"
38"\n"
39" path Path name of the message queue to create\n"
40"\n"
41" Note: this program must be run as root in order to enable all tests\n"
42"\n";
43
44char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
45char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
46char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
47char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
48
49int default_settings;
50struct rlimit saved_limits, cur_limits;
51int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
52int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
53FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
54char *queue_path;
55mqd_t queue = -1;
56
57static inline void __set(FILE *stream, int value, char *err_msg);
58void shutdown(int exit_val, char *err_cause, int line_no);
59static inline int get(FILE *stream);
60static inline void set(FILE *stream, int value);
61static inline void getr(int type, struct rlimit *rlim);
62static inline void setr(int type, struct rlimit *rlim);
63void validate_current_settings();
64static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
65static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
66
67static inline void __set(FILE *stream, int value, char *err_msg)
68{
69 rewind(stream);
70 if (fprintf(stream, "%d", value) < 0)
71 perror(err_msg);
72}
73
74
75void shutdown(int exit_val, char *err_cause, int line_no)
76{
77 static int in_shutdown = 0;
78
79 /* In case we get called recursively by a set() call below */
80 if (in_shutdown++)
81 return;
82
83 seteuid(0);
84
85 if (queue != -1)
86 if (mq_close(queue))
87 perror("mq_close() during shutdown");
88 if (queue_path)
89 /*
90 * Be silent if this fails, if we cleaned up already it's
91 * expected to fail
92 */
93 mq_unlink(queue_path);
94 if (default_settings) {
95 if (saved_def_msgs)
96 __set(def_msgs, saved_def_msgs,
97 "failed to restore saved_def_msgs");
98 if (saved_def_msgsize)
99 __set(def_msgsize, saved_def_msgsize,
100 "failed to restore saved_def_msgsize");
101 }
102 if (saved_max_msgs)
103 __set(max_msgs, saved_max_msgs,
104 "failed to restore saved_max_msgs");
105 if (saved_max_msgsize)
106 __set(max_msgsize, saved_max_msgsize,
107 "failed to restore saved_max_msgsize");
108 if (exit_val)
109 error(exit_val, errno, "%s at %d", err_cause, line_no);
110 exit(0);
111}
112
113static inline int get(FILE *stream)
114{
115 int value;
116 rewind(stream);
117 if (fscanf(stream, "%d", &value) != 1)
118 shutdown(4, "Error reading /proc entry", __LINE__ - 1);
119 return value;
120}
121
122static inline void set(FILE *stream, int value)
123{
124 int new_value;
125
126 rewind(stream);
127 if (fprintf(stream, "%d", value) < 0)
128 return shutdown(5, "Failed writing to /proc file",
129 __LINE__ - 1);
130 new_value = get(stream);
131 if (new_value != value)
132 return shutdown(5, "We didn't get what we wrote to /proc back",
133 __LINE__ - 1);
134}
135
136static inline void getr(int type, struct rlimit *rlim)
137{
138 if (getrlimit(type, rlim))
139 shutdown(6, "getrlimit()", __LINE__ - 1);
140}
141
142static inline void setr(int type, struct rlimit *rlim)
143{
144 if (setrlimit(type, rlim))
145 shutdown(7, "setrlimit()", __LINE__ - 1);
146}
147
148void validate_current_settings()
149{
150 int rlim_needed;
151
152 if (cur_limits.rlim_cur < 4096) {
153 printf("Current rlimit value for POSIX message queue bytes is "
154 "unreasonably low,\nincreasing.\n\n");
155 cur_limits.rlim_cur = 8192;
156 cur_limits.rlim_max = 16384;
157 setr(RLIMIT_MSGQUEUE, &cur_limits);
158 }
159
160 if (default_settings) {
161 rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
162 2 * sizeof(void *));
163 if (rlim_needed > cur_limits.rlim_cur) {
164 printf("Temporarily lowering default queue parameters "
165 "to something that will work\n"
166 "with the current rlimit values.\n\n");
167 set(def_msgs, 10);
168 cur_def_msgs = 10;
169 set(def_msgsize, 128);
170 cur_def_msgsize = 128;
171 }
172 } else {
173 rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
174 2 * sizeof(void *));
175 if (rlim_needed > cur_limits.rlim_cur) {
176 printf("Temporarily lowering maximum queue parameters "
177 "to something that will work\n"
178 "with the current rlimit values in case this is "
179 "a kernel that ties the default\n"
180 "queue parameters to the maximum queue "
181 "parameters.\n\n");
182 set(max_msgs, 10);
183 cur_max_msgs = 10;
184 set(max_msgsize, 128);
185 cur_max_msgsize = 128;
186 }
187 }
188}
189
190/*
191 * test_queue - Test opening a queue, shutdown if we fail. This should
192 * only be called in situations that should never fail. We clean up
193 * after ourselves and return the queue attributes in *result.
194 */
195static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
196{
197 int flags = O_RDWR | O_EXCL | O_CREAT;
198 int perms = DEFFILEMODE;
199
200 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
201 shutdown(1, "mq_open()", __LINE__);
202 if (mq_getattr(queue, result))
203 shutdown(1, "mq_getattr()", __LINE__);
204 if (mq_close(queue))
205 shutdown(1, "mq_close()", __LINE__);
206 queue = -1;
207 if (mq_unlink(queue_path))
208 shutdown(1, "mq_unlink()", __LINE__);
209}
210
211/*
212 * Same as test_queue above, but failure is not fatal.
213 * Returns:
214 * 0 - Failed to create a queue
215 * 1 - Created a queue, attributes in *result
216 */
217static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
218{
219 int flags = O_RDWR | O_EXCL | O_CREAT;
220 int perms = DEFFILEMODE;
221
222 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
223 return 0;
224 if (mq_getattr(queue, result))
225 shutdown(1, "mq_getattr()", __LINE__);
226 if (mq_close(queue))
227 shutdown(1, "mq_close()", __LINE__);
228 queue = -1;
229 if (mq_unlink(queue_path))
230 shutdown(1, "mq_unlink()", __LINE__);
231 return 1;
232}
233
234int main(int argc, char *argv[])
235{
236 struct mq_attr attr, result;
237
238 if (argc != 2) {
239 fprintf(stderr, "Must pass a valid queue name\n\n");
240 fprintf(stderr, usage, argv[0]);
241 exit(1);
242 }
243
244 /*
245 * Although we can create a msg queue with a non-absolute path name,
246 * unlink will fail. So, if the name doesn't start with a /, add one
247 * when we save it.
248 */
249 if (*argv[1] == '/')
250 queue_path = strdup(argv[1]);
251 else {
252 queue_path = malloc(strlen(argv[1]) + 2);
253 if (!queue_path) {
254 perror("malloc()");
255 exit(1);
256 }
257 queue_path[0] = '/';
258 queue_path[1] = 0;
259 strcat(queue_path, argv[1]);
260 }
261
262 if (getuid() != 0) {
263 fprintf(stderr, "Not running as root, but almost all tests "
264 "require root in order to modify\nsystem settings. "
265 "Exiting.\n");
266 exit(1);
267 }
268
269 /* Find out what files there are for us to make tweaks in */
270 def_msgs = fopen(DEF_MSGS, "r+");
271 def_msgsize = fopen(DEF_MSGSIZE, "r+");
272 max_msgs = fopen(MAX_MSGS, "r+");
273 max_msgsize = fopen(MAX_MSGSIZE, "r+");
274
275 if (!max_msgs)
276 shutdown(2, "Failed to open msg_max", __LINE__);
277 if (!max_msgsize)
278 shutdown(2, "Failed to open msgsize_max", __LINE__);
279 if (def_msgs || def_msgsize)
280 default_settings = 1;
281
282 /* Load up the current system values for everything we can */
283 getr(RLIMIT_MSGQUEUE, &saved_limits);
284 cur_limits = saved_limits;
285 if (default_settings) {
286 saved_def_msgs = cur_def_msgs = get(def_msgs);
287 saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
288 }
289 saved_max_msgs = cur_max_msgs = get(max_msgs);
290 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
291
292 /* Tell the user our initial state */
293 printf("\nInitial system state:\n");
294 printf("\tUsing queue path:\t\t%s\n", queue_path);
295 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
296 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
297 printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
298 printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
299 if (default_settings) {
300 printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
301 printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
302 } else {
303 printf("\tDefault Message Size:\t\tNot Supported\n");
304 printf("\tDefault Queue Size:\t\tNot Supported\n");
305 }
306 printf("\n");
307
308 validate_current_settings();
309
310 printf("Adjusted system state for testing:\n");
311 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
312 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
313 printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
314 printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
315 if (default_settings) {
316 printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
317 printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
318 }
319
320 printf("\n\nTest series 1, behavior when no attr struct "
321 "passed to mq_open:\n");
322 if (!default_settings) {
323 test_queue(NULL, &result);
324 printf("Given sane system settings, mq_open without an attr "
325 "struct succeeds:\tPASS\n");
326 if (result.mq_maxmsg != cur_max_msgs ||
327 result.mq_msgsize != cur_max_msgsize) {
328 printf("Kernel does not support setting the default "
329 "mq attributes,\nbut also doesn't tie the "
330 "defaults to the maximums:\t\t\tPASS\n");
331 } else {
332 set(max_msgs, ++cur_max_msgs);
333 set(max_msgsize, ++cur_max_msgsize);
334 test_queue(NULL, &result);
335 if (result.mq_maxmsg == cur_max_msgs &&
336 result.mq_msgsize == cur_max_msgsize)
337 printf("Kernel does not support setting the "
338 "default mq attributes and\n"
339 "also ties system wide defaults to "
340 "the system wide maximums:\t\t"
341 "FAIL\n");
342 else
343 printf("Kernel does not support setting the "
344 "default mq attributes,\n"
345 "but also doesn't tie the defaults to "
346 "the maximums:\t\t\tPASS\n");
347 }
348 } else {
349 printf("Kernel supports setting defaults separately from "
350 "maximums:\t\tPASS\n");
351 /*
352 * While we are here, go ahead and test that the kernel
353 * properly follows the default settings
354 */
355 test_queue(NULL, &result);
356 printf("Given sane values, mq_open without an attr struct "
357 "succeeds:\t\tPASS\n");
358 if (result.mq_maxmsg != cur_def_msgs ||
359 result.mq_msgsize != cur_def_msgsize)
360 printf("Kernel supports setting defaults, but does "
361 "not actually honor them:\tFAIL\n\n");
362 else {
363 set(def_msgs, ++cur_def_msgs);
364 set(def_msgsize, ++cur_def_msgsize);
365 /* In case max was the same as the default */
366 set(max_msgs, ++cur_max_msgs);
367 set(max_msgsize, ++cur_max_msgsize);
368 test_queue(NULL, &result);
369 if (result.mq_maxmsg != cur_def_msgs ||
370 result.mq_msgsize != cur_def_msgsize)
371 printf("Kernel supports setting defaults, but "
372 "does not actually honor them:\t"
373 "FAIL\n");
374 else
375 printf("Kernel properly honors default setting "
376 "knobs:\t\t\t\tPASS\n");
377 }
378 set(def_msgs, cur_max_msgs + 1);
379 cur_def_msgs = cur_max_msgs + 1;
380 set(def_msgsize, cur_max_msgsize + 1);
381 cur_def_msgsize = cur_max_msgsize + 1;
382 if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
383 cur_limits.rlim_cur) {
384 cur_limits.rlim_cur = (cur_def_msgs + 2) *
385 (cur_def_msgsize + 2 * sizeof(void *));
386 cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
387 setr(RLIMIT_MSGQUEUE, &cur_limits);
388 }
389 if (test_queue_fail(NULL, &result)) {
390 if (result.mq_maxmsg == cur_max_msgs &&
391 result.mq_msgsize == cur_max_msgsize)
392 printf("Kernel properly limits default values "
393 "to lesser of default/max:\t\tPASS\n");
394 else
395 printf("Kernel does not properly set default "
396 "queue parameters when\ndefaults > "
397 "max:\t\t\t\t\t\t\t\tFAIL\n");
398 } else
399 printf("Kernel fails to open mq because defaults are "
400 "greater than maximums:\tFAIL\n");
401 set(def_msgs, --cur_def_msgs);
402 set(def_msgsize, --cur_def_msgsize);
403 cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
404 cur_def_msgsize;
405 setr(RLIMIT_MSGQUEUE, &cur_limits);
406 if (test_queue_fail(NULL, &result))
407 printf("Kernel creates queue even though defaults "
408 "would exceed\nrlimit setting:"
409 "\t\t\t\t\t\t\t\tFAIL\n");
410 else
411 printf("Kernel properly fails to create queue when "
412 "defaults would\nexceed rlimit:"
413 "\t\t\t\t\t\t\t\tPASS\n");
414 }
415
416 /*
417 * Test #2 - open with an attr struct that exceeds rlimit
418 */
419 printf("\n\nTest series 2, behavior when attr struct is "
420 "passed to mq_open:\n");
421 cur_max_msgs = 32;
422 cur_max_msgsize = cur_limits.rlim_max >> 4;
423 set(max_msgs, cur_max_msgs);
424 set(max_msgsize, cur_max_msgsize);
425 attr.mq_maxmsg = cur_max_msgs;
426 attr.mq_msgsize = cur_max_msgsize;
427 if (test_queue_fail(&attr, &result))
428 printf("Queue open in excess of rlimit max when euid = 0 "
429 "succeeded:\t\tFAIL\n");
430 else
431 printf("Queue open in excess of rlimit max when euid = 0 "
432 "failed:\t\tPASS\n");
433 attr.mq_maxmsg = cur_max_msgs + 1;
434 attr.mq_msgsize = 10;
435 if (test_queue_fail(&attr, &result))
436 printf("Queue open with mq_maxmsg > limit when euid = 0 "
437 "succeeded:\t\tPASS\n");
438 else
439 printf("Queue open with mq_maxmsg > limit when euid = 0 "
440 "failed:\t\tFAIL\n");
441 attr.mq_maxmsg = 1;
442 attr.mq_msgsize = cur_max_msgsize + 1;
443 if (test_queue_fail(&attr, &result))
444 printf("Queue open with mq_msgsize > limit when euid = 0 "
445 "succeeded:\t\tPASS\n");
446 else
447 printf("Queue open with mq_msgsize > limit when euid = 0 "
448 "failed:\t\tFAIL\n");
449 attr.mq_maxmsg = 65536;
450 attr.mq_msgsize = 65536;
451 if (test_queue_fail(&attr, &result))
452 printf("Queue open with total size > 2GB when euid = 0 "
453 "succeeded:\t\tFAIL\n");
454 else
455 printf("Queue open with total size > 2GB when euid = 0 "
456 "failed:\t\t\tPASS\n");
457 seteuid(99);
458 attr.mq_maxmsg = cur_max_msgs;
459 attr.mq_msgsize = cur_max_msgsize;
460 if (test_queue_fail(&attr, &result))
461 printf("Queue open in excess of rlimit max when euid = 99 "
462 "succeeded:\t\tFAIL\n");
463 else
464 printf("Queue open in excess of rlimit max when euid = 99 "
465 "failed:\t\tPASS\n");
466 attr.mq_maxmsg = cur_max_msgs + 1;
467 attr.mq_msgsize = 10;
468 if (test_queue_fail(&attr, &result))
469 printf("Queue open with mq_maxmsg > limit when euid = 99 "
470 "succeeded:\t\tFAIL\n");
471 else
472 printf("Queue open with mq_maxmsg > limit when euid = 99 "
473 "failed:\t\tPASS\n");
474 attr.mq_maxmsg = 1;
475 attr.mq_msgsize = cur_max_msgsize + 1;
476 if (test_queue_fail(&attr, &result))
477 printf("Queue open with mq_msgsize > limit when euid = 99 "
478 "succeeded:\t\tFAIL\n");
479 else
480 printf("Queue open with mq_msgsize > limit when euid = 99 "
481 "failed:\t\tPASS\n");
482 attr.mq_maxmsg = 65536;
483 attr.mq_msgsize = 65536;
484 if (test_queue_fail(&attr, &result))
485 printf("Queue open with total size > 2GB when euid = 99 "
486 "succeeded:\t\tFAIL\n");
487 else
488 printf("Queue open with total size > 2GB when euid = 99 "
489 "failed:\t\t\tPASS\n");
490
491 shutdown(0,"",0);
492}
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
new file mode 100644
index 000000000000..2fadd4b97045
--- /dev/null
+++ b/tools/testing/selftests/mqueue/mq_perf_tests.c
@@ -0,0 +1,741 @@
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)");
299 printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg);
300 printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize);
301 printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs);
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);
443 printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec,
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();
457 printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
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;
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",
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;
466 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
467
468
469 for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
470 printf(cur_test->desc);
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");
496 printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
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;
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",
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;
505 printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
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;
539 int i, cpu;
540 struct sigaction sa;
541 poptContext popt_context;
542 char rc;
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%d\n", saved_limits.rlim_cur);
657 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
658 printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
659 printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
660 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
661 printf("\n");
662
663 increase_limits();
664
665 printf("Adjusted system state for testing:\n");
666 if (cur_limits.rlim_cur == RLIM_INFINITY) {
667 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
668 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
669 } else {
670 printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
671 cur_limits.rlim_cur);
672 printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
673 cur_limits.rlim_max);
674 }
675 printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
676 printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
677 printf("\tNice value:\t\t\t\t%d\n", cur_nice);
678 printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
679 (continuous_mode_fake ? "fake mode" : "enabled") :
680 "disabled");
681 printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
682 for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
683 printf(",%d", cpus_to_pin[cpu]);
684 printf("\n");
685
686 sa.sa_sigaction = sig_action_SIGUSR1;
687 sigemptyset(&sa.sa_mask);
688 sigaddset(&sa.sa_mask, SIGHUP);
689 sigaddset(&sa.sa_mask, SIGINT);
690 sigaddset(&sa.sa_mask, SIGQUIT);
691 sigaddset(&sa.sa_mask, SIGTERM);
692 sa.sa_flags = SA_SIGINFO;
693 if (sigaction(SIGUSR1, &sa, NULL) == -1)
694 shutdown(1, "sigaction(SIGUSR1)", __LINE__);
695 sa.sa_sigaction = sig_action;
696 if (sigaction(SIGHUP, &sa, NULL) == -1)
697 shutdown(1, "sigaction(SIGHUP)", __LINE__);
698 if (sigaction(SIGINT, &sa, NULL) == -1)
699 shutdown(1, "sigaction(SIGINT)", __LINE__);
700 if (sigaction(SIGQUIT, &sa, NULL) == -1)
701 shutdown(1, "sigaction(SIGQUIT)", __LINE__);
702 if (sigaction(SIGTERM, &sa, NULL) == -1)
703 shutdown(1, "sigaction(SIGTERM)", __LINE__);
704
705 if (!continuous_mode_fake) {
706 attr.mq_flags = O_NONBLOCK;
707 attr.mq_maxmsg = cur_max_msgs;
708 attr.mq_msgsize = MSG_SIZE;
709 open_queue(&attr);
710 }
711 for (i = 0; i < num_cpus_to_pin; i++) {
712 pthread_attr_t thread_attr;
713 void *thread_func;
714
715 if (continuous_mode_fake)
716 thread_func = &fake_cont_thread;
717 else if (continuous_mode)
718 thread_func = &cont_thread;
719 else
720 thread_func = &perf_test_thread;
721
722 CPU_ZERO_S(cpu_set_size, cpu_set);
723 CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
724 pthread_attr_init(&thread_attr);
725 pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
726 cpu_set);
727 if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
728 NULL))
729 shutdown(1, "pthread_create()", __LINE__);
730 pthread_attr_destroy(&thread_attr);
731 }
732
733 if (!continuous_mode) {
734 pthread_join(cpu_threads[0], &retval);
735 shutdown((long)retval, "perf_test_thread()", __LINE__);
736 } else {
737 while (1)
738 sleep(1);
739 }
740 shutdown(0, "", 0);
741}