Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932890AbbFIM4T (ORCPT ); Tue, 9 Jun 2015 08:56:19 -0400 Received: from lists.s-osg.org ([54.187.51.154]:38729 "EHLO lists.s-osg.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753857AbbFIM4H (ORCPT ); Tue, 9 Jun 2015 08:56:07 -0400 Message-ID: <5576E25E.40600@osg.samsung.com> Date: Tue, 09 Jun 2015 06:55:58 -0600 From: Shuah Khan Organization: Samsung Open Source Group User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: Davidlohr Bueso , Andrew Morton CC: linux-kernel@vger.kernel.org, Shuah Khan Subject: Re: [PATCH -next] selftests/ipc: Consolidate posix and sysv msg queue tests References: <1433807517.3165.32.camel@stgolabs.net> In-Reply-To: <1433807517.3165.32.camel@stgolabs.net> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 103660 Lines: 3233 On 06/08/2015 05:51 PM, Davidlohr Bueso wrote: > Move them both in the their own directory, under selftests/ipc/. > As with the actual code, all forms of ipc tend to reside in the > same directory, so apply this to selftests. > > Keep the Makefiles (at least for now), with some minor path > hierarchy tweaks, for both msg and mqueue. Add a trivial > ipc/Makefile that simply passes the building to the individual > subdirectory. > > Signed-off-by: Davidlohr Bueso Looks good in general. Please see comments below. > --- > tools/testing/selftests/ipc/.gitignore | 3 + > tools/testing/selftests/ipc/Makefile | 32 +- > tools/testing/selftests/ipc/mqueue/Makefile | 22 + > tools/testing/selftests/ipc/mqueue/mq_open_tests.c | 500 ++++++++++++++ > tools/testing/selftests/ipc/mqueue/mq_perf_tests.c | 742 +++++++++++++++++++++ > tools/testing/selftests/ipc/msg/Makefile | 22 + > tools/testing/selftests/ipc/msg/msgque.c | 254 +++++++ > tools/testing/selftests/ipc/msgque.c | 254 ------- > tools/testing/selftests/mqueue/.gitignore | 2 - > tools/testing/selftests/mqueue/Makefile | 22 - > tools/testing/selftests/mqueue/mq_open_tests.c | 500 -------------- > tools/testing/selftests/mqueue/mq_perf_tests.c | 742 --------------------- > 12 files changed, 1559 insertions(+), 1536 deletions(-) > create mode 100644 tools/testing/selftests/ipc/.gitignore > create mode 100644 tools/testing/selftests/ipc/mqueue/Makefile > create mode 100644 tools/testing/selftests/ipc/mqueue/mq_open_tests.c > create mode 100644 tools/testing/selftests/ipc/mqueue/mq_perf_tests.c > create mode 100644 tools/testing/selftests/ipc/msg/Makefile > create mode 100644 tools/testing/selftests/ipc/msg/msgque.c > delete mode 100644 tools/testing/selftests/ipc/msgque.c > delete mode 100644 tools/testing/selftests/mqueue/.gitignore > delete mode 100644 tools/testing/selftests/mqueue/Makefile > delete mode 100644 tools/testing/selftests/mqueue/mq_open_tests.c > delete mode 100644 tools/testing/selftests/mqueue/mq_perf_tests.c > > diff --git a/tools/testing/selftests/ipc/.gitignore b/tools/testing/selftests/ipc/.gitignore > new file mode 100644 > index 0000000..3d8a449 > --- /dev/null > +++ b/tools/testing/selftests/ipc/.gitignore > @@ -0,0 +1,3 @@ > +mqueue/mq_open_tests > +mqueue/mq_perf_tests > +msg/msgque_test > diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile > index 25d2e70..8686551 100644 > --- a/tools/testing/selftests/ipc/Makefile > +++ b/tools/testing/selftests/ipc/Makefile > @@ -1,22 +1,22 @@ > -uname_M := $(shell uname -m 2>/dev/null || echo not) > -ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) > -ifeq ($(ARCH),i386) > - ARCH := x86 > - CFLAGS := -DCONFIG_X86_32 -D__i386__ > -endif > -ifeq ($(ARCH),x86_64) > - ARCH := x86 > - CFLAGS := -DCONFIG_X86_64 -D__x86_64__ > -endif > - > -CFLAGS += -I../../../../usr/include/ Hmm. This looks like more than a moving code and cleanup change. The above is removing special handling for x86 and x86_64. I would like to see this as a separate patch and not combined with the moving code. > +SUBDIRS := msg > +SUBDIRS += mqueue > > +.PHONY: all clean > all: > - $(CC) $(CFLAGS) msgque.c -o msgque_test > - > -TEST_PROGS := msgque_test > + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done > > include ../lib.mk > +override define RUN_TESTS > + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done > +endef > + > +override define INSTALL_RULE > + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done > +endef > + > +override define EMIT_TESTS > + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done > +endef > > clean: > - rm -fr ./msgque_test > + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done > diff --git a/tools/testing/selftests/ipc/mqueue/Makefile b/tools/testing/selftests/ipc/mqueue/Makefile > new file mode 100644 > index 0000000..1fa56ea > --- /dev/null > +++ b/tools/testing/selftests/ipc/mqueue/Makefile > @@ -0,0 +1,22 @@ > +CFLAGS = -O2 > + > +all: > + $(CC) $(CFLAGS) mq_open_tests.c -o mq_open_tests -lrt > + $(CC) $(CFLAGS) -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt > + > +include ../../lib.mk > + > +override define RUN_TESTS > + @./mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]" > + @./mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]" > +endef > + > +TEST_PROGS := mq_open_tests mq_perf_tests > + > +override define EMIT_TESTS > + echo "./mq_open_tests /test1 || echo \"selftests: mq_open_tests [FAIL]\"" > + echo "./mq_perf_tests || echo \"selftests: mq_perf_tests [FAIL]\"" > +endef > + > +clean: > + rm -f mq_open_tests mq_perf_tests > diff --git a/tools/testing/selftests/ipc/mqueue/mq_open_tests.c b/tools/testing/selftests/ipc/mqueue/mq_open_tests.c > new file mode 100644 > index 0000000..9c1a5d35 > --- /dev/null > +++ b/tools/testing/selftests/ipc/mqueue/mq_open_tests.c > @@ -0,0 +1,500 @@ > +/* > + * This application is Copyright 2012 Red Hat, Inc. > + * Doug Ledford > + * > + * mq_open_tests is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, version 3. > + * > + * mq_open_tests is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * For the full text of the license, see . > + * > + * mq_open_tests.c > + * Tests the various situations that should either succeed or fail to > + * open a posix message queue and then reports whether or not they > + * did as they were supposed to. > + * > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +static char *usage = > +"Usage:\n" > +" %s path\n" > +"\n" > +" path Path name of the message queue to create\n" > +"\n" > +" Note: this program must be run as root in order to enable all tests\n" > +"\n"; > + > +char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default"; > +char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default"; > +char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; > +char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; > + > +int default_settings; > +struct rlimit saved_limits, cur_limits; > +int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize; > +int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize; > +FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize; > +char *queue_path; > +mqd_t queue = -1; > + > +static inline void __set(FILE *stream, int value, char *err_msg); > +void shutdown(int exit_val, char *err_cause, int line_no); > +static inline int get(FILE *stream); > +static inline void set(FILE *stream, int value); > +static inline void getr(int type, struct rlimit *rlim); > +static inline void setr(int type, struct rlimit *rlim); > +void validate_current_settings(); > +static inline void test_queue(struct mq_attr *attr, struct mq_attr *result); > +static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result); > + > +static inline void __set(FILE *stream, int value, char *err_msg) > +{ > + rewind(stream); > + if (fprintf(stream, "%d", value) < 0) > + perror(err_msg); > +} > + > + > +void shutdown(int exit_val, char *err_cause, int line_no) > +{ > + static int in_shutdown = 0; > + > + /* In case we get called recursively by a set() call below */ > + if (in_shutdown++) > + return; > + > + if (seteuid(0) == -1) > + perror("seteuid() failed"); > + > + if (queue != -1) > + if (mq_close(queue)) > + perror("mq_close() during shutdown"); > + if (queue_path) > + /* > + * Be silent if this fails, if we cleaned up already it's > + * expected to fail > + */ > + mq_unlink(queue_path); > + if (default_settings) { > + if (saved_def_msgs) > + __set(def_msgs, saved_def_msgs, > + "failed to restore saved_def_msgs"); > + if (saved_def_msgsize) > + __set(def_msgsize, saved_def_msgsize, > + "failed to restore saved_def_msgsize"); > + } > + if (saved_max_msgs) > + __set(max_msgs, saved_max_msgs, > + "failed to restore saved_max_msgs"); > + if (saved_max_msgsize) > + __set(max_msgsize, saved_max_msgsize, > + "failed to restore saved_max_msgsize"); > + if (exit_val) > + error(exit_val, errno, "%s at %d", err_cause, line_no); > + exit(0); > +} > + > +static inline int get(FILE *stream) > +{ > + int value; > + rewind(stream); > + if (fscanf(stream, "%d", &value) != 1) > + shutdown(4, "Error reading /proc entry", __LINE__ - 1); > + return value; > +} > + > +static inline void set(FILE *stream, int value) > +{ > + int new_value; > + > + rewind(stream); > + if (fprintf(stream, "%d", value) < 0) > + return shutdown(5, "Failed writing to /proc file", > + __LINE__ - 1); > + new_value = get(stream); > + if (new_value != value) > + return shutdown(5, "We didn't get what we wrote to /proc back", > + __LINE__ - 1); > +} > + > +static inline void getr(int type, struct rlimit *rlim) > +{ > + if (getrlimit(type, rlim)) > + shutdown(6, "getrlimit()", __LINE__ - 1); > +} > + > +static inline void setr(int type, struct rlimit *rlim) > +{ > + if (setrlimit(type, rlim)) > + shutdown(7, "setrlimit()", __LINE__ - 1); > +} > + > +void validate_current_settings() > +{ > + int rlim_needed; > + > + if (cur_limits.rlim_cur < 4096) { > + printf("Current rlimit value for POSIX message queue bytes is " > + "unreasonably low,\nincreasing.\n\n"); > + cur_limits.rlim_cur = 8192; > + cur_limits.rlim_max = 16384; > + setr(RLIMIT_MSGQUEUE, &cur_limits); > + } > + > + if (default_settings) { > + rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 + > + 2 * sizeof(void *)); > + if (rlim_needed > cur_limits.rlim_cur) { > + printf("Temporarily lowering default queue parameters " > + "to something that will work\n" > + "with the current rlimit values.\n\n"); > + set(def_msgs, 10); > + cur_def_msgs = 10; > + set(def_msgsize, 128); > + cur_def_msgsize = 128; > + } > + } else { > + rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 + > + 2 * sizeof(void *)); > + if (rlim_needed > cur_limits.rlim_cur) { > + printf("Temporarily lowering maximum queue parameters " > + "to something that will work\n" > + "with the current rlimit values in case this is " > + "a kernel that ties the default\n" > + "queue parameters to the maximum queue " > + "parameters.\n\n"); > + set(max_msgs, 10); > + cur_max_msgs = 10; > + set(max_msgsize, 128); > + cur_max_msgsize = 128; > + } > + } > +} > + > +/* > + * test_queue - Test opening a queue, shutdown if we fail. This should > + * only be called in situations that should never fail. We clean up > + * after ourselves and return the queue attributes in *result. > + */ > +static inline void test_queue(struct mq_attr *attr, struct mq_attr *result) > +{ > + int flags = O_RDWR | O_EXCL | O_CREAT; > + int perms = DEFFILEMODE; > + > + if ((queue = mq_open(queue_path, flags, perms, attr)) == -1) > + shutdown(1, "mq_open()", __LINE__); > + if (mq_getattr(queue, result)) > + shutdown(1, "mq_getattr()", __LINE__); > + if (mq_close(queue)) > + shutdown(1, "mq_close()", __LINE__); > + queue = -1; > + if (mq_unlink(queue_path)) > + shutdown(1, "mq_unlink()", __LINE__); > +} > + > +/* > + * Same as test_queue above, but failure is not fatal. > + * Returns: > + * 0 - Failed to create a queue > + * 1 - Created a queue, attributes in *result > + */ > +static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result) > +{ > + int flags = O_RDWR | O_EXCL | O_CREAT; > + int perms = DEFFILEMODE; > + > + if ((queue = mq_open(queue_path, flags, perms, attr)) == -1) > + return 0; > + if (mq_getattr(queue, result)) > + shutdown(1, "mq_getattr()", __LINE__); > + if (mq_close(queue)) > + shutdown(1, "mq_close()", __LINE__); > + queue = -1; > + if (mq_unlink(queue_path)) > + shutdown(1, "mq_unlink()", __LINE__); > + return 1; > +} > + > +int main(int argc, char *argv[]) > +{ > + struct mq_attr attr, result; > + > + if (argc != 2) { > + fprintf(stderr, "Must pass a valid queue name\n\n"); > + fprintf(stderr, usage, argv[0]); > + exit(1); > + } > + > + /* > + * Although we can create a msg queue with a non-absolute path name, > + * unlink will fail. So, if the name doesn't start with a /, add one > + * when we save it. > + */ > + if (*argv[1] == '/') > + queue_path = strdup(argv[1]); > + else { > + queue_path = malloc(strlen(argv[1]) + 2); > + if (!queue_path) { > + perror("malloc()"); > + exit(1); > + } > + queue_path[0] = '/'; > + queue_path[1] = 0; > + strcat(queue_path, argv[1]); > + } > + > + if (getuid() != 0) { > + fprintf(stderr, "Not running as root, but almost all tests " > + "require root in order to modify\nsystem settings. " > + "Exiting.\n"); > + exit(1); > + } > + > + /* Find out what files there are for us to make tweaks in */ > + def_msgs = fopen(DEF_MSGS, "r+"); > + def_msgsize = fopen(DEF_MSGSIZE, "r+"); > + max_msgs = fopen(MAX_MSGS, "r+"); > + max_msgsize = fopen(MAX_MSGSIZE, "r+"); > + > + if (!max_msgs) > + shutdown(2, "Failed to open msg_max", __LINE__); > + if (!max_msgsize) > + shutdown(2, "Failed to open msgsize_max", __LINE__); > + if (def_msgs || def_msgsize) > + default_settings = 1; > + > + /* Load up the current system values for everything we can */ > + getr(RLIMIT_MSGQUEUE, &saved_limits); > + cur_limits = saved_limits; > + if (default_settings) { > + saved_def_msgs = cur_def_msgs = get(def_msgs); > + saved_def_msgsize = cur_def_msgsize = get(def_msgsize); > + } > + saved_max_msgs = cur_max_msgs = get(max_msgs); > + saved_max_msgsize = cur_max_msgsize = get(max_msgsize); > + > + /* Tell the user our initial state */ > + printf("\nInitial system state:\n"); > + printf("\tUsing queue path:\t\t%s\n", queue_path); > + printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", > + (long) saved_limits.rlim_cur); > + printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", > + (long) saved_limits.rlim_max); > + printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize); > + printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs); > + if (default_settings) { > + printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize); > + printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs); > + } else { > + printf("\tDefault Message Size:\t\tNot Supported\n"); > + printf("\tDefault Queue Size:\t\tNot Supported\n"); > + } > + printf("\n"); > + > + validate_current_settings(); > + > + printf("Adjusted system state for testing:\n"); > + printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur); > + printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max); > + printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize); > + printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs); > + if (default_settings) { > + printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize); > + printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs); > + } > + > + printf("\n\nTest series 1, behavior when no attr struct " > + "passed to mq_open:\n"); > + if (!default_settings) { > + test_queue(NULL, &result); > + printf("Given sane system settings, mq_open without an attr " > + "struct succeeds:\tPASS\n"); > + if (result.mq_maxmsg != cur_max_msgs || > + result.mq_msgsize != cur_max_msgsize) { > + printf("Kernel does not support setting the default " > + "mq attributes,\nbut also doesn't tie the " > + "defaults to the maximums:\t\t\tPASS\n"); > + } else { > + set(max_msgs, ++cur_max_msgs); > + set(max_msgsize, ++cur_max_msgsize); > + test_queue(NULL, &result); > + if (result.mq_maxmsg == cur_max_msgs && > + result.mq_msgsize == cur_max_msgsize) > + printf("Kernel does not support setting the " > + "default mq attributes and\n" > + "also ties system wide defaults to " > + "the system wide maximums:\t\t" > + "FAIL\n"); > + else > + printf("Kernel does not support setting the " > + "default mq attributes,\n" > + "but also doesn't tie the defaults to " > + "the maximums:\t\t\tPASS\n"); > + } > + } else { > + printf("Kernel supports setting defaults separately from " > + "maximums:\t\tPASS\n"); > + /* > + * While we are here, go ahead and test that the kernel > + * properly follows the default settings > + */ > + test_queue(NULL, &result); > + printf("Given sane values, mq_open without an attr struct " > + "succeeds:\t\tPASS\n"); > + if (result.mq_maxmsg != cur_def_msgs || > + result.mq_msgsize != cur_def_msgsize) > + printf("Kernel supports setting defaults, but does " > + "not actually honor them:\tFAIL\n\n"); > + else { > + set(def_msgs, ++cur_def_msgs); > + set(def_msgsize, ++cur_def_msgsize); > + /* In case max was the same as the default */ > + set(max_msgs, ++cur_max_msgs); > + set(max_msgsize, ++cur_max_msgsize); > + test_queue(NULL, &result); > + if (result.mq_maxmsg != cur_def_msgs || > + result.mq_msgsize != cur_def_msgsize) > + printf("Kernel supports setting defaults, but " > + "does not actually honor them:\t" > + "FAIL\n"); > + else > + printf("Kernel properly honors default setting " > + "knobs:\t\t\t\tPASS\n"); > + } > + set(def_msgs, cur_max_msgs + 1); > + cur_def_msgs = cur_max_msgs + 1; > + set(def_msgsize, cur_max_msgsize + 1); > + cur_def_msgsize = cur_max_msgsize + 1; > + if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >= > + cur_limits.rlim_cur) { > + cur_limits.rlim_cur = (cur_def_msgs + 2) * > + (cur_def_msgsize + 2 * sizeof(void *)); > + cur_limits.rlim_max = 2 * cur_limits.rlim_cur; > + setr(RLIMIT_MSGQUEUE, &cur_limits); > + } > + if (test_queue_fail(NULL, &result)) { > + if (result.mq_maxmsg == cur_max_msgs && > + result.mq_msgsize == cur_max_msgsize) > + printf("Kernel properly limits default values " > + "to lesser of default/max:\t\tPASS\n"); > + else > + printf("Kernel does not properly set default " > + "queue parameters when\ndefaults > " > + "max:\t\t\t\t\t\t\t\tFAIL\n"); > + } else > + printf("Kernel fails to open mq because defaults are " > + "greater than maximums:\tFAIL\n"); > + set(def_msgs, --cur_def_msgs); > + set(def_msgsize, --cur_def_msgsize); > + cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs * > + cur_def_msgsize; > + setr(RLIMIT_MSGQUEUE, &cur_limits); > + if (test_queue_fail(NULL, &result)) > + printf("Kernel creates queue even though defaults " > + "would exceed\nrlimit setting:" > + "\t\t\t\t\t\t\t\tFAIL\n"); > + else > + printf("Kernel properly fails to create queue when " > + "defaults would\nexceed rlimit:" > + "\t\t\t\t\t\t\t\tPASS\n"); > + } > + > + /* > + * Test #2 - open with an attr struct that exceeds rlimit > + */ > + printf("\n\nTest series 2, behavior when attr struct is " > + "passed to mq_open:\n"); > + cur_max_msgs = 32; > + cur_max_msgsize = cur_limits.rlim_max >> 4; > + set(max_msgs, cur_max_msgs); > + set(max_msgsize, cur_max_msgsize); > + attr.mq_maxmsg = cur_max_msgs; > + attr.mq_msgsize = cur_max_msgsize; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open in excess of rlimit max when euid = 0 " > + "succeeded:\t\tFAIL\n"); > + else > + printf("Queue open in excess of rlimit max when euid = 0 " > + "failed:\t\tPASS\n"); > + attr.mq_maxmsg = cur_max_msgs + 1; > + attr.mq_msgsize = 10; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open with mq_maxmsg > limit when euid = 0 " > + "succeeded:\t\tPASS\n"); > + else > + printf("Queue open with mq_maxmsg > limit when euid = 0 " > + "failed:\t\tFAIL\n"); > + attr.mq_maxmsg = 1; > + attr.mq_msgsize = cur_max_msgsize + 1; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open with mq_msgsize > limit when euid = 0 " > + "succeeded:\t\tPASS\n"); > + else > + printf("Queue open with mq_msgsize > limit when euid = 0 " > + "failed:\t\tFAIL\n"); > + attr.mq_maxmsg = 65536; > + attr.mq_msgsize = 65536; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open with total size > 2GB when euid = 0 " > + "succeeded:\t\tFAIL\n"); > + else > + printf("Queue open with total size > 2GB when euid = 0 " > + "failed:\t\t\tPASS\n"); > + > + if (seteuid(99) == -1) { > + perror("seteuid() failed"); > + exit(1); > + } > + > + attr.mq_maxmsg = cur_max_msgs; > + attr.mq_msgsize = cur_max_msgsize; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open in excess of rlimit max when euid = 99 " > + "succeeded:\t\tFAIL\n"); > + else > + printf("Queue open in excess of rlimit max when euid = 99 " > + "failed:\t\tPASS\n"); > + attr.mq_maxmsg = cur_max_msgs + 1; > + attr.mq_msgsize = 10; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open with mq_maxmsg > limit when euid = 99 " > + "succeeded:\t\tFAIL\n"); > + else > + printf("Queue open with mq_maxmsg > limit when euid = 99 " > + "failed:\t\tPASS\n"); > + attr.mq_maxmsg = 1; > + attr.mq_msgsize = cur_max_msgsize + 1; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open with mq_msgsize > limit when euid = 99 " > + "succeeded:\t\tFAIL\n"); > + else > + printf("Queue open with mq_msgsize > limit when euid = 99 " > + "failed:\t\tPASS\n"); > + attr.mq_maxmsg = 65536; > + attr.mq_msgsize = 65536; > + if (test_queue_fail(&attr, &result)) > + printf("Queue open with total size > 2GB when euid = 99 " > + "succeeded:\t\tFAIL\n"); > + else > + printf("Queue open with total size > 2GB when euid = 99 " > + "failed:\t\t\tPASS\n"); > + > + shutdown(0,"",0); > +} > diff --git a/tools/testing/selftests/ipc/mqueue/mq_perf_tests.c b/tools/testing/selftests/ipc/mqueue/mq_perf_tests.c > new file mode 100644 > index 0000000..8519e9e > --- /dev/null > +++ b/tools/testing/selftests/ipc/mqueue/mq_perf_tests.c > @@ -0,0 +1,742 @@ > +/* > + * This application is Copyright 2012 Red Hat, Inc. > + * Doug Ledford > + * > + * mq_perf_tests is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, version 3. > + * > + * mq_perf_tests is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * For the full text of the license, see . > + * > + * mq_perf_tests.c > + * Tests various types of message queue workloads, concentrating on those > + * situations that invole large message sizes, large message queue depths, > + * or both, and reports back useful metrics about kernel message queue > + * performance. > + * > + */ > +#define _GNU_SOURCE > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +static char *usage = > +"Usage:\n" > +" %s [-c #[,#..] -f] path\n" > +"\n" > +" -c # Skip most tests and go straight to a high queue depth test\n" > +" and then run that test continuously (useful for running at\n" > +" the same time as some other workload to see how much the\n" > +" cache thrashing caused by adding messages to a very deep\n" > +" queue impacts the performance of other programs). The number\n" > +" indicates which CPU core we should bind the process to during\n" > +" the run. If you have more than one physical CPU, then you\n" > +" will need one copy per physical CPU package, and you should\n" > +" specify the CPU cores to pin ourself to via a comma separated\n" > +" list of CPU values.\n" > +" -f Only usable with continuous mode. Pin ourself to the CPUs\n" > +" as requested, then instead of looping doing a high mq\n" > +" workload, just busy loop. This will allow us to lock up a\n" > +" single CPU just like we normally would, but without actually\n" > +" thrashing the CPU cache. This is to make it easier to get\n" > +" comparable numbers from some other workload running on the\n" > +" other CPUs. One set of numbers with # CPUs locked up running\n" > +" an mq workload, and another set of numbers with those same\n" > +" CPUs locked away from the test workload, but not doing\n" > +" anything to trash the cache like the mq workload might.\n" > +" path Path name of the message queue to create\n" > +"\n" > +" Note: this program must be run as root in order to enable all tests\n" > +"\n"; > + > +char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; > +char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; > + > +#define min(a, b) ((a) < (b) ? (a) : (b)) > +#define MAX_CPUS 64 > +char *cpu_option_string; > +int cpus_to_pin[MAX_CPUS]; > +int num_cpus_to_pin; > +pthread_t cpu_threads[MAX_CPUS]; > +pthread_t main_thread; > +cpu_set_t *cpu_set; > +int cpu_set_size; > +int cpus_online; > + > +#define MSG_SIZE 16 > +#define TEST1_LOOPS 10000000 > +#define TEST2_LOOPS 100000 > +int continuous_mode; > +int continuous_mode_fake; > + > +struct rlimit saved_limits, cur_limits; > +int saved_max_msgs, saved_max_msgsize; > +int cur_max_msgs, cur_max_msgsize; > +FILE *max_msgs, *max_msgsize; > +int cur_nice; > +char *queue_path = "/mq_perf_tests"; > +mqd_t queue = -1; > +struct mq_attr result; > +int mq_prio_max; > + > +const struct poptOption options[] = { > + { > + .longName = "continuous", > + .shortName = 'c', > + .argInfo = POPT_ARG_STRING, > + .arg = &cpu_option_string, > + .val = 'c', > + .descrip = "Run continuous tests at a high queue depth in " > + "order to test the effects of cache thrashing on " > + "other tasks on the system. This test is intended " > + "to be run on one core of each physical CPU while " > + "some other CPU intensive task is run on all the other " > + "cores of that same physical CPU and the other task " > + "is timed. It is assumed that the process of adding " > + "messages to the message queue in a tight loop will " > + "impact that other task to some degree. Once the " > + "tests are performed in this way, you should then " > + "re-run the tests using fake mode in order to check " > + "the difference in time required to perform the CPU " > + "intensive task", > + .argDescrip = "cpu[,cpu]", > + }, > + { > + .longName = "fake", > + .shortName = 'f', > + .argInfo = POPT_ARG_NONE, > + .arg = &continuous_mode_fake, > + .val = 0, > + .descrip = "Tie up the CPUs that we would normally tie up in" > + "continuous mode, but don't actually do any mq stuff, " > + "just keep the CPU busy so it can't be used to process " > + "system level tasks as this would free up resources on " > + "the other CPU cores and skew the comparison between " > + "the no-mqueue work and mqueue work tests", > + .argDescrip = NULL, > + }, > + { > + .longName = "path", > + .shortName = 'p', > + .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, > + .arg = &queue_path, > + .val = 'p', > + .descrip = "The name of the path to use in the mqueue " > + "filesystem for our tests", > + .argDescrip = "pathname", > + }, > + POPT_AUTOHELP > + POPT_TABLEEND > +}; > + > +static inline void __set(FILE *stream, int value, char *err_msg); > +void shutdown(int exit_val, char *err_cause, int line_no); > +void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context); > +void sig_action(int signum, siginfo_t *info, void *context); > +static inline int get(FILE *stream); > +static inline void set(FILE *stream, int value); > +static inline int try_set(FILE *stream, int value); > +static inline void getr(int type, struct rlimit *rlim); > +static inline void setr(int type, struct rlimit *rlim); > +static inline void open_queue(struct mq_attr *attr); > +void increase_limits(void); > + > +static inline void __set(FILE *stream, int value, char *err_msg) > +{ > + rewind(stream); > + if (fprintf(stream, "%d", value) < 0) > + perror(err_msg); > +} > + > + > +void shutdown(int exit_val, char *err_cause, int line_no) > +{ > + static int in_shutdown = 0; > + int errno_at_shutdown = errno; > + int i; > + > + /* In case we get called by multiple threads or from an sighandler */ > + if (in_shutdown++) > + return; > + > + for (i = 0; i < num_cpus_to_pin; i++) > + if (cpu_threads[i]) { > + pthread_kill(cpu_threads[i], SIGUSR1); > + pthread_join(cpu_threads[i], NULL); > + } > + > + if (queue != -1) > + if (mq_close(queue)) > + perror("mq_close() during shutdown"); > + if (queue_path) > + /* > + * Be silent if this fails, if we cleaned up already it's > + * expected to fail > + */ > + mq_unlink(queue_path); > + if (saved_max_msgs) > + __set(max_msgs, saved_max_msgs, > + "failed to restore saved_max_msgs"); > + if (saved_max_msgsize) > + __set(max_msgsize, saved_max_msgsize, > + "failed to restore saved_max_msgsize"); > + if (exit_val) > + error(exit_val, errno_at_shutdown, "%s at %d", > + err_cause, line_no); > + exit(0); > +} > + > +void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context) > +{ > + if (pthread_self() != main_thread) > + pthread_exit(0); > + else { > + fprintf(stderr, "Caught signal %d in SIGUSR1 handler, " > + "exiting\n", signum); > + shutdown(0, "", 0); > + fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); > + exit(0); > + } > +} > + > +void sig_action(int signum, siginfo_t *info, void *context) > +{ > + if (pthread_self() != main_thread) > + pthread_kill(main_thread, signum); > + else { > + fprintf(stderr, "Caught signal %d, exiting\n", signum); > + shutdown(0, "", 0); > + fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); > + exit(0); > + } > +} > + > +static inline int get(FILE *stream) > +{ > + int value; > + rewind(stream); > + if (fscanf(stream, "%d", &value) != 1) > + shutdown(4, "Error reading /proc entry", __LINE__); > + return value; > +} > + > +static inline void set(FILE *stream, int value) > +{ > + int new_value; > + > + rewind(stream); > + if (fprintf(stream, "%d", value) < 0) > + return shutdown(5, "Failed writing to /proc file", __LINE__); > + new_value = get(stream); > + if (new_value != value) > + return shutdown(5, "We didn't get what we wrote to /proc back", > + __LINE__); > +} > + > +static inline int try_set(FILE *stream, int value) > +{ > + int new_value; > + > + rewind(stream); > + fprintf(stream, "%d", value); > + new_value = get(stream); > + return new_value == value; > +} > + > +static inline void getr(int type, struct rlimit *rlim) > +{ > + if (getrlimit(type, rlim)) > + shutdown(6, "getrlimit()", __LINE__); > +} > + > +static inline void setr(int type, struct rlimit *rlim) > +{ > + if (setrlimit(type, rlim)) > + shutdown(7, "setrlimit()", __LINE__); > +} > + > +/** > + * open_queue - open the global queue for testing > + * @attr - An attr struct specifying the desired queue traits > + * @result - An attr struct that lists the actual traits the queue has > + * > + * This open is not allowed to fail, failure will result in an orderly > + * shutdown of the program. The global queue_path is used to set what > + * queue to open, the queue descriptor is saved in the global queue > + * variable. > + */ > +static inline void open_queue(struct mq_attr *attr) > +{ > + int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK; > + int perms = DEFFILEMODE; > + > + queue = mq_open(queue_path, flags, perms, attr); > + if (queue == -1) > + shutdown(1, "mq_open()", __LINE__); > + if (mq_getattr(queue, &result)) > + shutdown(1, "mq_getattr()", __LINE__); > + printf("\n\tQueue %s created:\n", queue_path); > + printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ? > + "O_NONBLOCK" : "(null)"); > + printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg); > + printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize); > + printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs); > +} > + > +void *fake_cont_thread(void *arg) > +{ > + int i; > + > + for (i = 0; i < num_cpus_to_pin; i++) > + if (cpu_threads[i] == pthread_self()) > + break; > + printf("\tStarted fake continuous mode thread %d on CPU %d\n", i, > + cpus_to_pin[i]); > + while (1) > + ; > +} > + > +void *cont_thread(void *arg) > +{ > + char buff[MSG_SIZE]; > + int i, priority; > + > + for (i = 0; i < num_cpus_to_pin; i++) > + if (cpu_threads[i] == pthread_self()) > + break; > + printf("\tStarted continuous mode thread %d on CPU %d\n", i, > + cpus_to_pin[i]); > + while (1) { > + while (mq_send(queue, buff, sizeof(buff), 0) == 0) > + ; > + mq_receive(queue, buff, sizeof(buff), &priority); > + } > +} > + > +#define drain_queue() \ > + while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE) > + > +#define do_untimed_send() \ > + do { \ > + if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ > + shutdown(3, "Test send failure", __LINE__); \ > + } while (0) > + > +#define do_send_recv() \ > + do { \ > + clock_gettime(clock, &start); \ > + if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ > + shutdown(3, "Test send failure", __LINE__); \ > + clock_gettime(clock, &middle); \ > + if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \ > + shutdown(3, "Test receive failure", __LINE__); \ > + clock_gettime(clock, &end); \ > + nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \ > + (middle.tv_nsec - start.tv_nsec); \ > + send_total.tv_nsec += nsec; \ > + if (send_total.tv_nsec >= 1000000000) { \ > + send_total.tv_sec++; \ > + send_total.tv_nsec -= 1000000000; \ > + } \ > + nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \ > + (end.tv_nsec - middle.tv_nsec); \ > + recv_total.tv_nsec += nsec; \ > + if (recv_total.tv_nsec >= 1000000000) { \ > + recv_total.tv_sec++; \ > + recv_total.tv_nsec -= 1000000000; \ > + } \ > + } while (0) > + > +struct test { > + char *desc; > + void (*func)(int *); > +}; > + > +void const_prio(int *prio) > +{ > + return; > +} > + > +void inc_prio(int *prio) > +{ > + if (++*prio == mq_prio_max) > + *prio = 0; > +} > + > +void dec_prio(int *prio) > +{ > + if (--*prio < 0) > + *prio = mq_prio_max - 1; > +} > + > +void random_prio(int *prio) > +{ > + *prio = random() % mq_prio_max; > +} > + > +struct test test2[] = { > + {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n", > + const_prio}, > + {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n", > + inc_prio}, > + {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n", > + dec_prio}, > + {"\n\tTest #2d: Time send/recv message, queue full, random prio\n", > + random_prio}, > + {NULL, NULL} > +}; > + > +/** > + * Tests to perform (all done with MSG_SIZE messages): > + * > + * 1) Time to add/remove message with 0 messages on queue > + * 1a) with constant prio > + * 2) Time to add/remove message when queue close to capacity: > + * 2a) with constant prio > + * 2b) with increasing prio > + * 2c) with decreasing prio > + * 2d) with random prio > + * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX) > + */ > +void *perf_test_thread(void *arg) > +{ > + char buff[MSG_SIZE]; > + int prio_out, prio_in; > + int i; > + clockid_t clock; > + pthread_t *t; > + struct timespec res, start, middle, end, send_total, recv_total; > + unsigned long long nsec; > + struct test *cur_test; > + > + t = &cpu_threads[0]; > + printf("\n\tStarted mqueue performance test thread on CPU %d\n", > + cpus_to_pin[0]); > + mq_prio_max = sysconf(_SC_MQ_PRIO_MAX); > + if (mq_prio_max == -1) > + shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__); > + if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0) > + shutdown(2, "pthread_getcpuclockid", __LINE__); > + > + if (clock_getres(clock, &res)) > + shutdown(2, "clock_getres()", __LINE__); > + > + printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max); > + printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec, > + res.tv_nsec > 1 ? "s" : ""); > + > + > + > + printf("\n\tTest #1: Time send/recv message, queue empty\n"); > + printf("\t\t(%d iterations)\n", TEST1_LOOPS); > + prio_out = 0; > + send_total.tv_sec = 0; > + send_total.tv_nsec = 0; > + recv_total.tv_sec = 0; > + recv_total.tv_nsec = 0; > + for (i = 0; i < TEST1_LOOPS; i++) > + do_send_recv(); > + printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", > + send_total.tv_sec, send_total.tv_nsec); > + nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + > + send_total.tv_nsec) / TEST1_LOOPS; > + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > + printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", > + recv_total.tv_sec, recv_total.tv_nsec); > + nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + > + recv_total.tv_nsec) / TEST1_LOOPS; > + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > + > + > + for (cur_test = test2; cur_test->desc != NULL; cur_test++) { > + printf("%s:\n", cur_test->desc); > + printf("\t\t(%d iterations)\n", TEST2_LOOPS); > + prio_out = 0; > + send_total.tv_sec = 0; > + send_total.tv_nsec = 0; > + recv_total.tv_sec = 0; > + recv_total.tv_nsec = 0; > + printf("\t\tFilling queue..."); > + fflush(stdout); > + clock_gettime(clock, &start); > + for (i = 0; i < result.mq_maxmsg - 1; i++) { > + do_untimed_send(); > + cur_test->func(&prio_out); > + } > + clock_gettime(clock, &end); > + nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * > + 1000000000) + (end.tv_nsec - start.tv_nsec); > + printf("done.\t\t%lld.%llds\n", nsec / 1000000000, > + nsec % 1000000000); > + printf("\t\tTesting..."); > + fflush(stdout); > + for (i = 0; i < TEST2_LOOPS; i++) { > + do_send_recv(); > + cur_test->func(&prio_out); > + } > + printf("done.\n"); > + printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", > + send_total.tv_sec, send_total.tv_nsec); > + nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + > + send_total.tv_nsec) / TEST2_LOOPS; > + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > + printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", > + recv_total.tv_sec, recv_total.tv_nsec); > + nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + > + recv_total.tv_nsec) / TEST2_LOOPS; > + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > + printf("\t\tDraining queue..."); > + fflush(stdout); > + clock_gettime(clock, &start); > + drain_queue(); > + clock_gettime(clock, &end); > + nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * > + 1000000000) + (end.tv_nsec - start.tv_nsec); > + printf("done.\t\t%lld.%llds\n", nsec / 1000000000, > + nsec % 1000000000); > + } > + return 0; > +} > + > +void increase_limits(void) > +{ > + cur_limits.rlim_cur = RLIM_INFINITY; > + cur_limits.rlim_max = RLIM_INFINITY; > + setr(RLIMIT_MSGQUEUE, &cur_limits); > + while (try_set(max_msgs, cur_max_msgs += 10)) > + ; > + cur_max_msgs = get(max_msgs); > + while (try_set(max_msgsize, cur_max_msgsize += 1024)) > + ; > + cur_max_msgsize = get(max_msgsize); > + if (setpriority(PRIO_PROCESS, 0, -20) != 0) > + shutdown(2, "setpriority()", __LINE__); > + cur_nice = -20; > +} > + > +int main(int argc, char *argv[]) > +{ > + struct mq_attr attr; > + char *option, *next_option; > + int i, cpu, rc; > + struct sigaction sa; > + poptContext popt_context; > + void *retval; > + > + main_thread = pthread_self(); > + num_cpus_to_pin = 0; > + > + if (sysconf(_SC_NPROCESSORS_ONLN) == -1) { > + perror("sysconf(_SC_NPROCESSORS_ONLN)"); > + exit(1); > + } > + cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN)); > + cpu_set = CPU_ALLOC(cpus_online); > + if (cpu_set == NULL) { > + perror("CPU_ALLOC()"); > + exit(1); > + } > + cpu_set_size = CPU_ALLOC_SIZE(cpus_online); > + CPU_ZERO_S(cpu_set_size, cpu_set); > + > + popt_context = poptGetContext(NULL, argc, (const char **)argv, > + options, 0); > + > + while ((rc = poptGetNextOpt(popt_context)) > 0) { > + switch (rc) { > + case 'c': > + continuous_mode = 1; > + option = cpu_option_string; > + do { > + next_option = strchr(option, ','); > + if (next_option) > + *next_option = '\0'; > + cpu = atoi(option); > + if (cpu >= cpus_online) > + fprintf(stderr, "CPU %d exceeds " > + "cpus online, ignoring.\n", > + cpu); > + else > + cpus_to_pin[num_cpus_to_pin++] = cpu; > + if (next_option) > + option = ++next_option; > + } while (next_option && num_cpus_to_pin < MAX_CPUS); > + /* Double check that they didn't give us the same CPU > + * more than once */ > + for (cpu = 0; cpu < num_cpus_to_pin; cpu++) { > + if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size, > + cpu_set)) { > + fprintf(stderr, "Any given CPU may " > + "only be given once.\n"); > + exit(1); > + } else > + CPU_SET_S(cpus_to_pin[cpu], > + cpu_set_size, cpu_set); > + } > + break; > + case 'p': > + /* > + * Although we can create a msg queue with a > + * non-absolute path name, unlink will fail. So, > + * if the name doesn't start with a /, add one > + * when we save it. > + */ > + option = queue_path; > + if (*option != '/') { > + queue_path = malloc(strlen(option) + 2); > + if (!queue_path) { > + perror("malloc()"); > + exit(1); > + } > + queue_path[0] = '/'; > + queue_path[1] = 0; > + strcat(queue_path, option); > + free(option); > + } > + break; > + } > + } > + > + if (continuous_mode && num_cpus_to_pin == 0) { > + fprintf(stderr, "Must pass at least one CPU to continuous " > + "mode.\n"); > + poptPrintUsage(popt_context, stderr, 0); > + exit(1); > + } else if (!continuous_mode) { > + num_cpus_to_pin = 1; > + cpus_to_pin[0] = cpus_online - 1; > + } > + > + if (getuid() != 0) { > + fprintf(stderr, "Not running as root, but almost all tests " > + "require root in order to modify\nsystem settings. " > + "Exiting.\n"); > + exit(1); > + } > + > + max_msgs = fopen(MAX_MSGS, "r+"); > + max_msgsize = fopen(MAX_MSGSIZE, "r+"); > + if (!max_msgs) > + shutdown(2, "Failed to open msg_max", __LINE__); > + if (!max_msgsize) > + shutdown(2, "Failed to open msgsize_max", __LINE__); > + > + /* Load up the current system values for everything we can */ > + getr(RLIMIT_MSGQUEUE, &saved_limits); > + cur_limits = saved_limits; > + saved_max_msgs = cur_max_msgs = get(max_msgs); > + saved_max_msgsize = cur_max_msgsize = get(max_msgsize); > + errno = 0; > + cur_nice = getpriority(PRIO_PROCESS, 0); > + if (errno) > + shutdown(2, "getpriority()", __LINE__); > + > + /* Tell the user our initial state */ > + printf("\nInitial system state:\n"); > + printf("\tUsing queue path:\t\t\t%s\n", queue_path); > + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", > + (long) saved_limits.rlim_cur); > + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", > + (long) saved_limits.rlim_max); > + printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize); > + printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs); > + printf("\tNice value:\t\t\t\t%d\n", cur_nice); > + printf("\n"); > + > + increase_limits(); > + > + printf("Adjusted system state for testing:\n"); > + if (cur_limits.rlim_cur == RLIM_INFINITY) { > + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n"); > + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n"); > + } else { > + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", > + (long) cur_limits.rlim_cur); > + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", > + (long) cur_limits.rlim_max); > + } > + printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize); > + printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs); > + printf("\tNice value:\t\t\t\t%d\n", cur_nice); > + printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ? > + (continuous_mode_fake ? "fake mode" : "enabled") : > + "disabled"); > + printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]); > + for (cpu = 1; cpu < num_cpus_to_pin; cpu++) > + printf(",%d", cpus_to_pin[cpu]); > + printf("\n"); > + > + sa.sa_sigaction = sig_action_SIGUSR1; > + sigemptyset(&sa.sa_mask); > + sigaddset(&sa.sa_mask, SIGHUP); > + sigaddset(&sa.sa_mask, SIGINT); > + sigaddset(&sa.sa_mask, SIGQUIT); > + sigaddset(&sa.sa_mask, SIGTERM); > + sa.sa_flags = SA_SIGINFO; > + if (sigaction(SIGUSR1, &sa, NULL) == -1) > + shutdown(1, "sigaction(SIGUSR1)", __LINE__); > + sa.sa_sigaction = sig_action; > + if (sigaction(SIGHUP, &sa, NULL) == -1) > + shutdown(1, "sigaction(SIGHUP)", __LINE__); > + if (sigaction(SIGINT, &sa, NULL) == -1) > + shutdown(1, "sigaction(SIGINT)", __LINE__); > + if (sigaction(SIGQUIT, &sa, NULL) == -1) > + shutdown(1, "sigaction(SIGQUIT)", __LINE__); > + if (sigaction(SIGTERM, &sa, NULL) == -1) > + shutdown(1, "sigaction(SIGTERM)", __LINE__); > + > + if (!continuous_mode_fake) { > + attr.mq_flags = O_NONBLOCK; > + attr.mq_maxmsg = cur_max_msgs; > + attr.mq_msgsize = MSG_SIZE; > + open_queue(&attr); > + } > + for (i = 0; i < num_cpus_to_pin; i++) { > + pthread_attr_t thread_attr; > + void *thread_func; > + > + if (continuous_mode_fake) > + thread_func = &fake_cont_thread; > + else if (continuous_mode) > + thread_func = &cont_thread; > + else > + thread_func = &perf_test_thread; > + > + CPU_ZERO_S(cpu_set_size, cpu_set); > + CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set); > + pthread_attr_init(&thread_attr); > + pthread_attr_setaffinity_np(&thread_attr, cpu_set_size, > + cpu_set); > + if (pthread_create(&cpu_threads[i], &thread_attr, thread_func, > + NULL)) > + shutdown(1, "pthread_create()", __LINE__); > + pthread_attr_destroy(&thread_attr); > + } > + > + if (!continuous_mode) { > + pthread_join(cpu_threads[0], &retval); > + shutdown((long)retval, "perf_test_thread()", __LINE__); > + } else { > + while (1) > + sleep(1); > + } > + shutdown(0, "", 0); > +} > diff --git a/tools/testing/selftests/ipc/msg/Makefile b/tools/testing/selftests/ipc/msg/Makefile > new file mode 100644 > index 0000000..777ca76 > --- /dev/null > +++ b/tools/testing/selftests/ipc/msg/Makefile > @@ -0,0 +1,22 @@ > +uname_M := $(shell uname -m 2>/dev/null || echo not) > +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) > +ifeq ($(ARCH),i386) > + ARCH := x86 > + CFLAGS := -DCONFIG_X86_32 -D__i386__ > +endif > +ifeq ($(ARCH),x86_64) > + ARCH := x86 > + CFLAGS := -DCONFIG_X86_64 -D__x86_64__ > +endif > + > +CFLAGS += -I../../../../usr/include/ > + > +all: > + $(CC) $(CFLAGS) msgque.c -o msgque_test > + > +TEST_PROGS := msgque_test > + > +include ../../lib.mk > + > +clean: > + rm -fr ./msgque_test > diff --git a/tools/testing/selftests/ipc/msg/msgque.c b/tools/testing/selftests/ipc/msg/msgque.c > new file mode 100644 > index 0000000..69d539d > --- /dev/null > +++ b/tools/testing/selftests/ipc/msg/msgque.c > @@ -0,0 +1,254 @@ > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "../../kselftest.h" > + > +#define MAX_MSG_SIZE 32 > + > +struct msg1 { > + int msize; > + long mtype; > + char mtext[MAX_MSG_SIZE]; > +}; > + > +#define TEST_STRING "Test sysv5 msg" > +#define MSG_TYPE 1 > + > +#define ANOTHER_TEST_STRING "Yet another test sysv5 msg" > +#define ANOTHER_MSG_TYPE 26538 > + > +struct msgque_data { > + key_t key; > + int msq_id; > + int qbytes; > + int qnum; > + int mode; > + struct msg1 *messages; > +}; > + > +int restore_queue(struct msgque_data *msgque) > +{ > + int fd, ret, id, i; > + char buf[32]; > + > + fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY); > + if (fd == -1) { > + printf("Failed to open /proc/sys/kernel/msg_next_id\n"); > + return -errno; > + } > + sprintf(buf, "%d", msgque->msq_id); > + > + ret = write(fd, buf, strlen(buf)); > + if (ret != strlen(buf)) { > + printf("Failed to write to /proc/sys/kernel/msg_next_id\n"); > + return -errno; > + } > + > + id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL); > + if (id == -1) { > + printf("Failed to create queue\n"); > + return -errno; > + } > + > + if (id != msgque->msq_id) { > + printf("Restored queue has wrong id (%d instead of %d)\n", > + id, msgque->msq_id); > + ret = -EFAULT; > + goto destroy; > + } > + > + for (i = 0; i < msgque->qnum; i++) { > + if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype, > + msgque->messages[i].msize, IPC_NOWAIT) != 0) { > + printf("msgsnd failed (%m)\n"); > + ret = -errno; > + goto destroy; > + }; > + } > + return 0; > + > +destroy: > + if (msgctl(id, IPC_RMID, 0)) > + printf("Failed to destroy queue: %d\n", -errno); > + return ret; > +} > + > +int check_and_destroy_queue(struct msgque_data *msgque) > +{ > + struct msg1 message; > + int cnt = 0, ret; > + > + while (1) { > + ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE, > + 0, IPC_NOWAIT); > + if (ret < 0) { > + if (errno == ENOMSG) > + break; > + printf("Failed to read IPC message: %m\n"); > + ret = -errno; > + goto err; > + } > + if (ret != msgque->messages[cnt].msize) { > + printf("Wrong message size: %d (expected %d)\n", ret, > + msgque->messages[cnt].msize); > + ret = -EINVAL; > + goto err; > + } > + if (message.mtype != msgque->messages[cnt].mtype) { > + printf("Wrong message type\n"); > + ret = -EINVAL; > + goto err; > + } > + if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) { > + printf("Wrong message content\n"); > + ret = -EINVAL; > + goto err; > + } > + cnt++; > + } > + > + if (cnt != msgque->qnum) { > + printf("Wrong message number\n"); > + ret = -EINVAL; > + goto err; > + } > + > + ret = 0; > +err: > + if (msgctl(msgque->msq_id, IPC_RMID, 0)) { > + printf("Failed to destroy queue: %d\n", -errno); > + return -errno; > + } > + return ret; > +} > + > +int dump_queue(struct msgque_data *msgque) > +{ > + struct msqid64_ds ds; > + int kern_id; > + int i, ret; > + > + for (kern_id = 0; kern_id < 256; kern_id++) { > + ret = msgctl(kern_id, MSG_STAT, &ds); > + if (ret < 0) { > + if (errno == -EINVAL) > + continue; > + printf("Failed to get stats for IPC queue with id %d\n", > + kern_id); > + return -errno; > + } > + > + if (ret == msgque->msq_id) > + break; > + } > + > + msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum); > + if (msgque->messages == NULL) { > + printf("Failed to get stats for IPC queue\n"); > + return -ENOMEM; > + } > + > + msgque->qnum = ds.msg_qnum; > + msgque->mode = ds.msg_perm.mode; > + msgque->qbytes = ds.msg_qbytes; > + > + for (i = 0; i < msgque->qnum; i++) { > + ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype, > + MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY); > + if (ret < 0) { > + printf("Failed to copy IPC message: %m (%d)\n", errno); > + return -errno; > + } > + msgque->messages[i].msize = ret; > + } > + return 0; > +} > + > +int fill_msgque(struct msgque_data *msgque) > +{ > + struct msg1 msgbuf; > + > + msgbuf.mtype = MSG_TYPE; > + memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING)); > + if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING), > + IPC_NOWAIT) != 0) { > + printf("First message send failed (%m)\n"); > + return -errno; > + }; > + > + msgbuf.mtype = ANOTHER_MSG_TYPE; > + memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING)); > + if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING), > + IPC_NOWAIT) != 0) { > + printf("Second message send failed (%m)\n"); > + return -errno; > + }; > + return 0; > +} > + > +int main(int argc, char **argv) > +{ > + int msg, pid, err; > + struct msgque_data msgque; > + > + if (getuid() != 0) { > + printf("Please run the test as root - Exiting.\n"); > + return ksft_exit_fail(); > + } > + > + msgque.key = ftok(argv[0], 822155650); > + if (msgque.key == -1) { > + printf("Can't make key: %d\n", -errno); > + return ksft_exit_fail(); > + } > + > + msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); > + if (msgque.msq_id == -1) { > + err = -errno; > + printf("Can't create queue: %d\n", err); > + goto err_out; > + } > + > + err = fill_msgque(&msgque); > + if (err) { > + printf("Failed to fill queue: %d\n", err); > + goto err_destroy; > + } > + > + err = dump_queue(&msgque); > + if (err) { > + printf("Failed to dump queue: %d\n", err); > + goto err_destroy; > + } > + > + err = check_and_destroy_queue(&msgque); > + if (err) { > + printf("Failed to check and destroy queue: %d\n", err); > + goto err_out; > + } > + > + err = restore_queue(&msgque); > + if (err) { > + printf("Failed to restore queue: %d\n", err); > + goto err_destroy; > + } > + > + err = check_and_destroy_queue(&msgque); > + if (err) { > + printf("Failed to test queue: %d\n", err); > + goto err_out; > + } > + return ksft_exit_pass(); > + > +err_destroy: > + if (msgctl(msgque.msq_id, IPC_RMID, 0)) { > + printf("Failed to destroy queue: %d\n", -errno); > + return ksft_exit_fail(); > + } > +err_out: > + return ksft_exit_fail(); > +} > diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c > deleted file mode 100644 > index 1b2ce33..0000000 > --- a/tools/testing/selftests/ipc/msgque.c > +++ /dev/null > @@ -1,254 +0,0 @@ > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include "../kselftest.h" > - > -#define MAX_MSG_SIZE 32 > - > -struct msg1 { > - int msize; > - long mtype; > - char mtext[MAX_MSG_SIZE]; > -}; > - > -#define TEST_STRING "Test sysv5 msg" > -#define MSG_TYPE 1 > - > -#define ANOTHER_TEST_STRING "Yet another test sysv5 msg" > -#define ANOTHER_MSG_TYPE 26538 > - > -struct msgque_data { > - key_t key; > - int msq_id; > - int qbytes; > - int qnum; > - int mode; > - struct msg1 *messages; > -}; > - > -int restore_queue(struct msgque_data *msgque) > -{ > - int fd, ret, id, i; > - char buf[32]; > - > - fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY); > - if (fd == -1) { > - printf("Failed to open /proc/sys/kernel/msg_next_id\n"); > - return -errno; > - } > - sprintf(buf, "%d", msgque->msq_id); > - > - ret = write(fd, buf, strlen(buf)); > - if (ret != strlen(buf)) { > - printf("Failed to write to /proc/sys/kernel/msg_next_id\n"); > - return -errno; > - } > - > - id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL); > - if (id == -1) { > - printf("Failed to create queue\n"); > - return -errno; > - } > - > - if (id != msgque->msq_id) { > - printf("Restored queue has wrong id (%d instead of %d)\n", > - id, msgque->msq_id); > - ret = -EFAULT; > - goto destroy; > - } > - > - for (i = 0; i < msgque->qnum; i++) { > - if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype, > - msgque->messages[i].msize, IPC_NOWAIT) != 0) { > - printf("msgsnd failed (%m)\n"); > - ret = -errno; > - goto destroy; > - }; > - } > - return 0; > - > -destroy: > - if (msgctl(id, IPC_RMID, 0)) > - printf("Failed to destroy queue: %d\n", -errno); > - return ret; > -} > - > -int check_and_destroy_queue(struct msgque_data *msgque) > -{ > - struct msg1 message; > - int cnt = 0, ret; > - > - while (1) { > - ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE, > - 0, IPC_NOWAIT); > - if (ret < 0) { > - if (errno == ENOMSG) > - break; > - printf("Failed to read IPC message: %m\n"); > - ret = -errno; > - goto err; > - } > - if (ret != msgque->messages[cnt].msize) { > - printf("Wrong message size: %d (expected %d)\n", ret, > - msgque->messages[cnt].msize); > - ret = -EINVAL; > - goto err; > - } > - if (message.mtype != msgque->messages[cnt].mtype) { > - printf("Wrong message type\n"); > - ret = -EINVAL; > - goto err; > - } > - if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) { > - printf("Wrong message content\n"); > - ret = -EINVAL; > - goto err; > - } > - cnt++; > - } > - > - if (cnt != msgque->qnum) { > - printf("Wrong message number\n"); > - ret = -EINVAL; > - goto err; > - } > - > - ret = 0; > -err: > - if (msgctl(msgque->msq_id, IPC_RMID, 0)) { > - printf("Failed to destroy queue: %d\n", -errno); > - return -errno; > - } > - return ret; > -} > - > -int dump_queue(struct msgque_data *msgque) > -{ > - struct msqid64_ds ds; > - int kern_id; > - int i, ret; > - > - for (kern_id = 0; kern_id < 256; kern_id++) { > - ret = msgctl(kern_id, MSG_STAT, &ds); > - if (ret < 0) { > - if (errno == -EINVAL) > - continue; > - printf("Failed to get stats for IPC queue with id %d\n", > - kern_id); > - return -errno; > - } > - > - if (ret == msgque->msq_id) > - break; > - } > - > - msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum); > - if (msgque->messages == NULL) { > - printf("Failed to get stats for IPC queue\n"); > - return -ENOMEM; > - } > - > - msgque->qnum = ds.msg_qnum; > - msgque->mode = ds.msg_perm.mode; > - msgque->qbytes = ds.msg_qbytes; > - > - for (i = 0; i < msgque->qnum; i++) { > - ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype, > - MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY); > - if (ret < 0) { > - printf("Failed to copy IPC message: %m (%d)\n", errno); > - return -errno; > - } > - msgque->messages[i].msize = ret; > - } > - return 0; > -} > - > -int fill_msgque(struct msgque_data *msgque) > -{ > - struct msg1 msgbuf; > - > - msgbuf.mtype = MSG_TYPE; > - memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING)); > - if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING), > - IPC_NOWAIT) != 0) { > - printf("First message send failed (%m)\n"); > - return -errno; > - }; > - > - msgbuf.mtype = ANOTHER_MSG_TYPE; > - memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING)); > - if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING), > - IPC_NOWAIT) != 0) { > - printf("Second message send failed (%m)\n"); > - return -errno; > - }; > - return 0; > -} > - > -int main(int argc, char **argv) > -{ > - int msg, pid, err; > - struct msgque_data msgque; > - > - if (getuid() != 0) { > - printf("Please run the test as root - Exiting.\n"); > - return ksft_exit_fail(); > - } > - > - msgque.key = ftok(argv[0], 822155650); > - if (msgque.key == -1) { > - printf("Can't make key: %d\n", -errno); > - return ksft_exit_fail(); > - } > - > - msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); > - if (msgque.msq_id == -1) { > - err = -errno; > - printf("Can't create queue: %d\n", err); > - goto err_out; > - } > - > - err = fill_msgque(&msgque); > - if (err) { > - printf("Failed to fill queue: %d\n", err); > - goto err_destroy; > - } > - > - err = dump_queue(&msgque); > - if (err) { > - printf("Failed to dump queue: %d\n", err); > - goto err_destroy; > - } > - > - err = check_and_destroy_queue(&msgque); > - if (err) { > - printf("Failed to check and destroy queue: %d\n", err); > - goto err_out; > - } > - > - err = restore_queue(&msgque); > - if (err) { > - printf("Failed to restore queue: %d\n", err); > - goto err_destroy; > - } > - > - err = check_and_destroy_queue(&msgque); > - if (err) { > - printf("Failed to test queue: %d\n", err); > - goto err_out; > - } > - return ksft_exit_pass(); > - > -err_destroy: > - if (msgctl(msgque.msq_id, IPC_RMID, 0)) { > - printf("Failed to destroy queue: %d\n", -errno); > - return ksft_exit_fail(); > - } > -err_out: > - return ksft_exit_fail(); > -} > diff --git a/tools/testing/selftests/mqueue/.gitignore b/tools/testing/selftests/mqueue/.gitignore > deleted file mode 100644 > index d8d4237..0000000 > --- a/tools/testing/selftests/mqueue/.gitignore > +++ /dev/null > @@ -1,2 +0,0 @@ > -mq_open_tests > -mq_perf_tests > diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile > deleted file mode 100644 > index 0e3b41e..0000000 > --- a/tools/testing/selftests/mqueue/Makefile > +++ /dev/null > @@ -1,22 +0,0 @@ > -CFLAGS = -O2 > - > -all: > - $(CC) $(CFLAGS) mq_open_tests.c -o mq_open_tests -lrt > - $(CC) $(CFLAGS) -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt > - > -include ../lib.mk > - > -override define RUN_TESTS > - @./mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]" > - @./mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]" > -endef > - > -TEST_PROGS := mq_open_tests mq_perf_tests > - > -override define EMIT_TESTS > - echo "./mq_open_tests /test1 || echo \"selftests: mq_open_tests [FAIL]\"" > - echo "./mq_perf_tests || echo \"selftests: mq_perf_tests [FAIL]\"" > -endef > - > -clean: > - 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 > deleted file mode 100644 > index 9c1a5d35..0000000 > --- a/tools/testing/selftests/mqueue/mq_open_tests.c > +++ /dev/null > @@ -1,500 +0,0 @@ > -/* > - * This application is Copyright 2012 Red Hat, Inc. > - * Doug Ledford > - * > - * mq_open_tests is free software: you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation, version 3. > - * > - * mq_open_tests is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * For the full text of the license, see . > - * > - * mq_open_tests.c > - * Tests the various situations that should either succeed or fail to > - * open a posix message queue and then reports whether or not they > - * did as they were supposed to. > - * > - */ > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -static char *usage = > -"Usage:\n" > -" %s path\n" > -"\n" > -" path Path name of the message queue to create\n" > -"\n" > -" Note: this program must be run as root in order to enable all tests\n" > -"\n"; > - > -char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default"; > -char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default"; > -char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; > -char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; > - > -int default_settings; > -struct rlimit saved_limits, cur_limits; > -int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize; > -int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize; > -FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize; > -char *queue_path; > -mqd_t queue = -1; > - > -static inline void __set(FILE *stream, int value, char *err_msg); > -void shutdown(int exit_val, char *err_cause, int line_no); > -static inline int get(FILE *stream); > -static inline void set(FILE *stream, int value); > -static inline void getr(int type, struct rlimit *rlim); > -static inline void setr(int type, struct rlimit *rlim); > -void validate_current_settings(); > -static inline void test_queue(struct mq_attr *attr, struct mq_attr *result); > -static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result); > - > -static inline void __set(FILE *stream, int value, char *err_msg) > -{ > - rewind(stream); > - if (fprintf(stream, "%d", value) < 0) > - perror(err_msg); > -} > - > - > -void shutdown(int exit_val, char *err_cause, int line_no) > -{ > - static int in_shutdown = 0; > - > - /* In case we get called recursively by a set() call below */ > - if (in_shutdown++) > - return; > - > - if (seteuid(0) == -1) > - perror("seteuid() failed"); > - > - if (queue != -1) > - if (mq_close(queue)) > - perror("mq_close() during shutdown"); > - if (queue_path) > - /* > - * Be silent if this fails, if we cleaned up already it's > - * expected to fail > - */ > - mq_unlink(queue_path); > - if (default_settings) { > - if (saved_def_msgs) > - __set(def_msgs, saved_def_msgs, > - "failed to restore saved_def_msgs"); > - if (saved_def_msgsize) > - __set(def_msgsize, saved_def_msgsize, > - "failed to restore saved_def_msgsize"); > - } > - if (saved_max_msgs) > - __set(max_msgs, saved_max_msgs, > - "failed to restore saved_max_msgs"); > - if (saved_max_msgsize) > - __set(max_msgsize, saved_max_msgsize, > - "failed to restore saved_max_msgsize"); > - if (exit_val) > - error(exit_val, errno, "%s at %d", err_cause, line_no); > - exit(0); > -} > - > -static inline int get(FILE *stream) > -{ > - int value; > - rewind(stream); > - if (fscanf(stream, "%d", &value) != 1) > - shutdown(4, "Error reading /proc entry", __LINE__ - 1); > - return value; > -} > - > -static inline void set(FILE *stream, int value) > -{ > - int new_value; > - > - rewind(stream); > - if (fprintf(stream, "%d", value) < 0) > - return shutdown(5, "Failed writing to /proc file", > - __LINE__ - 1); > - new_value = get(stream); > - if (new_value != value) > - return shutdown(5, "We didn't get what we wrote to /proc back", > - __LINE__ - 1); > -} > - > -static inline void getr(int type, struct rlimit *rlim) > -{ > - if (getrlimit(type, rlim)) > - shutdown(6, "getrlimit()", __LINE__ - 1); > -} > - > -static inline void setr(int type, struct rlimit *rlim) > -{ > - if (setrlimit(type, rlim)) > - shutdown(7, "setrlimit()", __LINE__ - 1); > -} > - > -void validate_current_settings() > -{ > - int rlim_needed; > - > - if (cur_limits.rlim_cur < 4096) { > - printf("Current rlimit value for POSIX message queue bytes is " > - "unreasonably low,\nincreasing.\n\n"); > - cur_limits.rlim_cur = 8192; > - cur_limits.rlim_max = 16384; > - setr(RLIMIT_MSGQUEUE, &cur_limits); > - } > - > - if (default_settings) { > - rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 + > - 2 * sizeof(void *)); > - if (rlim_needed > cur_limits.rlim_cur) { > - printf("Temporarily lowering default queue parameters " > - "to something that will work\n" > - "with the current rlimit values.\n\n"); > - set(def_msgs, 10); > - cur_def_msgs = 10; > - set(def_msgsize, 128); > - cur_def_msgsize = 128; > - } > - } else { > - rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 + > - 2 * sizeof(void *)); > - if (rlim_needed > cur_limits.rlim_cur) { > - printf("Temporarily lowering maximum queue parameters " > - "to something that will work\n" > - "with the current rlimit values in case this is " > - "a kernel that ties the default\n" > - "queue parameters to the maximum queue " > - "parameters.\n\n"); > - set(max_msgs, 10); > - cur_max_msgs = 10; > - set(max_msgsize, 128); > - cur_max_msgsize = 128; > - } > - } > -} > - > -/* > - * test_queue - Test opening a queue, shutdown if we fail. This should > - * only be called in situations that should never fail. We clean up > - * after ourselves and return the queue attributes in *result. > - */ > -static inline void test_queue(struct mq_attr *attr, struct mq_attr *result) > -{ > - int flags = O_RDWR | O_EXCL | O_CREAT; > - int perms = DEFFILEMODE; > - > - if ((queue = mq_open(queue_path, flags, perms, attr)) == -1) > - shutdown(1, "mq_open()", __LINE__); > - if (mq_getattr(queue, result)) > - shutdown(1, "mq_getattr()", __LINE__); > - if (mq_close(queue)) > - shutdown(1, "mq_close()", __LINE__); > - queue = -1; > - if (mq_unlink(queue_path)) > - shutdown(1, "mq_unlink()", __LINE__); > -} > - > -/* > - * Same as test_queue above, but failure is not fatal. > - * Returns: > - * 0 - Failed to create a queue > - * 1 - Created a queue, attributes in *result > - */ > -static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result) > -{ > - int flags = O_RDWR | O_EXCL | O_CREAT; > - int perms = DEFFILEMODE; > - > - if ((queue = mq_open(queue_path, flags, perms, attr)) == -1) > - return 0; > - if (mq_getattr(queue, result)) > - shutdown(1, "mq_getattr()", __LINE__); > - if (mq_close(queue)) > - shutdown(1, "mq_close()", __LINE__); > - queue = -1; > - if (mq_unlink(queue_path)) > - shutdown(1, "mq_unlink()", __LINE__); > - return 1; > -} > - > -int main(int argc, char *argv[]) > -{ > - struct mq_attr attr, result; > - > - if (argc != 2) { > - fprintf(stderr, "Must pass a valid queue name\n\n"); > - fprintf(stderr, usage, argv[0]); > - exit(1); > - } > - > - /* > - * Although we can create a msg queue with a non-absolute path name, > - * unlink will fail. So, if the name doesn't start with a /, add one > - * when we save it. > - */ > - if (*argv[1] == '/') > - queue_path = strdup(argv[1]); > - else { > - queue_path = malloc(strlen(argv[1]) + 2); > - if (!queue_path) { > - perror("malloc()"); > - exit(1); > - } > - queue_path[0] = '/'; > - queue_path[1] = 0; > - strcat(queue_path, argv[1]); > - } > - > - if (getuid() != 0) { > - fprintf(stderr, "Not running as root, but almost all tests " > - "require root in order to modify\nsystem settings. " > - "Exiting.\n"); > - exit(1); > - } > - > - /* Find out what files there are for us to make tweaks in */ > - def_msgs = fopen(DEF_MSGS, "r+"); > - def_msgsize = fopen(DEF_MSGSIZE, "r+"); > - max_msgs = fopen(MAX_MSGS, "r+"); > - max_msgsize = fopen(MAX_MSGSIZE, "r+"); > - > - if (!max_msgs) > - shutdown(2, "Failed to open msg_max", __LINE__); > - if (!max_msgsize) > - shutdown(2, "Failed to open msgsize_max", __LINE__); > - if (def_msgs || def_msgsize) > - default_settings = 1; > - > - /* Load up the current system values for everything we can */ > - getr(RLIMIT_MSGQUEUE, &saved_limits); > - cur_limits = saved_limits; > - if (default_settings) { > - saved_def_msgs = cur_def_msgs = get(def_msgs); > - saved_def_msgsize = cur_def_msgsize = get(def_msgsize); > - } > - saved_max_msgs = cur_max_msgs = get(max_msgs); > - saved_max_msgsize = cur_max_msgsize = get(max_msgsize); > - > - /* Tell the user our initial state */ > - printf("\nInitial system state:\n"); > - printf("\tUsing queue path:\t\t%s\n", queue_path); > - printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", > - (long) saved_limits.rlim_cur); > - printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", > - (long) saved_limits.rlim_max); > - printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize); > - printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs); > - if (default_settings) { > - printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize); > - printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs); > - } else { > - printf("\tDefault Message Size:\t\tNot Supported\n"); > - printf("\tDefault Queue Size:\t\tNot Supported\n"); > - } > - printf("\n"); > - > - validate_current_settings(); > - > - printf("Adjusted system state for testing:\n"); > - printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur); > - printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max); > - printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize); > - printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs); > - if (default_settings) { > - printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize); > - printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs); > - } > - > - printf("\n\nTest series 1, behavior when no attr struct " > - "passed to mq_open:\n"); > - if (!default_settings) { > - test_queue(NULL, &result); > - printf("Given sane system settings, mq_open without an attr " > - "struct succeeds:\tPASS\n"); > - if (result.mq_maxmsg != cur_max_msgs || > - result.mq_msgsize != cur_max_msgsize) { > - printf("Kernel does not support setting the default " > - "mq attributes,\nbut also doesn't tie the " > - "defaults to the maximums:\t\t\tPASS\n"); > - } else { > - set(max_msgs, ++cur_max_msgs); > - set(max_msgsize, ++cur_max_msgsize); > - test_queue(NULL, &result); > - if (result.mq_maxmsg == cur_max_msgs && > - result.mq_msgsize == cur_max_msgsize) > - printf("Kernel does not support setting the " > - "default mq attributes and\n" > - "also ties system wide defaults to " > - "the system wide maximums:\t\t" > - "FAIL\n"); > - else > - printf("Kernel does not support setting the " > - "default mq attributes,\n" > - "but also doesn't tie the defaults to " > - "the maximums:\t\t\tPASS\n"); > - } > - } else { > - printf("Kernel supports setting defaults separately from " > - "maximums:\t\tPASS\n"); > - /* > - * While we are here, go ahead and test that the kernel > - * properly follows the default settings > - */ > - test_queue(NULL, &result); > - printf("Given sane values, mq_open without an attr struct " > - "succeeds:\t\tPASS\n"); > - if (result.mq_maxmsg != cur_def_msgs || > - result.mq_msgsize != cur_def_msgsize) > - printf("Kernel supports setting defaults, but does " > - "not actually honor them:\tFAIL\n\n"); > - else { > - set(def_msgs, ++cur_def_msgs); > - set(def_msgsize, ++cur_def_msgsize); > - /* In case max was the same as the default */ > - set(max_msgs, ++cur_max_msgs); > - set(max_msgsize, ++cur_max_msgsize); > - test_queue(NULL, &result); > - if (result.mq_maxmsg != cur_def_msgs || > - result.mq_msgsize != cur_def_msgsize) > - printf("Kernel supports setting defaults, but " > - "does not actually honor them:\t" > - "FAIL\n"); > - else > - printf("Kernel properly honors default setting " > - "knobs:\t\t\t\tPASS\n"); > - } > - set(def_msgs, cur_max_msgs + 1); > - cur_def_msgs = cur_max_msgs + 1; > - set(def_msgsize, cur_max_msgsize + 1); > - cur_def_msgsize = cur_max_msgsize + 1; > - if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >= > - cur_limits.rlim_cur) { > - cur_limits.rlim_cur = (cur_def_msgs + 2) * > - (cur_def_msgsize + 2 * sizeof(void *)); > - cur_limits.rlim_max = 2 * cur_limits.rlim_cur; > - setr(RLIMIT_MSGQUEUE, &cur_limits); > - } > - if (test_queue_fail(NULL, &result)) { > - if (result.mq_maxmsg == cur_max_msgs && > - result.mq_msgsize == cur_max_msgsize) > - printf("Kernel properly limits default values " > - "to lesser of default/max:\t\tPASS\n"); > - else > - printf("Kernel does not properly set default " > - "queue parameters when\ndefaults > " > - "max:\t\t\t\t\t\t\t\tFAIL\n"); > - } else > - printf("Kernel fails to open mq because defaults are " > - "greater than maximums:\tFAIL\n"); > - set(def_msgs, --cur_def_msgs); > - set(def_msgsize, --cur_def_msgsize); > - cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs * > - cur_def_msgsize; > - setr(RLIMIT_MSGQUEUE, &cur_limits); > - if (test_queue_fail(NULL, &result)) > - printf("Kernel creates queue even though defaults " > - "would exceed\nrlimit setting:" > - "\t\t\t\t\t\t\t\tFAIL\n"); > - else > - printf("Kernel properly fails to create queue when " > - "defaults would\nexceed rlimit:" > - "\t\t\t\t\t\t\t\tPASS\n"); > - } > - > - /* > - * Test #2 - open with an attr struct that exceeds rlimit > - */ > - printf("\n\nTest series 2, behavior when attr struct is " > - "passed to mq_open:\n"); > - cur_max_msgs = 32; > - cur_max_msgsize = cur_limits.rlim_max >> 4; > - set(max_msgs, cur_max_msgs); > - set(max_msgsize, cur_max_msgsize); > - attr.mq_maxmsg = cur_max_msgs; > - attr.mq_msgsize = cur_max_msgsize; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open in excess of rlimit max when euid = 0 " > - "succeeded:\t\tFAIL\n"); > - else > - printf("Queue open in excess of rlimit max when euid = 0 " > - "failed:\t\tPASS\n"); > - attr.mq_maxmsg = cur_max_msgs + 1; > - attr.mq_msgsize = 10; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open with mq_maxmsg > limit when euid = 0 " > - "succeeded:\t\tPASS\n"); > - else > - printf("Queue open with mq_maxmsg > limit when euid = 0 " > - "failed:\t\tFAIL\n"); > - attr.mq_maxmsg = 1; > - attr.mq_msgsize = cur_max_msgsize + 1; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open with mq_msgsize > limit when euid = 0 " > - "succeeded:\t\tPASS\n"); > - else > - printf("Queue open with mq_msgsize > limit when euid = 0 " > - "failed:\t\tFAIL\n"); > - attr.mq_maxmsg = 65536; > - attr.mq_msgsize = 65536; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open with total size > 2GB when euid = 0 " > - "succeeded:\t\tFAIL\n"); > - else > - printf("Queue open with total size > 2GB when euid = 0 " > - "failed:\t\t\tPASS\n"); > - > - if (seteuid(99) == -1) { > - perror("seteuid() failed"); > - exit(1); > - } > - > - attr.mq_maxmsg = cur_max_msgs; > - attr.mq_msgsize = cur_max_msgsize; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open in excess of rlimit max when euid = 99 " > - "succeeded:\t\tFAIL\n"); > - else > - printf("Queue open in excess of rlimit max when euid = 99 " > - "failed:\t\tPASS\n"); > - attr.mq_maxmsg = cur_max_msgs + 1; > - attr.mq_msgsize = 10; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open with mq_maxmsg > limit when euid = 99 " > - "succeeded:\t\tFAIL\n"); > - else > - printf("Queue open with mq_maxmsg > limit when euid = 99 " > - "failed:\t\tPASS\n"); > - attr.mq_maxmsg = 1; > - attr.mq_msgsize = cur_max_msgsize + 1; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open with mq_msgsize > limit when euid = 99 " > - "succeeded:\t\tFAIL\n"); > - else > - printf("Queue open with mq_msgsize > limit when euid = 99 " > - "failed:\t\tPASS\n"); > - attr.mq_maxmsg = 65536; > - attr.mq_msgsize = 65536; > - if (test_queue_fail(&attr, &result)) > - printf("Queue open with total size > 2GB when euid = 99 " > - "succeeded:\t\tFAIL\n"); > - else > - printf("Queue open with total size > 2GB when euid = 99 " > - "failed:\t\t\tPASS\n"); > - > - shutdown(0,"",0); > -} > diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c > deleted file mode 100644 > index 8519e9e..0000000 > --- a/tools/testing/selftests/mqueue/mq_perf_tests.c > +++ /dev/null > @@ -1,742 +0,0 @@ > -/* > - * This application is Copyright 2012 Red Hat, Inc. > - * Doug Ledford > - * > - * mq_perf_tests is free software: you can redistribute it and/or modify > - * it under the terms of the GNU General Public License as published by > - * the Free Software Foundation, version 3. > - * > - * mq_perf_tests is distributed in the hope that it will be useful, > - * but WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > - * GNU General Public License for more details. > - * > - * For the full text of the license, see . > - * > - * mq_perf_tests.c > - * Tests various types of message queue workloads, concentrating on those > - * situations that invole large message sizes, large message queue depths, > - * or both, and reports back useful metrics about kernel message queue > - * performance. > - * > - */ > -#define _GNU_SOURCE > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -static char *usage = > -"Usage:\n" > -" %s [-c #[,#..] -f] path\n" > -"\n" > -" -c # Skip most tests and go straight to a high queue depth test\n" > -" and then run that test continuously (useful for running at\n" > -" the same time as some other workload to see how much the\n" > -" cache thrashing caused by adding messages to a very deep\n" > -" queue impacts the performance of other programs). The number\n" > -" indicates which CPU core we should bind the process to during\n" > -" the run. If you have more than one physical CPU, then you\n" > -" will need one copy per physical CPU package, and you should\n" > -" specify the CPU cores to pin ourself to via a comma separated\n" > -" list of CPU values.\n" > -" -f Only usable with continuous mode. Pin ourself to the CPUs\n" > -" as requested, then instead of looping doing a high mq\n" > -" workload, just busy loop. This will allow us to lock up a\n" > -" single CPU just like we normally would, but without actually\n" > -" thrashing the CPU cache. This is to make it easier to get\n" > -" comparable numbers from some other workload running on the\n" > -" other CPUs. One set of numbers with # CPUs locked up running\n" > -" an mq workload, and another set of numbers with those same\n" > -" CPUs locked away from the test workload, but not doing\n" > -" anything to trash the cache like the mq workload might.\n" > -" path Path name of the message queue to create\n" > -"\n" > -" Note: this program must be run as root in order to enable all tests\n" > -"\n"; > - > -char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max"; > -char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max"; > - > -#define min(a, b) ((a) < (b) ? (a) : (b)) > -#define MAX_CPUS 64 > -char *cpu_option_string; > -int cpus_to_pin[MAX_CPUS]; > -int num_cpus_to_pin; > -pthread_t cpu_threads[MAX_CPUS]; > -pthread_t main_thread; > -cpu_set_t *cpu_set; > -int cpu_set_size; > -int cpus_online; > - > -#define MSG_SIZE 16 > -#define TEST1_LOOPS 10000000 > -#define TEST2_LOOPS 100000 > -int continuous_mode; > -int continuous_mode_fake; > - > -struct rlimit saved_limits, cur_limits; > -int saved_max_msgs, saved_max_msgsize; > -int cur_max_msgs, cur_max_msgsize; > -FILE *max_msgs, *max_msgsize; > -int cur_nice; > -char *queue_path = "/mq_perf_tests"; > -mqd_t queue = -1; > -struct mq_attr result; > -int mq_prio_max; > - > -const struct poptOption options[] = { > - { > - .longName = "continuous", > - .shortName = 'c', > - .argInfo = POPT_ARG_STRING, > - .arg = &cpu_option_string, > - .val = 'c', > - .descrip = "Run continuous tests at a high queue depth in " > - "order to test the effects of cache thrashing on " > - "other tasks on the system. This test is intended " > - "to be run on one core of each physical CPU while " > - "some other CPU intensive task is run on all the other " > - "cores of that same physical CPU and the other task " > - "is timed. It is assumed that the process of adding " > - "messages to the message queue in a tight loop will " > - "impact that other task to some degree. Once the " > - "tests are performed in this way, you should then " > - "re-run the tests using fake mode in order to check " > - "the difference in time required to perform the CPU " > - "intensive task", > - .argDescrip = "cpu[,cpu]", > - }, > - { > - .longName = "fake", > - .shortName = 'f', > - .argInfo = POPT_ARG_NONE, > - .arg = &continuous_mode_fake, > - .val = 0, > - .descrip = "Tie up the CPUs that we would normally tie up in" > - "continuous mode, but don't actually do any mq stuff, " > - "just keep the CPU busy so it can't be used to process " > - "system level tasks as this would free up resources on " > - "the other CPU cores and skew the comparison between " > - "the no-mqueue work and mqueue work tests", > - .argDescrip = NULL, > - }, > - { > - .longName = "path", > - .shortName = 'p', > - .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, > - .arg = &queue_path, > - .val = 'p', > - .descrip = "The name of the path to use in the mqueue " > - "filesystem for our tests", > - .argDescrip = "pathname", > - }, > - POPT_AUTOHELP > - POPT_TABLEEND > -}; > - > -static inline void __set(FILE *stream, int value, char *err_msg); > -void shutdown(int exit_val, char *err_cause, int line_no); > -void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context); > -void sig_action(int signum, siginfo_t *info, void *context); > -static inline int get(FILE *stream); > -static inline void set(FILE *stream, int value); > -static inline int try_set(FILE *stream, int value); > -static inline void getr(int type, struct rlimit *rlim); > -static inline void setr(int type, struct rlimit *rlim); > -static inline void open_queue(struct mq_attr *attr); > -void increase_limits(void); > - > -static inline void __set(FILE *stream, int value, char *err_msg) > -{ > - rewind(stream); > - if (fprintf(stream, "%d", value) < 0) > - perror(err_msg); > -} > - > - > -void shutdown(int exit_val, char *err_cause, int line_no) > -{ > - static int in_shutdown = 0; > - int errno_at_shutdown = errno; > - int i; > - > - /* In case we get called by multiple threads or from an sighandler */ > - if (in_shutdown++) > - return; > - > - for (i = 0; i < num_cpus_to_pin; i++) > - if (cpu_threads[i]) { > - pthread_kill(cpu_threads[i], SIGUSR1); > - pthread_join(cpu_threads[i], NULL); > - } > - > - if (queue != -1) > - if (mq_close(queue)) > - perror("mq_close() during shutdown"); > - if (queue_path) > - /* > - * Be silent if this fails, if we cleaned up already it's > - * expected to fail > - */ > - mq_unlink(queue_path); > - if (saved_max_msgs) > - __set(max_msgs, saved_max_msgs, > - "failed to restore saved_max_msgs"); > - if (saved_max_msgsize) > - __set(max_msgsize, saved_max_msgsize, > - "failed to restore saved_max_msgsize"); > - if (exit_val) > - error(exit_val, errno_at_shutdown, "%s at %d", > - err_cause, line_no); > - exit(0); > -} > - > -void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context) > -{ > - if (pthread_self() != main_thread) > - pthread_exit(0); > - else { > - fprintf(stderr, "Caught signal %d in SIGUSR1 handler, " > - "exiting\n", signum); > - shutdown(0, "", 0); > - fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); > - exit(0); > - } > -} > - > -void sig_action(int signum, siginfo_t *info, void *context) > -{ > - if (pthread_self() != main_thread) > - pthread_kill(main_thread, signum); > - else { > - fprintf(stderr, "Caught signal %d, exiting\n", signum); > - shutdown(0, "", 0); > - fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n"); > - exit(0); > - } > -} > - > -static inline int get(FILE *stream) > -{ > - int value; > - rewind(stream); > - if (fscanf(stream, "%d", &value) != 1) > - shutdown(4, "Error reading /proc entry", __LINE__); > - return value; > -} > - > -static inline void set(FILE *stream, int value) > -{ > - int new_value; > - > - rewind(stream); > - if (fprintf(stream, "%d", value) < 0) > - return shutdown(5, "Failed writing to /proc file", __LINE__); > - new_value = get(stream); > - if (new_value != value) > - return shutdown(5, "We didn't get what we wrote to /proc back", > - __LINE__); > -} > - > -static inline int try_set(FILE *stream, int value) > -{ > - int new_value; > - > - rewind(stream); > - fprintf(stream, "%d", value); > - new_value = get(stream); > - return new_value == value; > -} > - > -static inline void getr(int type, struct rlimit *rlim) > -{ > - if (getrlimit(type, rlim)) > - shutdown(6, "getrlimit()", __LINE__); > -} > - > -static inline void setr(int type, struct rlimit *rlim) > -{ > - if (setrlimit(type, rlim)) > - shutdown(7, "setrlimit()", __LINE__); > -} > - > -/** > - * open_queue - open the global queue for testing > - * @attr - An attr struct specifying the desired queue traits > - * @result - An attr struct that lists the actual traits the queue has > - * > - * This open is not allowed to fail, failure will result in an orderly > - * shutdown of the program. The global queue_path is used to set what > - * queue to open, the queue descriptor is saved in the global queue > - * variable. > - */ > -static inline void open_queue(struct mq_attr *attr) > -{ > - int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK; > - int perms = DEFFILEMODE; > - > - queue = mq_open(queue_path, flags, perms, attr); > - if (queue == -1) > - shutdown(1, "mq_open()", __LINE__); > - if (mq_getattr(queue, &result)) > - shutdown(1, "mq_getattr()", __LINE__); > - printf("\n\tQueue %s created:\n", queue_path); > - printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ? > - "O_NONBLOCK" : "(null)"); > - printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg); > - printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize); > - printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs); > -} > - > -void *fake_cont_thread(void *arg) > -{ > - int i; > - > - for (i = 0; i < num_cpus_to_pin; i++) > - if (cpu_threads[i] == pthread_self()) > - break; > - printf("\tStarted fake continuous mode thread %d on CPU %d\n", i, > - cpus_to_pin[i]); > - while (1) > - ; > -} > - > -void *cont_thread(void *arg) > -{ > - char buff[MSG_SIZE]; > - int i, priority; > - > - for (i = 0; i < num_cpus_to_pin; i++) > - if (cpu_threads[i] == pthread_self()) > - break; > - printf("\tStarted continuous mode thread %d on CPU %d\n", i, > - cpus_to_pin[i]); > - while (1) { > - while (mq_send(queue, buff, sizeof(buff), 0) == 0) > - ; > - mq_receive(queue, buff, sizeof(buff), &priority); > - } > -} > - > -#define drain_queue() \ > - while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE) > - > -#define do_untimed_send() \ > - do { \ > - if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ > - shutdown(3, "Test send failure", __LINE__); \ > - } while (0) > - > -#define do_send_recv() \ > - do { \ > - clock_gettime(clock, &start); \ > - if (mq_send(queue, buff, MSG_SIZE, prio_out)) \ > - shutdown(3, "Test send failure", __LINE__); \ > - clock_gettime(clock, &middle); \ > - if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \ > - shutdown(3, "Test receive failure", __LINE__); \ > - clock_gettime(clock, &end); \ > - nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \ > - (middle.tv_nsec - start.tv_nsec); \ > - send_total.tv_nsec += nsec; \ > - if (send_total.tv_nsec >= 1000000000) { \ > - send_total.tv_sec++; \ > - send_total.tv_nsec -= 1000000000; \ > - } \ > - nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \ > - (end.tv_nsec - middle.tv_nsec); \ > - recv_total.tv_nsec += nsec; \ > - if (recv_total.tv_nsec >= 1000000000) { \ > - recv_total.tv_sec++; \ > - recv_total.tv_nsec -= 1000000000; \ > - } \ > - } while (0) > - > -struct test { > - char *desc; > - void (*func)(int *); > -}; > - > -void const_prio(int *prio) > -{ > - return; > -} > - > -void inc_prio(int *prio) > -{ > - if (++*prio == mq_prio_max) > - *prio = 0; > -} > - > -void dec_prio(int *prio) > -{ > - if (--*prio < 0) > - *prio = mq_prio_max - 1; > -} > - > -void random_prio(int *prio) > -{ > - *prio = random() % mq_prio_max; > -} > - > -struct test test2[] = { > - {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n", > - const_prio}, > - {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n", > - inc_prio}, > - {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n", > - dec_prio}, > - {"\n\tTest #2d: Time send/recv message, queue full, random prio\n", > - random_prio}, > - {NULL, NULL} > -}; > - > -/** > - * Tests to perform (all done with MSG_SIZE messages): > - * > - * 1) Time to add/remove message with 0 messages on queue > - * 1a) with constant prio > - * 2) Time to add/remove message when queue close to capacity: > - * 2a) with constant prio > - * 2b) with increasing prio > - * 2c) with decreasing prio > - * 2d) with random prio > - * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX) > - */ > -void *perf_test_thread(void *arg) > -{ > - char buff[MSG_SIZE]; > - int prio_out, prio_in; > - int i; > - clockid_t clock; > - pthread_t *t; > - struct timespec res, start, middle, end, send_total, recv_total; > - unsigned long long nsec; > - struct test *cur_test; > - > - t = &cpu_threads[0]; > - printf("\n\tStarted mqueue performance test thread on CPU %d\n", > - cpus_to_pin[0]); > - mq_prio_max = sysconf(_SC_MQ_PRIO_MAX); > - if (mq_prio_max == -1) > - shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__); > - if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0) > - shutdown(2, "pthread_getcpuclockid", __LINE__); > - > - if (clock_getres(clock, &res)) > - shutdown(2, "clock_getres()", __LINE__); > - > - printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max); > - printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec, > - res.tv_nsec > 1 ? "s" : ""); > - > - > - > - printf("\n\tTest #1: Time send/recv message, queue empty\n"); > - printf("\t\t(%d iterations)\n", TEST1_LOOPS); > - prio_out = 0; > - send_total.tv_sec = 0; > - send_total.tv_nsec = 0; > - recv_total.tv_sec = 0; > - recv_total.tv_nsec = 0; > - for (i = 0; i < TEST1_LOOPS; i++) > - do_send_recv(); > - printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", > - send_total.tv_sec, send_total.tv_nsec); > - nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + > - send_total.tv_nsec) / TEST1_LOOPS; > - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > - printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", > - recv_total.tv_sec, recv_total.tv_nsec); > - nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + > - recv_total.tv_nsec) / TEST1_LOOPS; > - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > - > - > - for (cur_test = test2; cur_test->desc != NULL; cur_test++) { > - printf("%s:\n", cur_test->desc); > - printf("\t\t(%d iterations)\n", TEST2_LOOPS); > - prio_out = 0; > - send_total.tv_sec = 0; > - send_total.tv_nsec = 0; > - recv_total.tv_sec = 0; > - recv_total.tv_nsec = 0; > - printf("\t\tFilling queue..."); > - fflush(stdout); > - clock_gettime(clock, &start); > - for (i = 0; i < result.mq_maxmsg - 1; i++) { > - do_untimed_send(); > - cur_test->func(&prio_out); > - } > - clock_gettime(clock, &end); > - nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * > - 1000000000) + (end.tv_nsec - start.tv_nsec); > - printf("done.\t\t%lld.%llds\n", nsec / 1000000000, > - nsec % 1000000000); > - printf("\t\tTesting..."); > - fflush(stdout); > - for (i = 0; i < TEST2_LOOPS; i++) { > - do_send_recv(); > - cur_test->func(&prio_out); > - } > - printf("done.\n"); > - printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", > - send_total.tv_sec, send_total.tv_nsec); > - nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + > - send_total.tv_nsec) / TEST2_LOOPS; > - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > - printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", > - recv_total.tv_sec, recv_total.tv_nsec); > - nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + > - recv_total.tv_nsec) / TEST2_LOOPS; > - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); > - printf("\t\tDraining queue..."); > - fflush(stdout); > - clock_gettime(clock, &start); > - drain_queue(); > - clock_gettime(clock, &end); > - nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) * > - 1000000000) + (end.tv_nsec - start.tv_nsec); > - printf("done.\t\t%lld.%llds\n", nsec / 1000000000, > - nsec % 1000000000); > - } > - return 0; > -} > - > -void increase_limits(void) > -{ > - cur_limits.rlim_cur = RLIM_INFINITY; > - cur_limits.rlim_max = RLIM_INFINITY; > - setr(RLIMIT_MSGQUEUE, &cur_limits); > - while (try_set(max_msgs, cur_max_msgs += 10)) > - ; > - cur_max_msgs = get(max_msgs); > - while (try_set(max_msgsize, cur_max_msgsize += 1024)) > - ; > - cur_max_msgsize = get(max_msgsize); > - if (setpriority(PRIO_PROCESS, 0, -20) != 0) > - shutdown(2, "setpriority()", __LINE__); > - cur_nice = -20; > -} > - > -int main(int argc, char *argv[]) > -{ > - struct mq_attr attr; > - char *option, *next_option; > - int i, cpu, rc; > - struct sigaction sa; > - poptContext popt_context; > - void *retval; > - > - main_thread = pthread_self(); > - num_cpus_to_pin = 0; > - > - if (sysconf(_SC_NPROCESSORS_ONLN) == -1) { > - perror("sysconf(_SC_NPROCESSORS_ONLN)"); > - exit(1); > - } > - cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN)); > - cpu_set = CPU_ALLOC(cpus_online); > - if (cpu_set == NULL) { > - perror("CPU_ALLOC()"); > - exit(1); > - } > - cpu_set_size = CPU_ALLOC_SIZE(cpus_online); > - CPU_ZERO_S(cpu_set_size, cpu_set); > - > - popt_context = poptGetContext(NULL, argc, (const char **)argv, > - options, 0); > - > - while ((rc = poptGetNextOpt(popt_context)) > 0) { > - switch (rc) { > - case 'c': > - continuous_mode = 1; > - option = cpu_option_string; > - do { > - next_option = strchr(option, ','); > - if (next_option) > - *next_option = '\0'; > - cpu = atoi(option); > - if (cpu >= cpus_online) > - fprintf(stderr, "CPU %d exceeds " > - "cpus online, ignoring.\n", > - cpu); > - else > - cpus_to_pin[num_cpus_to_pin++] = cpu; > - if (next_option) > - option = ++next_option; > - } while (next_option && num_cpus_to_pin < MAX_CPUS); > - /* Double check that they didn't give us the same CPU > - * more than once */ > - for (cpu = 0; cpu < num_cpus_to_pin; cpu++) { > - if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size, > - cpu_set)) { > - fprintf(stderr, "Any given CPU may " > - "only be given once.\n"); > - exit(1); > - } else > - CPU_SET_S(cpus_to_pin[cpu], > - cpu_set_size, cpu_set); > - } > - break; > - case 'p': > - /* > - * Although we can create a msg queue with a > - * non-absolute path name, unlink will fail. So, > - * if the name doesn't start with a /, add one > - * when we save it. > - */ > - option = queue_path; > - if (*option != '/') { > - queue_path = malloc(strlen(option) + 2); > - if (!queue_path) { > - perror("malloc()"); > - exit(1); > - } > - queue_path[0] = '/'; > - queue_path[1] = 0; > - strcat(queue_path, option); > - free(option); > - } > - break; > - } > - } > - > - if (continuous_mode && num_cpus_to_pin == 0) { > - fprintf(stderr, "Must pass at least one CPU to continuous " > - "mode.\n"); > - poptPrintUsage(popt_context, stderr, 0); > - exit(1); > - } else if (!continuous_mode) { > - num_cpus_to_pin = 1; > - cpus_to_pin[0] = cpus_online - 1; > - } > - > - if (getuid() != 0) { > - fprintf(stderr, "Not running as root, but almost all tests " > - "require root in order to modify\nsystem settings. " > - "Exiting.\n"); > - exit(1); > - } > - > - max_msgs = fopen(MAX_MSGS, "r+"); > - max_msgsize = fopen(MAX_MSGSIZE, "r+"); > - if (!max_msgs) > - shutdown(2, "Failed to open msg_max", __LINE__); > - if (!max_msgsize) > - shutdown(2, "Failed to open msgsize_max", __LINE__); > - > - /* Load up the current system values for everything we can */ > - getr(RLIMIT_MSGQUEUE, &saved_limits); > - cur_limits = saved_limits; > - saved_max_msgs = cur_max_msgs = get(max_msgs); > - saved_max_msgsize = cur_max_msgsize = get(max_msgsize); > - errno = 0; > - cur_nice = getpriority(PRIO_PROCESS, 0); > - if (errno) > - shutdown(2, "getpriority()", __LINE__); > - > - /* Tell the user our initial state */ > - printf("\nInitial system state:\n"); > - printf("\tUsing queue path:\t\t\t%s\n", queue_path); > - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", > - (long) saved_limits.rlim_cur); > - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", > - (long) saved_limits.rlim_max); > - printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize); > - printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs); > - printf("\tNice value:\t\t\t\t%d\n", cur_nice); > - printf("\n"); > - > - increase_limits(); > - > - printf("Adjusted system state for testing:\n"); > - if (cur_limits.rlim_cur == RLIM_INFINITY) { > - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n"); > - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n"); > - } else { > - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", > - (long) cur_limits.rlim_cur); > - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", > - (long) cur_limits.rlim_max); > - } > - printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize); > - printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs); > - printf("\tNice value:\t\t\t\t%d\n", cur_nice); > - printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ? > - (continuous_mode_fake ? "fake mode" : "enabled") : > - "disabled"); > - printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]); > - for (cpu = 1; cpu < num_cpus_to_pin; cpu++) > - printf(",%d", cpus_to_pin[cpu]); > - printf("\n"); > - > - sa.sa_sigaction = sig_action_SIGUSR1; > - sigemptyset(&sa.sa_mask); > - sigaddset(&sa.sa_mask, SIGHUP); > - sigaddset(&sa.sa_mask, SIGINT); > - sigaddset(&sa.sa_mask, SIGQUIT); > - sigaddset(&sa.sa_mask, SIGTERM); > - sa.sa_flags = SA_SIGINFO; > - if (sigaction(SIGUSR1, &sa, NULL) == -1) > - shutdown(1, "sigaction(SIGUSR1)", __LINE__); > - sa.sa_sigaction = sig_action; > - if (sigaction(SIGHUP, &sa, NULL) == -1) > - shutdown(1, "sigaction(SIGHUP)", __LINE__); > - if (sigaction(SIGINT, &sa, NULL) == -1) > - shutdown(1, "sigaction(SIGINT)", __LINE__); > - if (sigaction(SIGQUIT, &sa, NULL) == -1) > - shutdown(1, "sigaction(SIGQUIT)", __LINE__); > - if (sigaction(SIGTERM, &sa, NULL) == -1) > - shutdown(1, "sigaction(SIGTERM)", __LINE__); > - > - if (!continuous_mode_fake) { > - attr.mq_flags = O_NONBLOCK; > - attr.mq_maxmsg = cur_max_msgs; > - attr.mq_msgsize = MSG_SIZE; > - open_queue(&attr); > - } > - for (i = 0; i < num_cpus_to_pin; i++) { > - pthread_attr_t thread_attr; > - void *thread_func; > - > - if (continuous_mode_fake) > - thread_func = &fake_cont_thread; > - else if (continuous_mode) > - thread_func = &cont_thread; > - else > - thread_func = &perf_test_thread; > - > - CPU_ZERO_S(cpu_set_size, cpu_set); > - CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set); > - pthread_attr_init(&thread_attr); > - pthread_attr_setaffinity_np(&thread_attr, cpu_set_size, > - cpu_set); > - if (pthread_create(&cpu_threads[i], &thread_attr, thread_func, > - NULL)) > - shutdown(1, "pthread_create()", __LINE__); > - pthread_attr_destroy(&thread_attr); > - } > - > - if (!continuous_mode) { > - pthread_join(cpu_threads[0], &retval); > - shutdown((long)retval, "perf_test_thread()", __LINE__); > - } else { > - while (1) > - sleep(1); > - } > - shutdown(0, "", 0); > -} > -- Shuah Khan Sr. Linux Kernel Developer Open Source Innovation Group Samsung Research America (Silicon Valley) shuahkh@osg.samsung.com | (970) 217-8978 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/