CPULimiteHost.popen(): set cgroup and (optionally) RT priority

This commit is contained in:
Bob Lantz
2012-04-13 15:50:45 -07:00
parent 089e8130e4
commit df600200a7
2 changed files with 74 additions and 13 deletions
+6 -5
View File
@@ -287,7 +287,8 @@ class Node( object ):
args: Popen() args, single list, or string args: Popen() args, single list, or string
kwargs: Popen() keyword args""" kwargs: Popen() keyword args"""
defaults = { 'stdout': PIPE, 'stderr': PIPE, defaults = { 'stdout': PIPE, 'stderr': PIPE,
'mncmd': [ 'mnexec', '-a' ] } 'mncmd':
[ 'mnexec', '-a', str( self.pid ) ] }
defaults.update( kwargs ) defaults.update( kwargs )
if len( args ) == 1: if len( args ) == 1:
if type( args[ 0 ] ) is list: if type( args[ 0 ] ) is list:
@@ -302,7 +303,7 @@ class Node( object ):
# Attach to our namespace using mnexec -a # Attach to our namespace using mnexec -a
mncmd = defaults[ 'mncmd' ] mncmd = defaults[ 'mncmd' ]
del defaults[ 'mncmd' ] del defaults[ 'mncmd' ]
cmd = mncmd + [ str( self.pid ) ] + cmd cmd = mncmd + cmd
return Popen( cmd, **defaults ) return Popen( cmd, **defaults )
def pexec( self, *args, **kwargs ): def pexec( self, *args, **kwargs ):
@@ -591,9 +592,9 @@ class CPULimitedHost( Host ):
kwargs: Popen() keyword args""" kwargs: Popen() keyword args"""
# Tell mnexec to execute command in our cgroup # Tell mnexec to execute command in our cgroup
mncmd = [ 'mnexec', '-a', str( self.pid ), mncmd = [ 'mnexec', '-a', str( self.pid ),
'-c', self.cgroup ] '-g', self.name ]
if self.sched == 'rt': if self.sched == 'rt':
mncmd = [ 'chrt', self.rtprio ] + mncmd mncmd += [ '-r', str( self.rtprio ) ]
return Host.popen( self, *args, mncmd=mncmd, **kwargs ) return Host.popen( self, *args, mncmd=mncmd, **kwargs )
def cleanup( self ): def cleanup( self ):
@@ -661,7 +662,7 @@ class CPULimitedHost( Host ):
self.cgroupSet( qstr, quota ) self.cgroupSet( qstr, quota )
if sched == 'rt': if sched == 'rt':
# Set RT priority if necessary # Set RT priority if necessary
self.chrt( prio=20 ) self.chrt()
info( '(%s %d/%dus) ' % ( sched, quota, period ) ) info( '(%s %d/%dus) ' % ( sched, quota, period ) )
def setCPUs( self, cores, mems=0 ): def setCPUs( self, cores, mems=0 ):
+68 -8
View File
@@ -7,6 +7,8 @@
* - detaching from a controlling tty using setsid * - detaching from a controlling tty using setsid
* - running in a network namespace * - running in a network namespace
* - printing out the pid of a process so we can identify it later * - printing out the pid of a process so we can identify it later
* - attaching to a namespace and cgroup
* - setting RT scheduling
* *
* Partially based on public domain setsid(1) * Partially based on public domain setsid(1)
*/ */
@@ -17,16 +19,21 @@
#include <limits.h> #include <limits.h>
#include <syscall.h> #include <syscall.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <limits.h>
#include <sched.h>
void usage(char *name) void usage(char *name)
{ {
printf("Execution utility for Mininet.\n" printf("Execution utility for Mininet.\n"
"usage: %s [-cdnp]\n" "usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n"
"-c: close all file descriptors except stdin/out/error\n" "-c: close all file descriptors except stdin/out/error\n"
"-d: detach from tty by calling setsid()\n" "-d: detach from tty by calling setsid()\n"
"-n: run in new network namespace\n" "-n: run in new network namespace\n"
"-p: print ^A + pid\n" "-p: print ^A + pid\n"
"-a pid: attach to pid's network namespace\n", "-a pid: attach to pid's network namespace\n"
"-g group: add to cgroup\n"
"-r rtprio: run with SCHED_RR (usually requires -g)\n",
name); name);
} }
@@ -36,6 +43,47 @@ int setns(int fd, int nstype)
return syscall(308, fd, nstype); return syscall(308, fd, nstype);
} }
/* Validate alphanumeric path foo1/bar2/baz */
void validate(char *path)
{
char *s;
for (s=path; *s; s++) {
if (!isalnum(*s) && *s != '/') {
fprintf(stderr, "invalid path: %s\n", path);
exit(1);
}
}
}
/* Add our pid to cgroup */
int cgroup(char *gname)
{
static char path[PATH_MAX];
static char *groups[] = {
"cpu", "cpuacct", "cpuset", NULL
};
char **gptr;
pid_t pid = getpid();
int count = 0;
validate(gname);
for (gptr = groups; *gptr; gptr++) {
FILE *f;
snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
*gptr, gname);
f = fopen(path, "w");
if (f) {
count++;
fprintf(f, "%d\n", pid);
fclose(f);
}
}
if (!count) {
fprintf(stderr, "cgroup: could not add to cgroup %s\n",
gname);
exit(1);
}
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char c; char c;
@@ -43,8 +91,8 @@ int main(int argc, char *argv[])
char path[PATH_MAX]; char path[PATH_MAX];
int nsid; int nsid;
int pid; int pid;
static struct sched_param sp;
while ((c = getopt(argc, argv, "+cdnpa:")) != -1) while ((c = getopt(argc, argv, "+cdnpa:g:r:")) != -1)
switch(c) { switch(c) {
case 'c': case 'c':
/* close file descriptors except stdin/out/error */ /* close file descriptors except stdin/out/error */
@@ -92,16 +140,28 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
break; break;
case 'g':
/* Attach to cgroup */
cgroup(optarg);
break;
case 'r':
/* Set RT scheduling priority */
sp.sched_priority = atoi(optarg);
if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
perror("sched_setscheduler");
return 1;
}
break;
default: default:
usage(argv[0]); usage(argv[0]);
break; break;
} }
if (optind < argc) { if (optind < argc) {
execvp(argv[optind], &argv[optind]); execvp(argv[optind], &argv[optind]);
perror(argv[optind]); perror(argv[optind]);
return 1; return 1;
} }
usage(argv[0]); usage(argv[0]);
} }