Subrata Modak wrote:

It would be great if you can do this. I need this to be compiled fine
with gcc alone.

The attached version will compile with:

gcc --std=c99 fairtest.c -o fairtest -lm

It would certainly be possible, but the whole config parsing routine would need to be rewritten to allow for commandline-based config information. I'm curious...what's the issue with reading config files to control testcases?


this we can manage with the config file. I will find out some way for
this.

If this turns out to be very difficult, I could rewrite the parsing code. I'd rather not do it if I don't have to though.

Chris
/*
Author: Nortel Networks 
	Chris Friesen		[EMAIL PROTECTED]
	Approval token "Nortel-02-July-2008-01"
 
Copyright 2008 Nortel Networks
   
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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
REPRESENTATIONS, AND CONDITIONS INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. See the GNU General Public License for more details.


IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

You should have received a copy of the GNU General Public License along with
this program; if not, contact the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA www.fsf.org/ for a copy.

*/

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sched.h>
#include <ctype.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <time.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>


#define GROUP_NAMESIZE 16
#define MAX_CPUS 4
#define MAX_GROUPS 10

#define for_all_kids(i,info) for(int i=0;i<info->numkidgroups;i++)
#define kid(i,info) info->kidgroups[i]
#define for_all_hogs(i,info) for(int i=0;i<info->numhogs;i++)
#define hog(i,info) info->hogs[i]


struct acct_data_struct
{
	pid_t pid;
	
	//the following are obtained from /proc/<pid>/sched
	float cputime;
	float wait_count;
	float wait_max;
	float wait_sum;
	float wait_avg;
	float ctx;
};

struct groupinfo
{
	struct groupinfo *parent;
	struct groupinfo *kidgroups[MAX_GROUPS];
	int numkidgroups;
	int share;
	float totalpercent;	//expected cpu usage of this group and all child groups
	float percent;		//expected cpu usage of this group
	float net;		//net cpu usage of this group
	float gross;		//gross cpu usage of this group
	float kidweight;	//sum of shares of child groups with cpu hogs
	char name;		//group name

	int numhogs;
	int numkidhogs;
	pid_t hogs[MAX_CPUS];
	struct acct_data_struct hogdata[MAX_CPUS];
	double totalactual; //sum of actual cpu usage of all hogs for this group (and child groups)
};

int delay=-1;
int duration=-1;
int do_yield=0;
int do_sleep=0;
int verbose=0;
int extraverbose=0;
int doaffine=0;
int setfifo=0;


int numcpus;
struct groupinfo rootgroup;

void printresults(struct groupinfo *info);

char groupname[GROUP_NAMESIZE];
char *buildname(struct groupinfo *info)
{
	if (info == &rootgroup) {
		strcpy(groupname, "root");
		return groupname;
	}

	char *ptr = groupname+GROUP_NAMESIZE-1;
	*ptr = 0;
	ptr--;
	*ptr = info->name;
	
	while((info=info->parent) != &rootgroup) {
		ptr--;
		*ptr = '/';
		ptr--;
		*ptr = info->name;
	}
	return ptr;
}

//can't have group percent be more than numhogs*100
void validatepercents(struct groupinfo *info)
{
	if (info->percent/100.0*numcpus > info->numhogs) {
		printf("invalid testcase configuration\n");
		printf("group \"%s\" cannot use up specified time with given number of hogs\n", buildname(info));
		exit(-1); 
	}
	
	for_all_kids(i,info)
		validatepercents(kid(i,info));
}

//determine the number of "descendent" hogs
void calckidhogs(struct groupinfo *info)
{
	for_all_kids(i,info)
		calckidhogs(kid(i,info));

	info->kidweight=0;
	for_all_kids(i,info) {
		info->numkidhogs += kid(i,info)->numhogs + kid(i,info)->numkidhogs;
		if ((kid(i,info)->numhogs > 0) || (kid(i,info)->kidweight))
			info->kidweight += kid(i,info)->share;
	}	
}


