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
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 */
report_result(char str[])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
sighandler1(UNUSED int signo)81 void sighandler1(UNUSED int signo)
82 {
83 }
84
sighandler2(UNUSED int signo)85 void sighandler2(UNUSED int signo)
86 {
87 end = 1;
88 }
89
usage(char * prog_name,int status)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
checkopt(int argc,char ** argv)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 */
cpu_hog(void)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
initialize(void)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
main(int argc,char ** argv)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 */
main(void)324 int main(void)
325 {
326 printf("System doesn't have required mempolicy support\n");
327 return 1;
328 }
329 #endif
330