blob: fa59a7b06f6521103620517a660bd27b1ca411cd [file] [log] [blame]
/******************************************************************************/
/* */
/* 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 <miaox@cn.fujitsu.com> */
/* */
/******************************************************************************/
#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"
#if HAVE_LINUX_MEMPOLICY_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")
char *TCID = "cpuset_cpu_hog";
int TST_TOTAL = 1;
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;
}
#else /* ! HAVE_LINUX_MEMPOLICY_H */
int main(void) {
printf("System doesn't have required mempolicy support\n");
return 1;
}
#endif