Peter Zijlstra wrote:
On Tue, 2008-08-26 at 03:20 +0530, Subrata Modak wrote:Hi Vatsa, 2.6.26 has seen commits to implement SMP nice support for the full group hierarchy. Did you use any specific regression/benchmark test cases ofyour own for this ?Some hand crafted scenarios at times, but chris friesen (CCed) wrote a nice test program - he might be willing to share ;-)
Sure...the more people that are testing in a systematic way, the better results we're likely to see in mainline.
I've attached my test app, along with some sample config files.It lets you specify some number of groups, set the share for each group, and specify 0/1/n cpu hogs for each group (where n is the number of cpus online). To save resources I've arbitrarily set the limit at 10 groups and 4 cpus, but that can easily be changed. Basically it sets up the groups, spawns a bunch of cpu hogs, and then after a specified amount of time it pauses all of the hogs and gathers cpu usage and latency data from /proc/<pid>/sched.
The tool must be run as root. In the simplest case you just give it the name of the config file and it will use the default options--cpu hogs are pure hogs, are not affined, and run in SCHED_OTHER with nice -10.
The app can handle multiple levels of group hierarchy. To simplify things, it will only allow scenarios where all the cpu hogs are in the leaf groups, and will bail out if this is violated.
You can use the "-v" option to dump more information, and "-V" to give the verbose version and also dump out the /proc/<pid>/sched files for manual parsing.
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.
*/
#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]
using namespace std;
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, 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();
}
test1.dat
Description: MPEG movie
test2.dat
Description: MPEG movie
test4.dat
Description: MPEG movie
------------------------------------------------------------------------- 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