//calculate the percent of the system that this group should get
void calcpercents(struct groupinfo *info)
{
	float percent;
	struct groupinfo *tmp;
	
	//don't do calculation for any group without hogs
	if (info == &rootgroup || info->numhogs==0)
		goto next;

	//this group has cpu hogs.  Walk up the tree to the root group,
	//calculating our expected cpu allocation.  Our share is divided by
	//the sum of the weights of our sibling groups with hogs in their
	//descendents, times the share of the parent group.
	//This is then repeated at the next level up,
	//all the way up to the root group. 
	
	percent = info->share;
	
	tmp = info;
	while(tmp->parent) {
		percent *= tmp->parent->share / tmp->parent->kidweight;
		tmp = tmp->parent;
	}

	info->net = percent;
next:
	for_all_kids(i,info)
		calcpercents(kid(i,info));
}

void calc_expected(struct groupinfo *info)
{
	if (info->numhogs)
		info->percent = info->net;
	
	for_all_kids(i,info)
		calc_expected(kid(i,info));
}

int dumpgroup(struct groupinfo *info)
{
	if (!info->name)
		return 0;
	
	if (info == &rootgroup)
		goto next;
	
	printf("%-s, %5d, %3d, %f\n", 
		buildname(info), info->share, info->numhogs, info->percent);
next:
	for_all_kids(i,info)
		dumpgroup(kid(i,info));
	return 0;
}

void dumpconfig()
{
	printf("using settling delay of %d sec, runtime of %d sec\n",
		delay, duration);
	printf("group hierarchy (name, weight, hogs, expected usage):\n");
	dumpgroup(&rootgroup);
}


struct groupinfo * findgroup(struct groupinfo *info, char *name)
{
	if (*name == '*')
		return &rootgroup;

	//scan kidgroups, try to find group with matching name
	for(int i=0;i<MAX_GROUPS;i++) {
		struct groupinfo *tmp = kid(i,info);
		if (!tmp) {
			//haven't found it yet, so doesnt' exist...make it
			struct groupinfo *newinfo = (struct groupinfo *)malloc(sizeof(struct groupinfo));
			memset(newinfo,0, sizeof(*newinfo));
			kid(i,info) = newinfo;
			newinfo->name = *name;
			newinfo->parent = info;
			info->numkidgroups++;
			return newinfo;
		}
		
		//we found a kid, check the name
		if (tmp->name == *name) {
			//two possibilities, duplicate name or else a child group
			//for now, ignore dupe
			return findgroup(tmp, name+2);
		} 
	}
	return 0;
}

void validateleafhogs(struct groupinfo *info)
{
	if (info->numhogs && info->numkidgroups) {
		printf("error in group %s, only leaf groups can have cpu hogs\n",
			buildname(info));
		exit(-1);
	}
	
	for_all_kids(i,info)
		validateleafhogs(kid(i,info));
}


int parsegroup(char *line)
{
	char *nextptr , *ptr = line;
	struct groupinfo *info;
	int num;

	nextptr = strchr(ptr, ',');
	*nextptr = 0;
	
	info = findgroup(&rootgroup, ptr);
	if (!info) {
		printf("unable to parse group, exiting\n");
		exit(-1);
	}
	
	//root group is already set up, so ignore it
	if (info == &rootgroup)
		return 0;
	
	//parse share
	ptr = nextptr+1;
	nextptr = strchr(ptr, ',');
	*nextptr = 0;
	int rc = sscanf(ptr, "%d", &num);
	if (rc != 1){
		printf("unable to parse numhogs, exiting\n");
		printf("next ptr: %s\n", ptr);
		exit(-1);
	}
	info->share=num;
	
	//parse numhogs
	//it's either 0,1,or 'n'
	ptr = nextptr+1;
	if (*ptr == '0')
		info->numhogs = 0;
	else if (*ptr == '1')
		info->numhogs = 1;
	else if (*ptr == 'n')
		info->numhogs = numcpus;
	else {
		printf("unable to parse numhogs, exiting\n");
		printf("next ptr: %s\n", ptr);
		exit(-1);
	}
	
	return 0;
}



int parseconfig(char *path)
{
	FILE * fp;
	char * line = NULL;
	size_t len = 0;
	ssize_t read;
	fp = fopen(path, "r");
	if (!fp) {
		perror("fopen");
		return -1;
	}

	rootgroup.name='*';
	rootgroup.share=100;
	rootgroup.numhogs=0;
	rootgroup.parent=NULL;
	rootgroup.net = 0;
	rootgroup.gross = 100;
	
	while ((read = getline(&line, &len, fp)) != -1) {
		if (!len)
			continue;
		if (line[0] == '#')
			continue;
		if (isspace(line[0]))
			continue;
		
		if (delay==-1)
			sscanf(line, "%d", &delay);
		else if (duration==-1)
			sscanf(line, "%d", &duration);
		else
			parsegroup(line);
	}
	if (line)
		free(line);
	fclose(fp);
	fp=NULL;
	
	validateleafhogs(&rootgroup);
	calckidhogs(&rootgroup);
	calcpercents(&rootgroup);
	calc_expected(&rootgroup);
	dumpconfig();
	
	validatepercents(&rootgroup);
	return 0;
}

