Home | History | Annotate | Download | only in cpuset_load_balance_test
      1 /******************************************************************************/
      2 /*                                                                            */
      3 /* Copyright (c) 2009 FUJITSU LIMITED                                         */
      4 /*                                                                            */
      5 /* This program is free software;  you can redistribute it and/or modify      */
      6 /* it under the terms of the GNU General Public License as published by       */
      7 /* the Free Software Foundation; either version 2 of the License, or          */
      8 /* (at your option) any later version.                                        */
      9 /*                                                                            */
     10 /* This program is distributed in the hope that it will be useful,            */
     11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
     12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
     13 /* the GNU General Public License for more details.                           */
     14 /*                                                                            */
     15 /* You should have received a copy of the GNU General Public License          */
     16 /* along with this program;  if not, write to the Free Software               */
     17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
     18 /*                                                                            */
     19 /* Author: Miao Xie <miaox (at) cn.fujitsu.com>                                    */
     20 /*                                                                            */
     21 /******************************************************************************/
     22 
     23 #include "config.h"
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <ctype.h>
     28 #include <math.h>
     29 #include <err.h>
     30 #include <errno.h>
     31 #include <signal.h>
     32 #include <sys/types.h>
     33 #include <sys/wait.h>
     34 #include <sys/stat.h>
     35 #include <fcntl.h>
     36 
     37 char *TCID = "cpuset_cpu_hog";
     38 int TST_TOTAL = 1;
     39 
     40 #if HAVE_LINUX_MEMPOLICY_H
     41 
     42 #include "../cpuset_lib/common.h"
     43 #include "../cpuset_lib/bitmask.h"
     44 #include "../cpuset_lib/cpuset.h"
     45 
     46 #define MAX_NPROCS	1000
     47 #define USAGE	("Usage: %s [-p nprocs] [-h]\n"		\
     48 		 "\t-p nprocs\n"					\
     49 		 "\t\tThe num of the procs. [Default = 2 * nr_cpus]\n"	\
     50 		 "\t-h\tHelp.\n")
     51 
     52 static int nprocs;
     53 static volatile int end;
     54 
     55 /*
     56  * report executing result to the parent by fifo
     57  *     "0\n" - everything is OK
     58  *     "1\n" - everything is OK, but break the test
     59  *     "2\n" - something failed
     60  */
     61 int report_result(char str[])
     62 {
     63 	int fd;
     64 
     65 	fd = open("./myfifo", O_WRONLY);
     66 	if (fd == -1) {
     67 		warn("open fifo failed");
     68 		return -1;
     69 	}
     70 
     71 	if (write(fd, str, strlen(str)) == -1) {
     72 		warn("write fifo failed.");
     73 		close(fd);
     74 		return -1;
     75 	}
     76 
     77 	close(fd);
     78 	return 0;
     79 }
     80 
     81 void sighandler1(UNUSED int signo)
     82 {
     83 }
     84 
     85 void sighandler2(UNUSED int signo)
     86 {
     87 	end = 1;
     88 }
     89 
     90 void usage(char *prog_name, int status)
     91 {
     92 	FILE *output = NULL;
     93 
     94 	if (prog_name == NULL)
     95 		prog_name = "cpu-hog";
     96 
     97 	if (status)
     98 		output = stderr;
     99 	else
    100 		output = stdout;
    101 
    102 	fprintf(output, USAGE, prog_name);
    103 
    104 	if (status)
    105 		report_result("2\n");
    106 	else
    107 		report_result("1\n");
    108 
    109 	exit(status);
    110 }
    111 
    112 void checkopt(int argc, char **argv)
    113 {
    114 	char c = '\0';
    115 	char *endptr = NULL;
    116 	long nr_cpus = 0;
    117 	long opt_value = 0;
    118 
    119 	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
    120 	if (nr_cpus <= 0) {
    121 		fprintf(stderr, "Error: sysconf failed\n");
    122 		report_result("2\n");
    123 		exit(1);
    124 	}
    125 
    126 	while ((c = getopt(argc, argv, "p:h")) != -1) {
    127 		switch (c) {
    128 		case 'p':
    129 			if (optarg[0] == '-' && !isdigit(optarg[1]))
    130 				OPT_MISSING(argv[0], c);
    131 			else {
    132 				opt_value = strtol(optarg, &endptr, DECIMAL);
    133 				if (errno || (endptr != NULL && *endptr != '\0')
    134 				    || opt_value <= 0 || opt_value > MAX_NPROCS)
    135 					ARG_WRONG(argv[0], c, optarg);
    136 				nprocs = atoi(optarg);
    137 			}
    138 			break;
    139 		case 'h':	/* usage message */
    140 			usage(argv[0], 0);
    141 			break;
    142 		default:
    143 			usage(argv[0], 1);
    144 			break;
    145 		}
    146 	}
    147 
    148 	if (nprocs == 0)
    149 		nprocs = 2 * nr_cpus;
    150 }
    151 
    152 /*
    153  * hog the cpu time and check the cpu which the task is running on is in the
    154  * cpus of the cpuset or not.
    155  *
    156  * return value: 0  - success.
    157  *               1  - the cpu which the task is running on isn't in the cpus
    158  *                    of the cpuset.
    159  *               -1 - failure for other reason.
    160  */
    161 int cpu_hog(void)
    162 {
    163 	double f = 2744545.34456455;
    164 	sigset_t signalset;
    165 	struct cpuset *cp = NULL;
    166 	struct bitmask *cpumask = NULL;
    167 	int cpu;
    168 	int nbits;
    169 	int ret = 0;
    170 
    171 	nbits = cpuset_cpus_nbits();
    172 
    173 	cp = cpuset_alloc();
    174 	if (cp == NULL)
    175 		return -1;
    176 
    177 	cpumask = bitmask_alloc(nbits);
    178 	if (cpumask == NULL) {
    179 		ret = -1;
    180 		goto err1;
    181 	}
    182 
    183 	if (sigemptyset(&signalset) < 0) {
    184 		ret = -1;
    185 		goto err2;
    186 	}
    187 
    188 	sigsuspend(&signalset);
    189 
    190 	if (cpuset_cpusetofpid(cp, 0) < 0) {
    191 		ret = -1;
    192 		goto err2;
    193 	}
    194 	if (cpuset_getcpus(cp, cpumask) != 0) {
    195 		ret = -1;
    196 		goto err2;
    197 	}
    198 
    199 	while (!end) {
    200 		f = sqrt(f * f);
    201 		cpu = cpuset_latestcpu(0);
    202 		if (cpu < 0) {
    203 			warn("get latest cpu failed.\n");
    204 			ret = -1;
    205 			goto err2;
    206 		}
    207 		if (!bitmask_isbitset(cpumask, cpu)) {
    208 			char str[50];
    209 			bitmask_displaylist(str, 50, cpumask);
    210 			warn("the task(%d) is running on the cpu(%d) excluded"
    211 			     " by cpuset(cpus: %s)\n", getpid(), cpu, str);
    212 			ret = 1;
    213 			goto err2;
    214 		}
    215 	}
    216 
    217 err2:
    218 	bitmask_free(cpumask);
    219 err1:
    220 	cpuset_free(cp);
    221 	return ret;
    222 }
    223 
    224 int initialize(void)
    225 {
    226 	struct sigaction sa1, sa2;
    227 
    228 	sa1.sa_handler = sighandler1;
    229 	if (sigemptyset(&sa1.sa_mask) < 0)
    230 		return -1;
    231 
    232 	sa1.sa_flags = 0;
    233 	if (sigaction(SIGUSR1, &sa1, NULL) < 0)
    234 		return -1;
    235 
    236 	sa2.sa_handler = sighandler2;
    237 	if (sigemptyset(&sa2.sa_mask) < 0)
    238 		return -1;
    239 
    240 	sa2.sa_flags = 0;
    241 	if (sigaction(SIGUSR2, &sa2, NULL) < 0)
    242 		return -1;
    243 
    244 	return 0;
    245 }
    246 
    247 int main(int argc, char **argv)
    248 {
    249 	int i = 0;
    250 	pid_t pid;
    251 	pid_t *childpids = NULL;
    252 	sigset_t signalset;
    253 	int status = 0;
    254 	int ret = 0;
    255 
    256 	checkopt(argc, argv);
    257 	if (initialize()) {
    258 		warn("initialize failed");
    259 		report_result("2\n");
    260 		exit(EXIT_FAILURE);
    261 	}
    262 
    263 	if (sigemptyset(&signalset) < 0) {
    264 		warn("sigemptyset failed");
    265 		report_result("2\n");
    266 		exit(EXIT_FAILURE);
    267 	}
    268 
    269 	childpids = malloc((nprocs) * sizeof(pid_t));
    270 	if (childpids == NULL) {
    271 		warn("alloc for child pids failed");
    272 		report_result("2\n");
    273 		exit(EXIT_FAILURE);
    274 	}
    275 	memset(childpids, 0, (nprocs) * sizeof(pid_t));
    276 
    277 	report_result("0\n");
    278 	sigsuspend(&signalset);
    279 	for (; i < nprocs; i++) {
    280 		pid = fork();
    281 		if (pid == -1) {
    282 			while (--i >= 0)
    283 				kill(childpids[i], SIGKILL);
    284 			warn("fork test tasks failed");
    285 			report_result("2\n");
    286 			exit(EXIT_FAILURE);
    287 		} else if (!pid) {
    288 			ret = cpu_hog();
    289 			exit(ret);
    290 		}
    291 		childpids[i] = pid;
    292 	}
    293 
    294 	report_result("0\n");
    295 
    296 	while (!end) {
    297 		if (sigemptyset(&signalset) < 0)
    298 			ret = -1;
    299 		else
    300 			sigsuspend(&signalset);
    301 
    302 		if (ret || end) {
    303 			for (i = 0; i < nprocs; i++) {
    304 				kill(childpids[i], SIGUSR2);
    305 			}
    306 			break;
    307 		} else {
    308 			for (i = 0; i < nprocs; i++) {
    309 				kill(childpids[i], SIGUSR1);
    310 			}
    311 		}
    312 	}
    313 	for (i = 0; i < nprocs; i++) {
    314 		wait(&status);
    315 		if (status)
    316 			ret = EXIT_FAILURE;
    317 	}
    318 
    319 	free(childpids);
    320 	return ret;
    321 }
    322 
    323 #else /* ! HAVE_LINUX_MEMPOLICY_H */
    324 int main(void)
    325 {
    326 	printf("System doesn't have required mempolicy support\n");
    327 	return 1;
    328 }
    329 #endif
    330