From: Subrata M. <su...@li...> - 2009-05-11 10:14:28
|
On Sat, 2009-05-09 at 16:16 +0800, Miao Xie wrote: > This is the patch of new testcases for the functionality test of cpuset. > It contains cpu hotplug vs cpuset test, load balance vs cpuset test, > schedule domains partition test, memory pressure measurement function > test, page caches spread test and memory allocation test. > > Note: page caches spread test(test of cpuset11) may fail because there is > something wrong with the kernel. I have made a patch to fix it. Now the > patch was adding into -mm tree. > > Signed-off-by: Miao Xie <mi...@cn...> Thanks Miao for making these test available to LTP. I hope you would continue to update these tests as and when required, as well as give some more tests to LTP as per your own areas of interest. Regards-- Subrata > --- > testcases/kernel/controllers/README | 1 + > testcases/kernel/controllers/cpuset/Makefile | 3 + > testcases/kernel/controllers/cpuset/README | 36 +- > .../cpuset/cpuset_hotplug_test/Makefile | 22 + > .../cpuset_hotplug_test/cpuset_hotplug_test.sh | 261 ++++++ > .../cpuset_hotplug_test/cpuset_list_compute.c | 115 +++ > .../kernel/controllers/cpuset/cpuset_lib/cpuinfo.c | 482 +++++++++++ > .../kernel/controllers/cpuset/cpuset_lib/cpuinfo.h | 24 + > .../controllers/cpuset/cpuset_lib/cpuset_funcs.sh | 93 ++- > .../kernel/controllers/cpuset/cpuset_lib/meminfo.c | 122 +++ > .../kernel/controllers/cpuset/cpuset_lib/meminfo.h | 11 + > .../cpuset/cpuset_load_balance_test/Makefile | 24 + > .../cpuset_load_balance_test/cpuset_cpu_hog.c | 316 ++++++++ > .../cpuset_load_balance_test.sh | 367 +++++++++ > .../cpuset_sched_domains_check.c | 135 ++++ > .../cpuset_sched_domains_test.sh | 306 +++++++ > .../cpuset/cpuset_memory_pressure_test/Makefile | 16 + > .../cpuset_memory_pressure.c | 57 ++ > .../cpuset_memory_pressure_testset.sh | 260 ++++++ > .../cpuset/cpuset_memory_spread_test/Makefile | 16 + > .../cpuset_memory_spread_test/cpuset_mem_hog.c | 127 +++ > .../cpuset_memory_spread_testset.sh | 335 ++++++++ > .../controllers/cpuset/cpuset_memory_test/Makefile | 20 + > .../cpuset/cpuset_memory_test/cpuset_memory_test.c | 387 +++++++++ > .../cpuset_memory_test/cpuset_memory_testset.sh | 832 ++++++++++++++++++++ > .../cpuset_syscall_test/cpuset_syscall_testset.sh | 2 +- > .../kernel/controllers/cpuset/run_cpuset_test.sh | 54 ++ > testcases/kernel/controllers/test_controllers.sh | 6 + > 28 files changed, 4419 insertions(+), 11 deletions(-) > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_hotplug_test/Makefile > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_hotplug_test.sh > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_list_compute.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.h > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.h > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_load_balance_test/Makefile > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_cpu_hog.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_load_balance_test.sh > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_sched_domains_check.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_sched_domains_test.sh > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/Makefile > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/Makefile > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_mem_hog.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_test/Makefile > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_test.c > create mode 100644 testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh > > diff --git a/testcases/kernel/controllers/README b/testcases/kernel/controllers/README > index 6cb0149..300bd8f 100644 > --- a/testcases/kernel/controllers/README > +++ b/testcases/kernel/controllers/README > @@ -69,6 +69,7 @@ CONFIG_CGROUPS=y > CONFIG_CGROUP_DEBUG=y > CONFIG_CGROUP_NS=y > CONFIG_CPUSETS=y > +CONFIG_PROC_PID_CPUSET=y > CONFIG_GROUP_SCHED=y > CONFIG_FAIR_GROUP_SCHED=y > CONFIG_RT_GROUP_SCHED=y > diff --git a/testcases/kernel/controllers/cpuset/Makefile b/testcases/kernel/controllers/cpuset/Makefile > index 7be0f5b..036af7f 100644 > --- a/testcases/kernel/controllers/cpuset/Makefile > +++ b/testcases/kernel/controllers/cpuset/Makefile > @@ -1,5 +1,8 @@ > SUBDIRS = cpuset_base_ops_test cpuset_lib cpuset_inherit_test > SUBDIRS += cpuset_exclusive_test cpuset_hierarchy_test cpuset_syscall_test > +SUBDIRS += cpuset_hotplug_test cpuset_load_balance_test > +SUBDIRS += cpuset_memory_pressure_test cpuset_memory_spread_test > +SUBDIRS += cpuset_memory_test > all: > @set -e; > for i in $(SUBDIRS); do $(MAKE) -C $$i $@ ;done; > diff --git a/testcases/kernel/controllers/cpuset/README b/testcases/kernel/controllers/cpuset/README > index 431d5a0..95f3574 100644 > --- a/testcases/kernel/controllers/cpuset/README > +++ b/testcases/kernel/controllers/cpuset/README > @@ -6,12 +6,10 @@ The directory cpuset contains the tests related to the cpuset controller. > Cpuset is a mechanism for assigning a set of CPUs and Memory Nodes to a set of > tasks. > > -There are total 190 testcases taht have been added till date. Now, These > +There are total 258 testcases that have been added till date. Now, These > testcases contain the basis operation test and part functionality test of > cpuset, such as: adding/removing cpus/mems, setting flags, exclusive function, > -hierarchy realtion, inherit relation and cpuset VS syscall. > - > -More testcases will be added in future. > +hierarchy relation, inherit relation, cpuset VS syscall and so on > > NOTE: the test can be run by root only. And 4 CPUs and 3 Memory Nodes is need > to run it at least. > @@ -42,6 +40,36 @@ cpuset_syscall_test > Directory containing the shell script and program which are used to test > syscalls whether they collide with cpuset. > > +cpuset_hotplug_test > +------------------- > +Directory containing the shell script and program which are used to test > +cpu hotplug whether they collide with cpuset. > + > +cpuset_load_balance_test > +------------------------ > +Directory containing the shell script and program which are used to test > +scheduler domains partitions. Beside that, they are also used to check that > +whether load balance breaks the cpuset's limit. > + > +cpuset_memory_pressure_test > +--------------------------- > +Directory containing the shell script and program which are used to test > +memory pressure measurement function. > + > +cpuset_memory_spread_test > +------------------------- > +Directory containing the shell script and program which are used to test > +page caches spread. There are two control files. One is memory_spread_page which > +is used to control the allocation of page caches, the other is > +memory_spread_slab which is used to control the allocation of slab objects. > +Because there are much factor to affect the result of slab spread test, it > +is hard to test it. So we just test memory_spread_page. > + > +cpuset_memory_test > +------------------ > +Directory containing the shell script and program which are used to test > +memory allocation. > + > cpuset_lib > ---------- > This directory contains the library and script for cpuset controller testing. > diff --git a/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/Makefile b/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/Makefile > new file mode 100644 > index 0000000..24058b4 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/Makefile > @@ -0,0 +1,22 @@ > +CFLAGS += -Wall -g -Wextra > +LDLIBS := -lm > + > +LIBSRCS=$(wildcard ../cpuset_lib/*.c) > +LIBOBJECTS=$(patsubst %.c,%.o,$(LIBSRCS)) > + > +SRCS=$(wildcard *.c) > +OBJECTS=$(patsubst %.c,%.o,$(SRCS)) > +TARGETS=$(patsubst %.c,%,$(SRCS)) > + > +all: $(TARGETS) > + > +$(TARGETS): %: %.o $(LIBOBJECTS) > + > +clean: > + rm -f $(TARGETS) $(OBJECTS) $(LIBOBJECTS) > + > +install: > + @set -e; > + for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i; chmod +x $$i; done > + ln -f cpuset_hotplug_test.sh ../../../../bin/cpuset_hotplug_test.sh; > + chmod +x cpuset_hotplug_test.sh; > diff --git a/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_hotplug_test.sh b/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_hotplug_test.sh > new file mode 100644 > index 0000000..6886874 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_hotplug_test.sh > @@ -0,0 +1,261 @@ > +#!/bin/sh > + > +################################################################################ > +# # > +# Copyright (c) 2009 FUJITSU LIMITED # > +# # > +# This program 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; either version 2 of the License, or # > +# (at your option) any later version. # > +# # > +# This program 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. # > +# # > +# You should have received a copy of the GNU General Public License # > +# along with this program; if not, write to the Free Software # > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # > +# # > +# Author: Miao Xie <mi...@cn...> # > +# # > +################################################################################ > + > +source ./cpuset_funcs.sh > + > +cd $LTPROOT/testcases/bin > + > +export TCID="cpuset08" > +export TST_TOTAL=13 > +export TST_COUNT=1 > + > +exit_status=0 > + > +nr_cpus=$NR_CPUS > +nr_mems=$N_NODES > + > +cpus_all="$(seq -s, 0 $((nr_cpus-1)))" > +cpus_all="`./cpuset_list_compute $cpus_all`" > +mems_all="$(seq -s, 0 $((nr_mems-1)))" > + > +# check_result <result> <expect> > +check_result() > +{ > + local result="$1" > + local expect="$2" > + > + case "$expect" in > + EMPTY) > + test -z "$result" > + return $? > + ;; > + *) > + test "$expect" = "$result" > + return $? > + ;; > + esac > +} > + > +# root_cpu_hotplug_test <cpuhotplug> <expect_cpus> <expect_task_cpus> > +root_cpu_hotplug_test() > +{ > + local cpuhotplug="$1" > + local expect_cpus="$2" > + local expect_task_cpus="$3" > + > + local root_cpus= > + local task_cpus= > + local tst_pid= > + local ret= > + > + setup_test_environment $cpuhotplug 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "setup test environment(offline CPU#$HOTPLUG_CPU) failed" > + return 1 > + fi > + > + /bin/cat /dev/zero &> /dev/null & > + tst_pid=$! > + > + cpu_hotplug $HOTPLUG_CPU $cpuhotplug 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "$cpuoffline CPU#$HOTPLUG_CPU failed." > + return 1 > + fi > + > + root_cpus="`cat $CPUSET/cpus`" > + > + task_cpus="`cat /proc/$tst_pid/status | grep Cpus_allowed_list`" > + task_cpus="`echo $task_cpus | sed -e 's/Cpus_allowed_list: //'`" > + > + check_result "$root_cpus" "$expect_cpus" > + ret=$? > + if [ $ret -eq 0 ] > + then > + check_result "$task_cpus" "$expect_task_cpus" > + ret=$? > + if [ $ret -ne 0 ]; then > + tst_resm TFAIL "task's allowed list isn't expected.(Result: $task_cpus, Expect: $expect_task_cpus)" > + fi > + else > + tst_resm TFAIL "root group's cpus isn't expected(Result: $root_cpus, Expect: $expect_cpus)." > + fi > + > + /bin/kill -9 $tst_pid &> /dev/null > + > + return $ret > +} > + > +# general_cpu_hotplug_test <cpuhotplug> <cpus> <expect_cpus> <expect_task_cpus> > +general_cpu_hotplug_test() > +{ > + local cpuhotplug="$1" > + local cpus="$2" > + local expect_cpus="$3" > + local expect_task_cpus="$4" > + local path="$CPUSET/1" > + > + local tst_pid= > + local task_cpus= > + local ret= > + > + setup_test_environment $cpuhotplug 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "setup test environment(offline CPU#$HOTPLUG_CPU) failed" > + return 1 > + fi > + > + cpuset_set "$path" "$cpus" "$mems_all" "0" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "set general group parameter failed." > + return 1 > + fi > + > + /bin/cat /dev/zero &> /dev/null & > + tst_pid=$! > + > + echo $tst_pid > "$path/tasks" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "attach test tasks to group failed." > + /bin/kill -s SIGKILL $tst_pid > + return 1 > + fi > + > + cpu_hotplug $HOTPLUG_CPU $cpuhotplug 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL ignored "$cpuoffline CPU#$HOTPLUG_CPU failed." > + /bin/kill -s SIGKILL $tst_pid > + return 1 > + fi > + > + cpus="`cat $path/cpus`" > + > + task_cpus="`cat /proc/$tst_pid/status | grep Cpus_allowed_list`" > + task_cpus="`echo $task_cpus | sed -e 's/Cpus_allowed_list: //'`" > + > + if [ "$expect_cpus" == "EMPTY" ]; then > + local tasks=`cat $path/tasks | grep "\b$tst_pid\b"` > + check_result "$tasks" "EMPTY" > + if [ $? -ne 0 ]; then > + tst_resm TFAIL "test task was still in general group, but its cpus is NULL" > + /bin/kill -s SIGKILL $tst_pid > + return 1 > + fi > + > + tasks=`cat $CPUSET/tasks | grep "\b$tst_pid\b"` > + check_result "$tasks" "$tst_pid" > + if [ $? -ne 0 ]; then > + tst_resm TFAIL "test task wasn't moved to parent group" > + /bin/kill -s SIGKILL $tst_pid > + return 1 > + fi > + fi > + > + check_result "$cpus" "$expect_cpus" > + ret=$? > + if [ $ret -eq 0 ]; then > + check_result $task_cpus $expect_task_cpus > + ret=$? > + if [ $ret -ne 0 ]; then > + tst_resm TFAIL "task's cpu allowed list isn't expected(Result: $task_cpus, Expect: $expect_task_cpus)." > + fi > + else > + if [ "$cpus" == "" ]; then > + cpus="EMPTY" > + fi > + tst_resm TFAIL "general group's cpus isn't expected(Result: $cpus, Expect: $expect_cpus)." > + fi > + /bin/kill -s SIGKILL $tst_pid &> /dev/null > + > + return $ret > +} > + > +base_test() > +{ > + setup > + if [ $? -ne 0 ]; then > + exit_status=1 > + else > + "$test_function" "$@" > + if [ $? -ne 0 ]; then > + exit_status=1 > + cleanup > + else > + cleanup > + if [ $? -ne 0 ]; then > + exit_status=1 > + else > + tst_resm TPASS "Cpuset vs CPU hotplug test succeeded." > + fi > + fi > + > + cpu_hotplug_cleanup > + fi > + ((TST_COUNT++)) > +} > + > +# Test Case 1-2 > +test_root_cpu_hotplug() > +{ > + local tmp_cpus="`./cpuset_list_compute -s $cpus_all $HOTPLUG_CPU`" > + > + test_function="root_cpu_hotplug_test" > + while read hotplug cpus_expect task_expect > + do > + base_test "$hotplug" "$cpus_expect" "$task_expect" > + done <<- EOF > + offline $tmp_cpus $cpus_all > + online $cpus_all $cpus_all > + EOF > + # while read hotplug cpus_expect task_expect > +} > + > +# Test Case 3-6 > +test_general_cpu_hotplug() > +{ > + local tmp_cpus="`./cpuset_list_compute -s $cpus_all $HOTPLUG_CPU`" > + > + test_function="general_cpu_hotplug_test" > + while read hotplug cpus cpus_expect task_expect > + do > + base_test "$hotplug" "$cpus" "$cpus_expect" "$task_expect" > + done <<- EOF > + offline 0-1 0 0 > + offline 1 EMPTY $cpus_all > + offline 0 0 0 > + online 0 0 0 > + EOF > + # while read hotplug cpus cpus_expect task_expect > +} > + > +test_root_cpu_hotplug > +test_general_cpu_hotplug > + > +exit $exit_status > diff --git a/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_list_compute.c b/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_list_compute.c > new file mode 100644 > index 0000000..f74d213 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_hotplug_test/cpuset_list_compute.c > @@ -0,0 +1,115 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <signal.h> > +#include <dirent.h> > +#include <sys/types.h> > +#include <pwd.h> > +#include <err.h> > + > +#include "../cpuset_lib/common.h" > +#include "../cpuset_lib/bitmask.h" > + > +#define MAX_STRING_SIZE 400 > +#define MAX_NBITS 1024 > + > +#define USAGE ("Usage : %s [-a|s] list1 [list2]\n" \ > + "\t-a|s list1 add/subtract list2." \ > + "[default: -a]\n" \ > + "\t-h Help.\n") > +int add_or_subtract; > +int convert; > + > +static void usage(char *prog_name, int status) > +{ > + FILE *output = NULL; > + > + if (prog_name == NULL) > + prog_name = "cpu-usage"; > + > + if (status) > + output = stderr; > + else > + output = stdout; > + > + fprintf(output, USAGE, prog_name); > + exit(status); > +} > + > +static void checkopt(int argc, char **argv) > +{ > + char c = '\0'; > + int optc = 0; > + > + while ((c = getopt(argc, argv, "ash")) != -1) { > + switch (c) { > + case 'a': > + add_or_subtract = 0; > + optc++; > + break; > + case 's': > + add_or_subtract = 1; > + optc++; > + break; > + case 'h': /* help */ > + usage(argv[0], 0); > + break; > + default: > + usage(argv[0], 1); > + break; > + } > + } > + > + if (optc == 2) > + OPT_COLLIDING(argv[0], 'a', 's'); > + > + if (argc == optc + 1) { > + fprintf(stderr, "%s: missing the argument list1.\n", > + argv[0]); > + usage(argv[0], 1); > + } else if (argc == optc + 2) > + convert = 1; > +} > + > +int main(int argc, char **argv) > +{ > + struct bitmask *mask1 = NULL, *mask2 = NULL, *mask3 = NULL; > + char buff[MAX_STRING_SIZE]; > + > + checkopt(argc, argv); > + > + mask1 = bitmask_alloc(MAX_NBITS); > + if (mask1 == NULL) > + err(EXIT_FAILURE, "alloc memory space for bitmask1 failed."); > + > + mask2 = bitmask_alloc(MAX_NBITS); > + if (mask2 == NULL) > + err(EXIT_FAILURE, "alloc memory space for bitmask2 failed."); > + > + mask3 = bitmask_alloc(MAX_NBITS); > + if (mask3 == NULL) > + err(EXIT_FAILURE, "alloc memory space for bitmask3 failed."); > + > + if (bitmask_parselist(argv[argc - 2 + convert], mask1) != 0) > + err(EXIT_FAILURE, "parse list1 string failed."); > + > + if (convert) { > + bitmask_displaylist(buff, MAX_STRING_SIZE, mask1); > + printf("%s\n", buff); > + return 0; > + } > + > + if (bitmask_parselist(argv[argc - 1], mask2) != 0) > + err(EXIT_FAILURE, "parse list2 string failed."); > + > + if (add_or_subtract) > + bitmask_andnot(mask3, mask1, mask2); > + else > + bitmask_or(mask3, mask1, mask2); > + > + bitmask_displaylist(buff, MAX_STRING_SIZE, mask3); > + printf("%s\n", buff); > + > + return 0; > +} > diff --git a/testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.c b/testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.c > new file mode 100644 > index 0000000..3fdd323 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.c > @@ -0,0 +1,482 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <sys/types.h> > +#include <dirent.h> > +#include <err.h> > +#include <errno.h> > + > +#include "bitmask.h" > +#include "cpuset.h" > +#include "common.h" > +#include "cpuinfo.h" > + > +#define CPUINFO_FILE "/proc/cpuinfo" > +#define SCHEDSTAT_FILE "/proc/schedstat" > +#define CGROUPINFO_FILE "/proc/cgroups" > +#define SYS_CPU_DIR "/sys/devices/system/cpu" > +#define LIST_PRESENT_CPU_FILE "/sys/devices/system/cpu/present" > +#define LIST_ONLINE_CPU_FILE "/sys/devices/system/cpu/online" > + > +struct cpuinfo *cpus; > +int ncpus; > +int cpus_nbits; > + > +/* get cpu_baseinfo from /proc/cpuinfo */ > +static int get_cpu_baseinfo(void) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + char *istr = NULL, *valstr = NULL, *saveptr = NULL; > + int ci = 0; > + int data = 0; > + > + /* get the number of cpus including offline cpus */ > + if (!ncpus) { > + ncpus = get_ncpus(); > + if (ncpus <= 0) > + return -1; > + } > + > + if (cpus != NULL) { > + free(cpus); > + cpus = NULL; > + } > + > + /* allocate the memory space for cpus */ > + cpus = (struct cpuinfo*)malloc(sizeof(*cpus) * ncpus); > + if (cpus == NULL) > + return -1; > + memset(cpus, 0, sizeof(*cpus) * ncpus); > + > + /* open file /proc/cpuinfo */ > + if ((fp = fopen(CPUINFO_FILE, "r")) == NULL) > + return -1; > + > + /* get cpuinfo */ > + while (fgets(buf, sizeof(buf), fp) != NULL) { > + istr = strtok_r(buf, "\t", &saveptr); > + valstr = index(saveptr, ':'); > + if (valstr == NULL) > + continue; > + valstr++; > + sscanf(valstr, " %d\n", &data); > + if (!strcmp(istr, "processor")) { > + if (data >= ncpus) { > + warnx("Warn: wrong cpu index"); > + fclose(fp); > + return -1; > + } > + ci = data; > + cpus[ci].online = 1; > + } > + } > + > + fclose(fp); > + return 0; > +} > + > +/* > + * get the cpu bitmask of the online processors > + * > + * return value: 0 - success > + * -1 - failed > + */ > +int online_cpumask(struct bitmask *cpumask) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + int i; > + > + if (cpumask == NULL) > + return -1; > + /* > + * open file /sys/devices/system/cpu/online and get online > + * cpulist. > + */ > + if ((fp = fopen(LIST_ONLINE_CPU_FILE, "r")) == NULL) { > + if (get_cpu_baseinfo() != 0) > + return -1; > + for (i = 0; i < ncpus; i++) { > + if (cpus[i].online) > + bitmask_setbit(cpumask, i); > + } > + } else { > + if (fgets(buf, sizeof(buf), fp) == NULL) { > + fclose(fp); > + return -1; > + } > + fclose(fp); > + > + /* parse present cpu list to bitmap */ > + buf[strlen(buf) - 1] = '\0'; > + if (bitmask_parselist(buf, cpumask) != 0) > + return -1; > + } > + > + return 0; > +} > + > +/* > + * get the cpu bitmask of the present processors including offline CPUs > + * > + * return value: 0 - success > + * -1 - failed > + */ > +int present_cpumask(struct bitmask *cpumask) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + char c_relpath[PATH_MAX]; > + int cpu = -1; > + > + if (cpumask == NULL) > + return -1; > + /* > + * open file /sys/devices/system/cpu/present and get present > + * cpulist. > + */ > + if ((fp = fopen(LIST_PRESENT_CPU_FILE, "r")) == NULL) { > + while_each_childdir(SYS_CPU_DIR, "/", c_relpath, > + sizeof(c_relpath)) { > + if (!strncmp(c_relpath + 1, "cpu", 3) > + && sscanf(c_relpath + 4, "%d", &cpu) > 0) { > + if (cpu >= 0) > + bitmask_setbit(cpumask, cpu); > + } > + } end_while_each_childdir > + } else { > + if (fgets(buf, sizeof(buf), fp) == NULL) { > + fclose(fp); > + return -1; > + } > + fclose(fp); > + > + /* parse present cpu list to bitmap */ > + buf[strlen(buf) - 1] = '\0'; > + if (bitmask_parselist(buf, cpumask) != 0) > + return -1; > + } > + > + return 0; > +} > + > +/* > + * get the number of the processors including offline CPUs > + * We get this number from /sys/devices/system/cpu/present. > + * By analyzing the present cpu list, we get the number of all cpus > + */ > +int get_ncpus(void) > +{ > + struct bitmask *bmp = NULL; > + int n = 0; > + > + /* get the bitmask's len */ > + cpus_nbits = cpuset_cpus_nbits(); > + if (cpus_nbits <= 0) > + return -1; > + > + /* allocate the space for bitmask */ > + bmp = bitmask_alloc(cpus_nbits); > + if (bmp == NULL) > + return -1; > + > + if (present_cpumask(bmp)) { > + bitmask_free(bmp); > + return -1; > + } > + > + /* Number of highest set bit +1 is the number of the CPUs */ > + n = bitmask_last(bmp) + 1; > + bitmask_free(bmp); > + > + return n; > +} > + > +/* get the sched domain's info for each cpu */ > +static int get_sched_domains(void) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + char str1[20], str2[BUFFSIZE]; > + int ci = 0; > + > + /* get the bitmask's len */ > + if (!cpus_nbits) { > + cpus_nbits = cpuset_cpus_nbits(); > + if (cpus_nbits <= 0) { > + warnx("get cpus nbits failed."); > + return -1; > + } > + } > + > + /* open file /proc/schedstat */ > + if ((fp = fopen(SCHEDSTAT_FILE, "r")) == NULL) > + return -1; > + > + /* get cpuinfo */ > + while (fgets(buf, sizeof(buf), fp) != NULL) { > + sscanf(buf, "%s %s", str1, str2); > + if (!strncmp(str1, "cpu", 3)) { > + ci = atoi(str1 + 3); > + if (ci < 0 || ci >= ncpus) { > + fprintf(stderr, "Warn: wrong cpu index"); > + fclose(fp); > + return -1; > + } > + } else if (!strncmp(str1, "domain", 6)) { > + if (!cpus[ci].sched_domain) { > + cpus[ci].sched_domain = bitmask_alloc( > + cpus_nbits); > + if (!cpus[ci].sched_domain) > + return -1; > + } > + if (bitmask_parsehex(str2, cpus[ci].sched_domain)) > + return -1; > + } > + } > + > + fclose(fp); > + return 0; > +} > + > +int getcpuinfo(void) > +{ > + int i; > + int node = -1; > + > + /* get the number of cpus including offline cpus */ > + if (!ncpus) { > + ncpus = get_ncpus(); > + if (ncpus <= 0) > + return -1; > + } > + > + if (cpus == NULL) { > + if (get_cpu_baseinfo() != 0) { > + warn("get base infomation of cpus from /proc/cpuinfo " > + "failed."); > + return -1; > + } > + } > + > + /* which node is every cpu belong to? */ > + for (i = 0; i < ncpus; i++) { > + node = cpuset_cpu2node(i); > + if (node == -1) > + warnx("cpu2node failed(cpu = %d)", i); > + cpus[i].nodeid = node; > + } > + > + /* get sched domain's infomation for each cpu */ > + if (get_sched_domains()) { > + warnx("get sched domain's info for each cpu failed."); > + return -1; > + } > + > + return 0; > +} > + > +/* get the number of the cpuset groups */ > +static int get_num_cpusets(void) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + char subsys_name[BUFFSIZE]; > + int num_cgroups = 0; > + int hierarchy; > + int enabled; > + > + /* open file /proc/cgroups and get num cpusets */ > + if ((fp = fopen(CGROUPINFO_FILE, "r")) == NULL) > + return -1; > + > + while (fgets(buf, sizeof(buf), fp) != NULL) { > + if (!strncmp(buf, "cpuset", 6)) { > + sscanf(buf, "%s\t%d\t%d\t%d\n", subsys_name, > + &hierarchy, &num_cgroups, &enabled); > + } > + } > + > + fclose(fp); > + > + return num_cgroups; > +} > + > +static struct cpuset **cpusets; > +static int ncpusets; > + > +static int find_domain_cpusets(char *relpath) > +{ > + struct cpuset *cp = NULL; > + char c_relpath[PATH_MAX]; > + int ret = 0; > + > + if (relpath == NULL) { > + errno = -EFAULT; > + return -1; > + } > + > + cp = cpuset_alloc(); > + if (cp == NULL) { > + errno = -ENOMEM; > + return -1; > + } > + > + if (cpuset_query(cp, relpath)) { > + cpuset_free(cp); > + return -1; > + } > + > + if (cpuset_cpus_weight(cp) == 0) > + return 0; > + > + if (cpuset_cpus_weight(cp) > 0 > + && cpuset_get_iopt(cp, "sched_load_balance") == 1) { > + cpusets[ncpusets] = cp; > + ncpusets++; > + return 0; > + } > + > + while_each_childdir(cpuset_mountpoint(), relpath, c_relpath, > + sizeof(c_relpath)) { > + if ((ret = find_domain_cpusets(c_relpath))) > + break; > + } end_while_each_childdir; > + > + return ret; > +} > + > +struct bitmask **domains; > +int ndomains; > + > +int partition_domains(void) > +{ > + int num_cpusets = 0; > + int i, j; > + struct bitmask *cpusa = NULL, *cpusb = NULL, *cpusc = NULL; > + int *flg = NULL; > + int ret = 0; > + > + num_cpusets = get_num_cpusets(); > + if (num_cpusets == 0) { > + warnx("cpuset subsystem is't compiled into kernel."); > + return -1; > + } > + > + if (!cpus_nbits) { > + cpus_nbits = cpuset_cpus_nbits(); > + if (!cpus_nbits) { > + warnx("nbits of cpus is wrong."); > + return -1; > + } > + } > + > + cpusa = bitmask_alloc(cpus_nbits); > + if (cpusa == NULL) { > + warnx("bitmask_alloc for partition domains failed."); > + return -1; > + } > + > + cpusb = bitmask_alloc(cpus_nbits); > + if (cpusb == NULL) { > + warnx("bitmask_alloc for partition domains failed."); > + ret = -1; > + goto errcpusb; > + } > + > + cpusc = bitmask_alloc(cpus_nbits); > + if (cpusb == NULL) { > + warnx("bitmask_alloc for partition domains failed."); > + ret = -1; > + goto errcpusc; > + } > + > + cpusets = (struct cpuset **)malloc(num_cpusets * sizeof(*cpusets)); > + if (cpusets == NULL) { > + warnx("alloc cpusets space failed."); > + ret = -1; > + goto errcpusets; > + } > + > + if ((ret = find_domain_cpusets("/"))) { > + warnx("find domain cpusets failed."); > + goto errfindcpusets; > + } > + > + flg = (int *)malloc(num_cpusets * sizeof(int)); > + if (flg == NULL) { > + warnx("alloc flg failed."); > + ret = -1; > + goto errfindcpusets; > + } > + memset(flg, 0, num_cpusets * sizeof(int)); > + > + ndomains = ncpusets; > +restart: > + for (i = 0; i < ncpusets; i++) { > + struct cpuset *cpa = cpusets[i]; > + > + if (flg[i]) > + continue; > + > + cpuset_getcpus(cpa, cpusa); > + > + for (j = i + 1; j < ncpusets; j++) { > + struct cpuset *cpb = cpusets[j]; > + > + if (flg[j]) > + continue; > + > + cpuset_getcpus(cpb, cpusb); > + if (bitmask_intersects(cpusa, cpusb)) { > + bitmask_or(cpusc, cpusa, cpusb); > + cpuset_setcpus(cpa, cpusc); > + flg[j] = 1; > + ndomains--; > + goto restart; > + } > + } > + } > + > + domains = (struct bitmask **)malloc(ndomains * sizeof(*domains)); > + if (domains == NULL) { > + warnx("alloc domains space failed."); > + ret = -1; > + goto errdomains; > + } > + > + for (i = 0, j = 0; i < ncpusets; i++) { > + if (flg[i]) > + continue; > + domains[j] = bitmask_alloc(cpus_nbits); > + if (cpuset_getcpus(cpusets[i], domains[j])) { > + warnx("cpuset getcpus failed."); > + ret = -1; > + goto errgetdomains; > + } > + j++; > + } > + goto errdomains; > + > +errgetdomains: > + for (i = 0; i < j; i++) > + bitmask_free(domains[i]); > + free(domains); > + domains = NULL; > +errdomains: > + free(flg); > +errfindcpusets: > + for (i = 0; i < ncpusets; i++) > + cpuset_free(cpusets[i]); > + free(cpusets); > + cpusets = NULL; > + ncpusets = 0; > +errcpusets: > + bitmask_free(cpusc); > +errcpusc: > + bitmask_free(cpusb); > +errcpusb: > + bitmask_free(cpusa); > + return ret; > +} > diff --git a/testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.h b/testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.h > new file mode 100644 > index 0000000..adaf183 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_lib/cpuinfo.h > @@ -0,0 +1,24 @@ > +#ifndef CPUINFO_H > +# define CPUINFO_H > + > +struct cpuinfo { > + int nodeid; /* which node is this CPU on */ > + int online; /* is this CPU online */ > + > + /* sched domains in each sched level of this CPU */ > + struct bitmask *sched_domain; > +}; > + > +extern struct cpuinfo *cpus; > +extern int ncpus; > +extern int cpus_nbits; > +extern struct bitmask **domains; > +extern int ndomains; > + > +extern int online_cpumask(struct bitmask *cpumask); > +extern int present_cpumask(struct bitmask *cpumask); > +extern int get_ncpus(void); > +extern int getcpuinfo(void); > +extern int partition_domains(void); > + > +#endif > diff --git a/testcases/kernel/controllers/cpuset/cpuset_lib/cpuset_funcs.sh b/testcases/kernel/controllers/cpuset/cpuset_lib/cpuset_funcs.sh > index 1221117..e473c27 100755 > --- a/testcases/kernel/controllers/cpuset/cpuset_lib/cpuset_funcs.sh > +++ b/testcases/kernel/controllers/cpuset/cpuset_lib/cpuset_funcs.sh > @@ -36,11 +36,24 @@ N_NODES=${N_NODES#*-*} > CPUSET="/dev/cpuset" > CPUSET_TMP="/tmp/cpuset_tmp" > > +HOTPLUG_CPU="1" > + > cpuset_log() > { > tst_resm TINFO "$*" > } > > +# cpuset_log_error <error_file> > +cpuset_log_error() > +{ > + local error_message= > + > + while read error_message > + do > + cpuset_log "$error_message" > + done < "$1" > +} > + > version_check() > { > tst_kvercmp 2 6 28 > @@ -173,12 +186,80 @@ cleanup() > rm -rf "$CPUSET_TMP" &> /dev/null > } > > -# set_cfiles_value <path> <value> > -set_cfiles_value() > +# set the cpuset's parameter > +# cpuset_set <cpusetpath> <cpus> <mems> <load_balance> > +cpuset_set() > { > - local path=$1 > - local value=$2 > + local path="$1" > + mkdir -p "$path" > + if [ $? -ne 0 ]; then > + return 1 > + fi > + > + local cpus="$2" > + local mems="$3" > + local load_balance="$4" > + > + if [ "$path" != "$CPUSET" ]; then > + if [ "$cpus" != "-" ]; then > + /bin/echo $cpus > $path/cpus > + if [ $? -ne 0 ]; then > + return 1 > + fi > + fi > + > + /bin/echo $mems > $path/mems > + if [ $? -ne 0 ]; then > + return 1 > + fi > + fi > > - echo $value > $path > - return $? > + /bin/echo $load_balance > $path/sched_load_balance > + if [ $? -ne 0 ]; then > + return 1 > + fi > } > + > +# cpu_hotplug cpu_id offline/online > +cpu_hotplug() > +{ > + if [ "$2" == "online" ]; then > + /bin/echo 1 > "/sys/devices/system/cpu/cpu$1/online" > + if [ $? -ne 0 ]; then > + return 1 > + fi > + elif [ "$2" == "offline" ]; then > + /bin/echo 0 > "/sys/devices/system/cpu/cpu$1/online" > + if [ $? -ne 0 ]; then > + return 1 > + fi > + fi > +} > + > +# setup_test_environment <online | offline> > +# online - online a CPU in testing, so we must offline a CPU first > +# offline - offline a CPU in testing, we needn't do anything > +setup_test_environment() > +{ > + if [ "$1" == "online" ]; then > + cpu_hotplug $HOTPLUG_CPU offline > + if [ $? -ne 0 ]; then > + return 1 > + fi > + fi > +} > + > +cpu_hotplug_cleanup() > +{ > + local cpus_array="$(seq -s' ' 1 $((NR_CPUS-1)))" > + local cpuid= > + for cpuid in $cpus_array > + do > + local file="/sys/devices/system/cpu/cpu$cpuid/online" > + local offline="$(cat $file)" > + if [ $offline -eq 0 ]; then > + cpu_hotplug $cpuid "online" > + fi > + done > +} > + > diff --git a/testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.c b/testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.c > new file mode 100644 > index 0000000..fa7762f > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.c > @@ -0,0 +1,122 @@ > +#include <stdio.h> > +#include <string.h> > + > +#include "common.h" > +#include "bitmask.h" > +#include "cpuset.h" > +#include "meminfo.h" > + > +#define LIST_PRESENT_MEM_FILE "/sys/devices/system/node/possible" > +#define LIST_ONLINE_MEM_FILE "/sys/devices/system/node/online" > + > +int nmems; > +int mems_nbits; > + > +/* > + * get the bitmask of the online nodes > + * > + * return value: 0 - success > + * -1 - failed > + */ > +int online_memmask(struct bitmask *memmask) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + > + if (memmask == NULL) > + return -1; > + > + /* > + * open file /sys/devices/system/node/online and get online > + * nodelist > + */ > + if ((fp = fopen(LIST_ONLINE_MEM_FILE, "r")) == NULL) > + return -1; > + > + if (fgets(buf, sizeof(buf), fp) == NULL) { > + fclose(fp); > + return -1; > + } > + > + fclose(fp); > + > + /* parse present nodelist to bitmap */ > + buf[strlen(buf) - 1] = '\0'; > + if (bitmask_parselist(buf, memmask) != 0) > + return -1; > + > + return 0; > +} > + > +/* > + * get the bitmask of the present nodes including offline nodes > + * > + * return value: 0 - success > + * -1 - failed > + */ > +int present_memmask(struct bitmask *memmask) > +{ > + FILE *fp = NULL; > + char buf[BUFFSIZE]; > + > + if (memmask == NULL) > + return -1; > + > + /* > + * open file /sys/devices/system/node/possible and get present > + * nodelist > + */ > + if ((fp = fopen(LIST_PRESENT_MEM_FILE, "r")) == NULL) > + return -1; > + > + if (fgets(buf, sizeof(buf), fp) == NULL) { > + fclose(fp); > + return -1; > + } > + > + fclose(fp); > + > + /* parse present nodelist to bitmap */ > + buf[strlen(buf) - 1] = '\0'; > + if (bitmask_parselist(buf, memmask) != 0) > + return -1; > + > + return 0; > +} > + > +/* > + * get the number of the nodes including offline nodes > + */ > +int get_nmems(void) > +{ > + struct bitmask *bmp = NULL; > + int n = 0; > + > + /* get the bitmask's len */ > + if (mems_nbits <= 0) { > + mems_nbits = cpuset_mems_nbits(); > + if (mems_nbits <= 0) > + return -1; > + } > + > + /* allocate the space for bitmask */ > + bmp = bitmask_alloc(mems_nbits); > + if (bmp == NULL) > + return -1; > + > + if (present_memmask(bmp)) { > + bitmask_free(bmp); > + return -1; > + } > + > + /* Numbwe of highest set bit +1 is the number of the nodes */ > + if (bitmask_weight(bmp) <= 0) { > + bitmask_free(bmp); > + return -1; > + } > + > + n = bitmask_last(bmp) + 1; > + bitmask_free(bmp); > + > + return n; > +} > diff --git a/testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.h b/testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.h > new file mode 100644 > index 0000000..0e8d8d8 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_lib/meminfo.h > @@ -0,0 +1,11 @@ > +#ifndef MEMINFO_H > +# define MEMINFO_H > + > +extern int nmems; > +extern int mems_nbits; > + > +extern int online_memmask(struct bitmask *memmask); > +extern int present_memmask(struct bitmask *memmask); > +extern int get_nmems(void); > + > +#endif > diff --git a/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/Makefile b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/Makefile > new file mode 100644 > index 0000000..4aaeeb9 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/Makefile > @@ -0,0 +1,24 @@ > +CFLAGS += -Wall -g -Wextra > +LDLIBS := -lm > + > +LIBSRCS=$(wildcard ../cpuset_lib/*.c) > +LIBOBJECTS=$(patsubst %.c,%.o,$(LIBSRCS)) > + > +SRCS=$(wildcard *.c) > +OBJECTS=$(patsubst %.c,%.o,$(SRCS)) > +TARGETS=$(patsubst %.c,%,$(SRCS)) > + > +all: $(TARGETS) > + > +$(TARGETS): %: %.o $(LIBOBJECTS) > + > +clean: > + rm -f $(TARGETS) $(OBJECTS) $(LIBOBJECTS) > + > +install: > + @set -e; > + for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i; chmod +x $$i; done > + ln -f cpuset_load_balance_test.sh ../../../../bin/cpuset_load_balance_test.sh; > + ln -f cpuset_sched_domains_test.sh ../../../../bin/cpuset_sched_domains_test.sh; > + chmod +x cpuset_load_balance_test.sh; > + chmod +x cpuset_sched_domains_test.sh; > diff --git a/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_cpu_hog.c b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_cpu_hog.c > new file mode 100644 > index 0000000..29d9997 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_cpu_hog.c > @@ -0,0 +1,316 @@ > +/******************************************************************************/ > +/* */ > +/* Copyright (c) 2009 FUJITSU LIMITED */ > +/* */ > +/* This program 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; either version 2 of the License, or */ > +/* (at your option) any later version. */ > +/* */ > +/* This program 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. */ > +/* */ > +/* You should have received a copy of the GNU General Public License */ > +/* along with this program; if not, write to the Free Software */ > +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ > +/* */ > +/* Author: Miao Xie <mi...@cn...> */ > +/* */ > +/******************************************************************************/ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <ctype.h> > +#include <math.h> > +#include <err.h> > +#include <errno.h> > +#include <signal.h> > +#include <sys/types.h> > +#include <sys/wait.h> > +#include <sys/stat.h> > +#include <fcntl.h> > + > +#include "../cpuset_lib/common.h" > +#include "../cpuset_lib/bitmask.h" > +#include "../cpuset_lib/cpuset.h" > + > +#define MAX_NPROCS 1000 > +#define USAGE ("Usage: %s [-p nprocs] [-h]\n" \ > + "\t-p nprocs\n" \ > + "\t\tThe num of the procs. [Default = 2 * nr_cpus]\n" \ > + "\t-h\tHelp.\n") > + > +unsigned long count; > +int nprocs; > +volatile int end; > + > +/* > + * report executing result to the parent by fifo > + * "0\n" - everything is OK > + * "1\n" - everything is OK, but break the test > + * "2\n" - something failed > + */ > +int report_result(char str[]) > +{ > + int fd; > + > + fd = open("./myfifo", O_WRONLY); > + if (fd == -1) { > + warn("open fifo failed"); > + return -1; > + } > + > + if (write(fd, str, strlen(str)) == -1) { > + warn("write fifo failed."); > + close(fd); > + return -1; > + } > + > + close(fd); > + return 0; > +} > + > +void sighandler1(UNUSED int signo) > +{ > +} > + > +void sighandler2(UNUSED int signo) > +{ > + end = 1; > +} > + > +void usage(char *prog_name, int status) > +{ > + FILE *output = NULL; > + > + if (prog_name == NULL) > + prog_name = "cpu-hog"; > + > + if (status) > + output = stderr; > + else > + output = stdout; > + > + fprintf(output, USAGE, prog_name); > + > + if (status) > + report_result("2\n"); > + else > + report_result("1\n"); > + > + exit(status); > +} > + > +void checkopt(int argc, char **argv) > +{ > + char c = '\0'; > + char *endptr = NULL; > + long nr_cpus = 0; > + long opt_value = 0; > + > + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); > + if (nr_cpus <= 0) { > + fprintf(stderr, "Error: sysconf failed\n"); > + report_result("2\n"); > + exit(1); > + } > + > + while ((c = getopt(argc, argv, "p:h")) != -1) { > + switch (c) { > + case 'p': > + if (optarg[0] == '-' && !isdigit(optarg[1])) > + OPT_MISSING(argv[0], c); > + else { > + opt_value = strtol(optarg, &endptr, DECIMAL); > + if (errno || (endptr != NULL && *endptr != '\0') > + || opt_value <= 0 || opt_value > MAX_NPROCS) > + ARG_WRONG(argv[0], c, optarg); > + nprocs = atoi(optarg); > + } > + break; > + case 'h': /* usage message */ > + usage(argv[0], 0); > + break; > + default: > + usage(argv[0], 1); > + break; > + } > + } > + > + if (nprocs == 0) > + nprocs = 2 * nr_cpus; > +} > + > +/* > + * hog the cpu time and check the cpu which the task is running on is in the > + * cpus of the cpuset or not. > + * > + * return value: 0 - success. > + * 1 - the cpu which the task is running on isn't in the cpus > + * of the cpuset. > + * -1 - failure for other reason. > + */ > +int cpu_hog(void) > +{ > + double f = 2744545.34456455; > + sigset_t sigset; > + struct cpuset *cp = NULL; > + struct bitmask *cpumask = NULL; > + int cpu; > + int nbits; > + int ret = 0; > + > + nbits = cpuset_cpus_nbits(); > + > + cp = cpuset_alloc(); > + if (cp == NULL) > + return -1; > + > + cpumask = bitmask_alloc(nbits); > + if (cpumask == NULL) { > + ret = -1; > + goto err1; > + } > + > + if (sigemptyset(&sigset) < 0) { > + ret = -1; > + goto err2; > + } > + > + sigsuspend(&sigset); > + > + if (cpuset_cpusetofpid(cp, 0) < 0) { > + ret = -1; > + goto err2; > + } > + if (cpuset_getcpus(cp, cpumask) != 0) { > + ret = -1; > + goto err2; > + } > + > + while (!end) { > + f = sqrt(f * f); > + cpu = cpuset_latestcpu(0); > + if (cpu < 0) { > + warn("get latest cpu failed.\n"); > + ret = -1; > + goto err2; > + } > + if (!bitmask_isbitset(cpumask, cpu)) { > + char str[50]; > + bitmask_displaylist(str, 50, cpumask); > + warn("the task(%d) is running on the cpu(%d) excluded" > + " by cpuset(cpus: %s)\n", getpid(), cpu, str); > + ret = 1; > + goto err2; > + } > + } > + > +err2: > + bitmask_free(cpumask); > +err1: > + cpuset_free(cp); > + return ret; > +} > + > +int initialize(void) > +{ > + struct sigaction sa1, sa2; > + > + sa1.sa_handler = sighandler1; > + if (sigemptyset(&sa1.sa_mask) < 0) > + return -1; > + > + sa1.sa_flags = 0; > + if (sigaction(SIGUSR1, &sa1, NULL) < 0) > + return -1; > + > + sa2.sa_handler = sighandler2; > + if (sigemptyset(&sa2.sa_mask) < 0) > + return -1; > + > + sa2.sa_flags = 0; > + if (sigaction(SIGUSR2, &sa2, NULL) < 0) > + return -1; > + > + return 0; > +} > + > +int main(int argc, char **argv) > +{ > + int i = 0; > + pid_t pid; > + pid_t *childpids = NULL; > + sigset_t sigset; > + int status = 0; > + int ret = 0; > + > + checkopt(argc,argv); > + if (initialize()) { > + warn("initialize failed"); > + report_result("2\n"); > + exit(EXIT_FAILURE); > + } > + > + if (sigemptyset(&sigset) < 0) { > + warn("sigemptyset failed"); > + report_result("2\n"); > + exit(EXIT_FAILURE); > + } > + > + childpids = (pid_t *)malloc((nprocs) * sizeof(pid_t)); > + if (childpids == NULL) { > + warn("alloc for child pids failed"); > + report_result("2\n"); > + exit(EXIT_FAILURE); > + } > + memset(childpids, 0, (nprocs) * sizeof(pid_t)); > + > + report_result("0\n"); > + sigsuspend(&sigset); > + for (; i < nprocs; i++) { > + pid = fork(); > + if (pid == -1) { > + while (--i >= 0) > + kill(childpids[i], SIGKILL); > + warn("fork test tasks failed"); > + report_result("2\n"); > + exit(EXIT_FAILURE); > + } else if (!pid) { > + ret = cpu_hog(); > + exit(ret); > + } > + childpids[i] = pid; > + } > + > + report_result("0\n"); > + > + while (!end) { > + if (sigemptyset(&sigset) < 0) > + ret = -1; > + else > + sigsuspend(&sigset); > + > + if (ret || end) { > + for(i = 0; i < nprocs; i++) { > + kill(childpids[i], SIGUSR2); > + } > + break; > + } else { > + for(i = 0; i < nprocs; i++) { > + kill(childpids[i], SIGUSR1); > + } > + } > + } > + for (i = 0; i < nprocs; i++) { > + wait(&status); > + if (status) > + ret = EXIT_FAILURE; > + } > + > + return ret; > +} > + > diff --git a/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_load_balance_test.sh b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_load_balance_test.sh > new file mode 100644 > index 0000000..06ce676 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_load_balance_test.sh > @@ -0,0 +1,367 @@ > +#!/bin/sh > + > +################################################################################ > +# # > +# Copyright (c) 2009 FUJITSU LIMITED # > +# # > +# This program 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; either version 2 of the License, or # > +# (at your option) any later version. # > +# # > +# This program 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. # > +# # > +# You should have received a copy of the GNU General Public License # > +# along with this program; if not, write to the Free Software # > +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # > +# # > +# Author: Miao Xie <mi...@cn...> # > +# # > +################################################################################ > + > +source ./cpuset_funcs.sh > + > +cd $LTPROOT/testcases/bin > + > +export TCID="cpuset07" > +export TST_TOTAL=13 > +export TST_COUNT=1 > + > +exit_status=0 > + > +# must >= 3 for: 1-$((nr_mems-2)) > +nr_cpus=4 > +nr_mems=3 > + > +cpus_all="$(seq -s, 0 $((nr_cpus-1)))" > +mems_all="$(seq -s, 0 $((nr_mems-1)))" > + > +runtime=30 > + > +#cpuset_set_opt <path> <cfile> <value> > +cpuset_set_opt() > +{ > + local path=$1 > + local cfile=$2 > + local value=$3 > + > + /bin/echo $value > $path/$cfile > + return $? > +} > + > +# general_load_balance_test1 <g_cpus> <g_balance> <r_balance> > +general_load_balance_test1() > +{ > + local g_cpus="$1" > + local g_balance="$2" > + local r_balance="$3" > + local g_path="$CPUSET/1" > + > + local fifo= > + local ret= > + > + cpuset_log "general group load balance test" > + cpuset_log "root group info:" > + cpuset_log " sched load balance:" $r_balance > + cpuset_log "general group info:" > + cpuset_log " cpus:" $g_cpus > + cpuset_log " sched load balance:" $g_balance > + > + cpuset_set "$CPUSET" "-" "$mems_all" "$r_balance" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "set root group parameter failed." > + return 1 > + fi > + > + cpuset_set "$g_path" "$g_cpus" "$mems_all" "$g_balance" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "set general group parameter failed." > + return 1 > + fi > + > + ./cpuset_cpu_hog 2> $CPUSET_TMP/cpu-hog_stderr & > + pid=$! > + > + read fifo < ./myfifo > + if [ $fifo -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "There is something wrong with test tasks" > + return 1 > + fi > + > + if [ "$g_cpus" != "-" ]; then > + cpuset_set_opt "$g_path" "tasks" "$pid" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "attach test tasks to group "\ > + "failed." > + /bin/kill -s SIGKILL $pid > + return 1 > + fi > + fi > + > + # start to fork the child processes > + /bin/kill -s SIGUSR1 $pid 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "send the signal to fork the child tasks " \ > + "failed." > + /bin/kill -s SIGKILL $pid > + return 1 > + fi > + > + read fifo < ./myfifo > + if [ $fifo -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/cpu-hog_stderr > + tst_resm TFAIL "forking test tasks failed" > + return 1 > + fi > + > + # start to run the child processes > + /bin/kill -s SIGUSR1 $pid 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "send the signal to run the child tasks " \ > + "failed." > + /bin/kill -s SIGUSR2 $pid > + return 1 > + fi > + > + sleep $runtime > + /bin/kill -s SIGUSR2 $pid 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "send the signal to stop the child tasks " \ > + "failed." > + return 1 > + fi > + > + wait $pid > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/cpu-hog_stderr > + tst_resm TFAIL "load balance test failed." > + return 1 > + fi > + > + tst_resm TPASS "load balance test succeeded." > +} > + > +# general_load_balance_test2 <g1_cpus> <g1_balance> > +# <g2_cpus> <g2_balance> > +# <cpuoffline> > +general_load_balance_test2() > +{ > + local g1_cpus=$1 > + local g1_balance=$2 > + local g1_path="$CPUSET/1" > + > + local g2_cpus=$3 > + local g2_balance=$4 > + local g2_path="$CPUSET/2" > + > + local cpuoffline=$5 > + > + local pid= > + local ret= > + > + cpuset_log "general group load balance test" > + cpuset_log "root group info:" > + cpuset_log " sched load balance:" 0 > + cpuset_log "general group1 info:" > + cpuset_log " cpus:" $g1_cpus > + cpuset_log " sched load balance:" $g1_balance > + cpuset_log "general group2 info:" > + cpuset_log " cpus:" $g2_cpus > + cpuset_log " sched load balance:" $g2_balance > + cpuset_log "CPU hotplug:" $cpuoffline > + > + cpuset_set "$CPUSET" "-" "$mems_all" "0" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "set root group parameter failed." > + return 1 > + fi > + > + cpuset_set "$g1_path" "$g1_cpus" "$mems_all" "$g1_balance" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "set general group1 parameter failed." > + return 1 > + fi > + > + cpuset_set "$g2_path" "$g2_cpus" "$mems_all" "$g2_balance" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "set general group2 parameter failed." > + return 1 > + fi > + > + # setup test environment > + setup_test_environment $cpuoffline 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "setup test environment(offline CPU#$HOTPLUG_CPU) failed" > + return 1 > + fi > + > + ./cpuset_cpu_hog 2> $CPUSET_TMP/cpu-hog_stderr & > + pid=$! > + > + # wait for the parent to do prepare > + read fifo < ./myfifo > + if [ $fifo -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "There is something wrong with test tasks" > + return 1 > + fi > + > + if [ "$g1_cpus" != "-" ]; then > + cpuset_set_opt "$g1_path" "tasks" "$pid" 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "attach test tasks to group "\ > + "failed." > + /bin/kill -s SIGKILL $pid > + return 1 > + fi > + fi > + > + # start to fork the child processes > + /bin/kill -s SIGUSR1 $pid 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "send the signal to fork the child tasks " \ > + "failed." > + /bin/kill -s SIGKILL $pid > + return 1 > + fi > + > + # wait for the end of forking > + read fifo < ./myfifo > + if [ $fifo -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/cpu-hog_stderr > + tst_resm TFAIL "forking test tasks failed" > + return 1 > + fi > + > + sleep 1 > + cpu_hotplug $HOTPLUG_CPU $cpuoffline 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "$cpuoffline CPU#$HOTPLUG_CPU failed." > + /bin/kill -s SIGUSR2 $pid > + wait $pid > + return 1 > + fi > + > + # start to run the child processes > + /bin/kill -s SIGUSR1 $pid 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "send the signal to run the child tasks " \ > + "failed." > + /bin/kill -s SIGUSR2 $pid > + wait $pid > + return 1 > + fi > + > + sleep $runtime > + /bin/kill -s SIGUSR2 $pid 2> $CPUSET_TMP/stderr > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/stderr > + tst_resm TFAIL "send the signal to stop the child tasks " \ > + "failed." > + return 1 > + fi > + > + wait $pid > + if [ $? -ne 0 ]; then > + cpuset_log_error $CPUSET_TMP/cpu-hog_stderr > + tst_resm TFAIL "load balance test failed." > + return 1 > + fi > + > + tst_resm TPASS "load balance test succeeded." > +} > + > +base_test() > +{ > + setup > + if [ $? -ne 0 ]; then > + exit_status=1 > + else > + $test_pro "$@" > + if [ $? -ne 0 ]; then > + exit_status=1 > + fi > + > + cleanup > + if [ $? -ne 0 ]; then > + exit_status=1 > + fi > + > + cpu_hotplug_cleanup > + fi > + ((TST_COUNT++)) > +} > + > +test_general_load_balance1() > +{ > + test_pro="general_load_balance_test1" > + > + local g_cpus= > + local g_isbalance= > + local r_isbalance= > + > + while read g_cpus g_isbalance r_isbalance > + do > + base_test $g_cpus $g_isbalance $r_isbalance > + done <<- EOF > + - 1 0 > + 1 0 0 > + - 1 1 > + 1 1 1 > + 1,2 0 0 > + 1,2 1 0 > + $cpus_all 1 0 > + EOF > + # while read g_cpus g_isbalance r_isbalance > +} > + > +test_general_load_balance2() > +{ > + test_pro="general_load_balance_test2" > + > + local g1_cpus= > + local g1_isbalance= > + > + local g2_cpus= > + local g2_isbalance= > + > + local hotplug= > + > + while read g1_cpus g1_isbalance g2_cpus g2_isbalance hotplug > + do > + base_test $g1_cpus $g1_isbalance $g2_cpus $g2_isbalance $hotplug > + done <<- EOF > + 1 1 0 1 none > + 1,2 1 0-3 0 none > + 1,2 1 0,3 1 none > + 1,2 1 1,3 1 none > + 1,2 1 1,3 1 offline > + 1,2 1 1,3 1 online > + EOF > + # while read g1_cpus g1_isbalance g2_cpus g2_isbalance hotplug > +} > + > +mkfifo myfifo > +test_general_load_balance1 > +test_general_load_balance2 > +rm -f myfifo > + > +exit $exit_status > diff --git a/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_sched_domains_check.c b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_sched_domains_check.c > new file mode 100644 > index 0000000..a514d61 > --- /dev/null > +++ b/testcases/kernel/controllers/cpuset/cpuset_load_balance_test/cpuset_sched_domains_check.c > @@ -0,0 +1,135 @@ > +/******************************************************************************/ > +/* */ > +/* Copyright (c) 2009 FUJITSU LIMITED */ > +/* */ > +/* This program 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; either version 2 of the License, or */ > +/* (at your option) any later version. */ > +/* */ > +/* This program 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. */ > +/* */ > +/* You should have received a copy of the GNU General Public License */ > +/* along with this program; if not, write to the Free Software */ > +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ > +/* */ > +/* Author: Miao Xie <mi...@cn...> */ > +/* ... [truncated message content] |