int setshare(int share, char *path)
{
	char filename[128];
	sprintf(filename, "%s/cpu.shares", path); 
	
	int fd = open(filename, O_RDWR);
	char buf[1000];
	int len=0;
	len += sprintf(buf+len, "%d", share);

	int rc = write(fd, buf, strlen(buf)+1);
	close(fd);
	
	if (rc < 0)
		printf("%s: errror writing: %s\n", path, buf);
	
	return 0;
	
}


int setgroup(pid_t pid, char *path)
{
	char members[128];
	sprintf(members, "%s/tasks", path);
	int fd = open(members, O_RDWR);
	char buf[100];
	sprintf(buf, "%d", pid);
	int rc = write(fd, buf, strlen(buf));
	if (rc == -1) {
		perror("problem setting task group:");
	}
	close(fd);
	return 0;
	
}

void makegroups(struct groupinfo *info)
{
	if (info != &rootgroup) {
		char *name = buildname(info);
		mkdir(name, 0777);
		setshare(info->share, name);
	}
	
	for_all_kids(i,info)
		makegroups(kid(i,info));
}

int setupsched()
{
	system("mount -t cgroup -o cpu cgroup /dev/cgroup/ &> /dev/null");
	chdir("/dev/cgroup");
	system("find /dev/cgroup -type d -mindepth 1 "
	       "| sort -r | xargs rmdir >& /dev/null");
	system("mkdir -p sys;cd sys;echo 2 > cpu.shares;for i in `cat ../tasks`; do echo $i > tasks;   done");

	makegroups(&rootgroup);
	
	return 0;
}

void forkkidgroups(struct groupinfo *info)
{
	for_all_hogs(i,info) {
		int rc = fork();
		if (!rc) {
			//printf("pid %d in group %s, cpu %d\n", getpid(), buildname(info), i);
			//fflush(stdout);
			if (doaffine) {
	       			cpu_set_t cpumask;

        			CPU_ZERO(&cpumask);
        			CPU_SET(i, &cpumask);

        			int rc = syscall(__NR_sched_setaffinity, getpid(), sizeof(cpumask), &cpumask);
        			if (rc < 0) {
					printf("unable to set affinity for pid %d, cpu %d, group %s: %m",
						getpid(), i, buildname(info));
				}
			}
                        struct sched_param p;
			if (setfifo) {
				p.sched_priority = 1;
				sched_setscheduler(getpid(), SCHED_FIFO, &p);
			} else {
                        	p.sched_priority = 0;
                        	sched_setscheduler(getpid(), SCHED_OTHER, &p);
				setpriority(PRIO_PROCESS, 0, -10);
			}
		
			//infinite loop in child process
			
			/* put ourselves to sleep until woken by parent */
			raise(SIGSTOP);
			
			int count = 0;
			while(1) {
				if (count++ > 1000000){
					count=0;
					if (do_yield)
						sched_yield();
					if (do_sleep) {
						struct timespec ts = {0,1};
						nanosleep(&ts,0);
					}
				}
				
				
			}
		} else if (rc>0) {
			/* need to put kid into non-rt policy so we can set its group */
                        struct sched_param p;
                        p.sched_priority = 0;
                        sched_setscheduler(rc, SCHED_OTHER, &p);
			
			hog(i,info)=rc;
			setgroup(rc, buildname(info));
		} else {
			printf("error, unable to fork child hog %d, group %s: %m\n", i, buildname(info));
			exit(-1);
		}
	}

	for_all_kids(i,info)
		forkkidgroups(kid(i,info));
}

void killkidgroups(struct groupinfo *info, int sig)
{
	for_all_hogs(i,info)
		kill(hog(i,info), sig);
	for_all_kids(i,info)
		killkidgroups(kid(i,info), sig);
}

