CPULimiteHost.popen(): set cgroup and (optionally) RT priority
This commit is contained in:
+6
-5
@@ -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 ):
|
||||||
|
|||||||
@@ -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]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user