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