void resetstats(struct groupinfo *info)
{
	for_all_hogs(i,info) {
		char cmd[1024];
		snprintf(cmd, sizeof(cmd), "echo 0 > /proc/%d/sched", hog(i,info));
		system(cmd);
	}
		
	for_all_kids(i,info)
		resetstats(kid(i,info));
}


void parseline(char *line, char *key, float *val)
{
	float tmp;
	int conv;
	
	char *s = strstr(line, key);
	if (!s)
		return;
	s = strstr(s, ":");
	if (!s)
		return;
	s++;
	conv = sscanf(s, " %f", &tmp);
	if (conv==1)
		*val = tmp;
	else {
		printf("error parsing line %s for key %s", line, key);
		exit(-1);
	}
}

/* exit if we can't read data for this pid */
void getpiddata(pid_t pid, struct acct_data_struct *data)
{
	FILE * fp;
	char * line = NULL;
	size_t len = 0;
	ssize_t read;
	char name[1024];
	float wait_max, wait_sum, wait_count, sum_exec_runtime,ctx;
	
	if (extraverbose) {
		snprintf(name, sizeof(name), "cat /proc/%d/sched", pid);
		system(name);
	}
	
	snprintf(name, sizeof(name), "/proc/%d/sched", pid);
	
	
	fp = fopen(name, "r");
	if (!fp) {
		printf("error opening sched stats file for pid %d: %m", pid);
		exit(-1);
	}
	wait_max = wait_sum = wait_count = sum_exec_runtime = 0;

	while ((read = getline(&line, &len, fp)) != -1) {
		if (!len) {
			printf("error reading stats file for pid %d\n", pid);
			exit(-1);
		}
				
		parseline(line, "se.wait_max", &wait_max);
		parseline(line, "se.wait_sum", &wait_sum);
		parseline(line, "se.wait_count", &wait_count);
		parseline(line, "se.sum_exec_runtime", &sum_exec_runtime);
		parseline(line, "nr_switches", &ctx);

	}
		
	if (line)
		free(line);
	fclose(fp);


	if (!wait_max || !wait_sum || !wait_count || !sum_exec_runtime || !ctx){
		printf("error parsing stats for pid %d\n", pid);
		exit(-1);
	}
	
	data->cputime = sum_exec_runtime;
	data->wait_max = wait_max;
	data->wait_sum = wait_sum;
	data->wait_count = wait_count;
	data->wait_avg = wait_sum/wait_count;
	data->ctx = ctx;
}

int updatetime(struct groupinfo *info)
{
	for_all_hogs(i,info) {
		getpiddata(hog(i,info), &info->hogdata[i]);
		info->totalactual+=info->hogdata[i].cputime;
	}
	
	for_all_kids(i,info) {
		int rc = updatetime(kid(i,info));
		if (rc == 1)
			return 1;
		info->totalactual+=kid(i,info)->totalactual;
	}
	return 0;
}


int checktime(struct groupinfo *info)
{
	for_all_hogs(i,info) {
		if (hog(i,info) != info->hogdata[i].pid) {
			printf("error, no timing data for pid %d, results unreliable\n", hog(i,info));
			return 1;
		}
	}
	
	for_all_kids(i,info) {
		int rc = checktime(kid(i,info));
		if (rc == 1)
			return 1;
	}
	return 0;
}


float allowed_variance(struct groupinfo *info, int cpu)
{
	//allow 3% of specified weight as error
	float allowed_error = info->percent * 0.03;
		
	//with smallest tolerance of 0.25%
	if (allowed_error < 0.25)
		allowed_error = 0.25;

	return allowed_error;
}

const char * meets_share_spec(struct groupinfo *info, int hog)
{
	/* note....this is the old calculation, need to update it with the new */
	float actual;
	if (hog==-1)
		actual = info->totalactual*100.0/rootgroup.totalactual;
	else
		actual = (float)info->hogdata[hog].cputime*100.0*numcpus/rootgroup.totalactual;
	float expected = info->percent;
	float allowed_error = allowed_variance(info, 0);
	if ((fabs(actual - expected) < allowed_error) || (actual > expected))
		return "y";
	else
		return "n";
}

float allowed_lat(struct groupinfo *info, int cpu)
{
	float tmp = 1000 / (info->percent * 10.0);
	if (tmp < 20)
		tmp = 20;
	return tmp;
}

const char * meets_lat_spec(struct groupinfo *info, int cpu)
{
	float worst = info->hogdata[0].wait_max;
	return (allowed_lat(info, cpu) > worst) ? "y" : "n";
}



