cpuset_cpu_hog.c revision 0aaaf37500ec21d4e673c8f36f9934346269ac21
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@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
37char *TCID = "cpuset_cpu_hog";
38int 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
52static int nprocs;
53static 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 */
61int 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
81void sighandler1(UNUSED int signo)
82{
83}
84
85void sighandler2(UNUSED int signo)
86{
87	end = 1;
88}
89
90void 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
112void 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 */
161int cpu_hog(void)
162{
163	double f = 2744545.34456455;
164	sigset_t sigset;
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(&sigset) < 0) {
184		ret = -1;
185		goto err2;
186	}
187
188	sigsuspend(&sigset);
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
217err2:
218	bitmask_free(cpumask);
219err1:
220	cpuset_free(cp);
221	return ret;
222}
223
224int 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
247int main(int argc, char **argv)
248{
249	int i = 0;
250	pid_t pid;
251	pid_t *childpids = NULL;
252	sigset_t sigset;
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(&sigset) < 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(&sigset);
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(&sigset) < 0)
298			ret = -1;
299		else
300			sigsuspend(&sigset);
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 */
324int main(void)
325{
326	printf("System doesn't have required mempolicy support\n");
327	return 1;
328}
329#endif
330