void printresults_mult(struct groupinfo *info)
{
	char tmpbuf[1024];
	int pos;

	if ((info==&rootgroup) || (info->numhogs == 0))
		goto printkidgroups;
	
	info->totalactual=0;
	for_all_hogs(i,info)
		info->totalactual+=info->hogdata[i].cputime;

	//name
	printf("%7s", buildname(info));
	
	if (verbose) {	
		pos=0;
		pos += sprintf(tmpbuf + pos, "  %s", meets_share_spec(info, -1));
		pos += sprintf(tmpbuf + pos, "(%s", meets_share_spec(info, 0));
		for (int i=1;i<info->numhogs;i++) {
			pos += sprintf(tmpbuf + pos, "/%s", meets_share_spec(info, i));
		}
		printf("%8s)", tmpbuf);
	}
	
	
	if (verbose) {	
		pos=0;
		pos += sprintf(tmpbuf + pos, "  %s", meets_lat_spec(info, 0));
		for (int i=1;i<info->numhogs;i++) {
			pos += sprintf(tmpbuf + pos, "/%s", meets_lat_spec(info, i));
		}
		printf("%12s", tmpbuf);
	}
		
	//actual percent
	pos=0;
	pos += sprintf(tmpbuf + pos, "  %5.2f", (float)info->totalactual*100.0/rootgroup.totalactual);
	if (verbose) {
		pos += sprintf(tmpbuf + pos, "(%5.2f", (float)info->hogdata[0].cputime*100.0*numcpus/rootgroup.totalactual);
		for (int i=1;i<info->numhogs;i++) {
			pos += sprintf(tmpbuf + pos, "/%.2f", (float)info->hogdata[i].cputime*100.0*numcpus/rootgroup.totalactual);
		}
		printf("%21s)", tmpbuf);
	} else
		printf("%13s", tmpbuf);
		
	
	//expected percent
	pos=0;
	pos += sprintf(tmpbuf + pos, "  %5.2f", info->percent);
	printf("%14s", tmpbuf);
	
	if (verbose) {	
		//error
		pos=0;
		pos += sprintf(tmpbuf + pos, "  %5.2f", (float)info->hogdata[0].cputime*100.0*numcpus/rootgroup.totalactual - info->percent);
		for (int i=1;i<info->numhogs;i++) {
			pos += sprintf(tmpbuf + pos, "/%.2f", (float)info->hogdata[i].cputime*100.0*numcpus/rootgroup.totalactual - info->percent);
		}
		printf("%14s", tmpbuf);
	
		//allowed error?
		pos=0;
		pos += sprintf(tmpbuf + pos, "   %5.2f", allowed_variance(info, 0));
		printf("%10s", tmpbuf);
	
		//context switches
		pos=0;
		pos += sprintf(tmpbuf + pos, "  %.0f", info->hogdata[0].ctx);
		for (int i=1;i<info->numhogs;i++) {
			pos += sprintf(tmpbuf + pos, "/%.0f", info->hogdata[i].ctx);
		}
		printf("%15s", tmpbuf);
	}
		
	//avg latency
	pos=0;
	pos += sprintf(tmpbuf + pos, "   %.0f", info->hogdata[0].wait_avg);
	for (int i=1;i<info->numhogs;i++) {
		pos += sprintf(tmpbuf + pos, "/%.0f",info->hogdata[i].wait_avg);
	}
	printf("%18s", tmpbuf);

	//worst latency
	pos=0;
	pos += sprintf(tmpbuf + pos, "   %.0f", info->hogdata[0].wait_max);
	for (int i=1;i<info->numhogs;i++) {
		pos += sprintf(tmpbuf + pos, "/%.0f", info->hogdata[i].wait_max);
	}
	printf("%18s", tmpbuf);


	if (verbose) {
		//allowed latency
		pos=0;
		pos += sprintf(tmpbuf + pos, "   %.2f", allowed_lat(info, 0));
		for (int i=1;i<info->numhogs;i++) {
			pos += sprintf(tmpbuf + pos, "/%.2f", allowed_lat(info, i));
		}
		printf("%23s", tmpbuf);
	}

	printf("\n");
	
printkidgroups:
	for_all_kids(i,info)
		printresults(kid(i,info));
}


//results for single hog
void printresults_single(struct groupinfo *info)
{
	float percent, expected;
	
	if ((info==&rootgroup) || (info->numhogs == 0))
		goto printkidgroups;
	
	
	info->totalactual=0;
	for_all_hogs(i,info) {
		info->totalactual+=info->hogdata[i].cputime;
	}
	
	percent = info->totalactual * 100.0 / rootgroup.totalactual;
	expected =  info->percent;
	
	
	printf("%7s", buildname(info));
	if (verbose)
		printf("%8s%12s      ", meets_share_spec(info, -1), meets_lat_spec(info, 0));
		
	//printf("%15.2f", time_ms);
	
	printf("%13.2f%14.2f", percent, expected);
	if (verbose)
		printf("%14.2f%14.2f%14.0f", 
			percent - expected, allowed_variance(info, 0), info->hogdata[0].ctx);
	
	printf("%18.0f%18.0f", info->hogdata[0].wait_avg, info->hogdata[0].wait_max);
	if (verbose)
		printf("%20.2f", allowed_lat(info,0));

	printf("\n");

	
printkidgroups:
	//could print time/scheduled breakdown per pid within group
	
	for_all_kids(i,info)
		printresults(kid(i,info));
}


void printresults(struct groupinfo *info)
{
	if (info->numhogs > 1)
		printresults_mult(info);
	else
		printresults_single(info);
}


void printout(struct groupinfo *info)
{
	double expected=duration*numcpus*1000.0;
	double err = fabs(rootgroup.totalactual - expected);
	
	//complain if more than 2% discrepancy between actual and expected duration
	if (err/expected > 0.02)
		printf("Warning, actual cpu time different than expected. actual: %f, expected: %f\n",
			rootgroup.totalactual, expected);	
	
	if (verbose) {
		printf("            meets       meets\n");
		printf("  group   share spec   lat spec       actual(%%)     expected(%%)    error(%%)   allowed error(%%)  ctx switches   avg latency(ms)   max_latency(ms)  allowed_latency(ms)\n");
	} else {
		printf("  group       actual(%%)     expected(%%)    avg latency(ms)   max_latency(ms)\n");
	}
	printresults(info);
}

int runtest()
{
	//configure the scheduler for the test
	setupsched();
	
	//create the cpu hogs for each group.  They will sleep
	//waiting to be sent SIGCONT.
	forkkidgroups(&rootgroup);
	
	//tell all hogs to continue
	killkidgroups(&rootgroup, SIGCONT);
	
	//let hogs run for initial delay time to get them settled in
	sleep(delay);
	
	//pause hogs for a sec and reset all the stats, then start them
	killkidgroups(&rootgroup, SIGSTOP);
	resetstats(&rootgroup);
	killkidgroups(&rootgroup, SIGCONT);
	
	//let hogs run for duration of test
	sleep(duration);
	
	//pause all hogs
	killkidgroups(&rootgroup, SIGSTOP);
	
	//get the runtime data
	updatetime(&rootgroup);

	//terminate all hogs
	killkidgroups(&rootgroup, SIGTERM);

	//dump the data
	printout(&rootgroup);
	
	//erase all groups
	system("find /dev/cgroup -type d -mindepth 1 "
	       "| sort -r | xargs rmdir >& /dev/null");
	
	return 0;
}

int main(int argc, char **argv)
{
	while(1) {
		int c = getopt(argc, argv, "syvVaf");
		switch(c) {
		case 'y':
			printf("doing yield\n");
	       		do_yield = 1;
			break;
		case 's':
			printf("doing sleep\n");
			do_sleep = 1;
			break;
		case 'v':
			verbose = 1;
			break;
		case 'V':
			verbose = 1;
			extraverbose = 1;
			break;
		case 'a':
			doaffine = 1;
			break;
		case 'f':
			setfifo=1;
			break;
		case -1:
		default:
			goto done_options;
		}
	}
done_options:

	signal(SIGCHLD, SIG_IGN);
	
	// bump up the priority of the main task so we can kill the others
	struct sched_param p;
	p.sched_priority = 2;
	sched_setscheduler(getpid(), SCHED_RR, &p);

        numcpus = sysconf(_SC_NPROCESSORS_ONLN);
	
	//parse the config file specified in the arg list
	int rc = parseconfig(argv[optind]);
	if (rc < 0) {
		printf("unable to parse config file\n");
		return -1;
	}

	runtest();
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to