Add static cpu (and memory) assignment.
This commit is contained in:
@@ -221,6 +221,9 @@ class MininetRunner( object ):
|
|||||||
opts.add_option( '--prefixlen', type='int', default=8,
|
opts.add_option( '--prefixlen', type='int', default=8,
|
||||||
help='prefix length (e.g. /8) for automatic '
|
help='prefix length (e.g. /8) for automatic '
|
||||||
'network configuration' )
|
'network configuration' )
|
||||||
|
opts.add_option( '--pin', action='store_true',
|
||||||
|
default=False, help="pin hosts to CPU cores "
|
||||||
|
"(requires --host cfs or --host rt)" )
|
||||||
|
|
||||||
self.options, self.args = opts.parse_args()
|
self.options, self.args = opts.parse_args()
|
||||||
|
|
||||||
@@ -259,6 +262,7 @@ class MininetRunner( object ):
|
|||||||
xterms = self.options.xterms
|
xterms = self.options.xterms
|
||||||
mac = self.options.mac
|
mac = self.options.mac
|
||||||
arp = self.options.arp
|
arp = self.options.arp
|
||||||
|
pin = self.options.pin
|
||||||
listenPort = None
|
listenPort = None
|
||||||
if not self.options.nolistenport:
|
if not self.options.nolistenport:
|
||||||
listenPort = self.options.listenport
|
listenPort = self.options.listenport
|
||||||
@@ -268,7 +272,8 @@ class MininetRunner( object ):
|
|||||||
ipBase=ipBase,
|
ipBase=ipBase,
|
||||||
inNamespace=inNamespace,
|
inNamespace=inNamespace,
|
||||||
xterms=xterms, autoSetMacs=mac,
|
xterms=xterms, autoSetMacs=mac,
|
||||||
autoStaticArp=arp, listenPort=listenPort )
|
autoStaticArp=arp, autoPinCpus=pin,
|
||||||
|
listenPort=listenPort )
|
||||||
|
|
||||||
if self.options.pre:
|
if self.options.pre:
|
||||||
CLI( mn, script=self.options.pre )
|
CLI( mn, script=self.options.pre )
|
||||||
|
|||||||
+12
-4
@@ -96,7 +96,7 @@ from mininet.cli import CLI
|
|||||||
from mininet.log import info, error, debug, output
|
from mininet.log import info, error, debug, output
|
||||||
from mininet.node import Host, OVSKernelSwitch, Controller
|
from mininet.node import Host, OVSKernelSwitch, Controller
|
||||||
from mininet.link import Link, Intf
|
from mininet.link import Link, Intf
|
||||||
from mininet.util import quietRun, fixLimits
|
from mininet.util import quietRun, fixLimits, numCores
|
||||||
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
|
from mininet.util import macColonHex, ipStr, ipParse, netParse, ipAdd
|
||||||
from mininet.term import cleanUpScreens, makeTerms
|
from mininet.term import cleanUpScreens, makeTerms
|
||||||
|
|
||||||
@@ -107,7 +107,8 @@ class Mininet( object ):
|
|||||||
controller=Controller, link=Link, intf=Intf,
|
controller=Controller, link=Link, intf=Intf,
|
||||||
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
|
build=True, xterms=False, cleanup=False, ipBase='10.0.0.0/8',
|
||||||
inNamespace=False,
|
inNamespace=False,
|
||||||
autoSetMacs=False, autoStaticArp=False, listenPort=None ):
|
autoSetMacs=False, autoStaticArp=False, autoPinCpus=False,
|
||||||
|
listenPort=None ):
|
||||||
"""Create Mininet object.
|
"""Create Mininet object.
|
||||||
topo: Topo (topology) object or None
|
topo: Topo (topology) object or None
|
||||||
switch: default Switch class
|
switch: default Switch class
|
||||||
@@ -120,8 +121,9 @@ class Mininet( object ):
|
|||||||
xterms: if build now, spawn xterms?
|
xterms: if build now, spawn xterms?
|
||||||
cleanup: if build now, cleanup before creating?
|
cleanup: if build now, cleanup before creating?
|
||||||
inNamespace: spawn switches and controller in net namespaces?
|
inNamespace: spawn switches and controller in net namespaces?
|
||||||
autoSetMacs: set MAC addrs from topo dpid?
|
autoSetMacs: set MAC addrs automatically like IP addresses?
|
||||||
autoStaticArp: set all-pairs static MAC addrs?
|
autoStaticArp: set all-pairs static MAC addrs?
|
||||||
|
autoPinCpus: pin hosts to (real) cores (requires CPULimitedHost)?
|
||||||
listenPort: base listening port to open; will be incremented for
|
listenPort: base listening port to open; will be incremented for
|
||||||
each additional switch in the net if inNamespace=False"""
|
each additional switch in the net if inNamespace=False"""
|
||||||
self.topo = topo
|
self.topo = topo
|
||||||
@@ -138,6 +140,9 @@ class Mininet( object ):
|
|||||||
self.cleanup = cleanup
|
self.cleanup = cleanup
|
||||||
self.autoSetMacs = autoSetMacs
|
self.autoSetMacs = autoSetMacs
|
||||||
self.autoStaticArp = autoStaticArp
|
self.autoStaticArp = autoStaticArp
|
||||||
|
self.autoPinCpus = autoPinCpus
|
||||||
|
self.numCores = numCores()
|
||||||
|
self.nextCore = 0 # next core for pinning hosts to CPUs
|
||||||
self.listenPort = listenPort
|
self.listenPort = listenPort
|
||||||
|
|
||||||
self.hosts = []
|
self.hosts = []
|
||||||
@@ -166,6 +171,9 @@ class Mininet( object ):
|
|||||||
prefixLen=self.prefixLen ) }
|
prefixLen=self.prefixLen ) }
|
||||||
if self.autoSetMacs:
|
if self.autoSetMacs:
|
||||||
defaults[ 'mac'] = macColonHex( self.nextIP )
|
defaults[ 'mac'] = macColonHex( self.nextIP )
|
||||||
|
if self.autoPinCpus:
|
||||||
|
defaults[ 'cores' ] = self.nextCore
|
||||||
|
self.nextCore = ( self.nextCore + 1 ) % self.numCores
|
||||||
self.nextIP += 1
|
self.nextIP += 1
|
||||||
defaults.update( params )
|
defaults.update( params )
|
||||||
if not cls:
|
if not cls:
|
||||||
@@ -230,7 +238,7 @@ class Mininet( object ):
|
|||||||
"Configure a set of hosts."
|
"Configure a set of hosts."
|
||||||
for host in self.hosts:
|
for host in self.hosts:
|
||||||
info( host.name + ' ' )
|
info( host.name + ' ' )
|
||||||
host.configDefault( defaultRoute=host.defaultIntf )
|
host.configDefault( defaultRoute=host.defaultIntf() )
|
||||||
# You're low priority, dude!
|
# You're low priority, dude!
|
||||||
# BL: do we want to do this here or not?
|
# BL: do we want to do this here or not?
|
||||||
# May not make sense if we have CPU lmiting...
|
# May not make sense if we have CPU lmiting...
|
||||||
|
|||||||
+37
-6
@@ -51,8 +51,8 @@ import select
|
|||||||
from subprocess import Popen, PIPE, STDOUT
|
from subprocess import Popen, PIPE, STDOUT
|
||||||
|
|
||||||
from mininet.log import info, error, warn, debug
|
from mininet.log import info, error, warn, debug
|
||||||
from mininet.util import quietRun, errRun, errFail, moveIntf, isShellBuiltin
|
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||||
from mininet.util import numCores, retry
|
numCores, retry, mountCgroups )
|
||||||
from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN
|
from mininet.moduledeps import moduleDeps, pathCheck, OVS_KMOD, OF_KMOD, TUN
|
||||||
from mininet.link import Link, Intf, TCIntf
|
from mininet.link import Link, Intf, TCIntf
|
||||||
|
|
||||||
@@ -514,10 +514,15 @@ class CPULimitedHost( Host ):
|
|||||||
|
|
||||||
def __init__( self, name, sched='cfs', **kwargs ):
|
def __init__( self, name, sched='cfs', **kwargs ):
|
||||||
Host.__init__( self, name, **kwargs )
|
Host.__init__( self, name, **kwargs )
|
||||||
|
# Initialize class if necessary
|
||||||
|
if not CPULimitedHost.inited:
|
||||||
|
CPULimitedHost.init()
|
||||||
# Create a cgroup and move shell into it
|
# Create a cgroup and move shell into it
|
||||||
self.cgroup = 'cpu,cpuacct:/' + self.name
|
self.cgroup = 'cpu,cpuacct,cpuset:/' + self.name
|
||||||
errFail( 'cgcreate -g ' + self.cgroup )
|
errFail( 'cgcreate -g ' + self.cgroup )
|
||||||
errFail( 'cgclassify -g %s %s' % ( self.cgroup, self.pid ) )
|
# We don't add ourselves to a cpuset because you must
|
||||||
|
# specify the cpu and memory placement first
|
||||||
|
errFail( 'cgclassify -g cpu,cpuacct:/%s %s' % ( self.name, self.pid ) )
|
||||||
# BL: Setting the correct period/quota is tricky, particularly
|
# BL: Setting the correct period/quota is tricky, particularly
|
||||||
# for RT. RT allows very small quotas, but the overhead
|
# for RT. RT allows very small quotas, but the overhead
|
||||||
# seems to be high. CFS has a mininimum quota of 1 ms, but
|
# seems to be high. CFS has a mininimum quota of 1 ms, but
|
||||||
@@ -540,7 +545,7 @@ class CPULimitedHost( Host ):
|
|||||||
"Return value of cgroup parameter"
|
"Return value of cgroup parameter"
|
||||||
cmd = 'cgget -r %s.%s /%s' % (
|
cmd = 'cgget -r %s.%s /%s' % (
|
||||||
resource, param, self.name )
|
resource, param, self.name )
|
||||||
return quietRun( cmd ).split()[ -1 ]
|
return int( quietRun( cmd ).split()[ -1 ] )
|
||||||
|
|
||||||
def cgroupDel( self ):
|
def cgroupDel( self ):
|
||||||
"Clean up our cgroup"
|
"Clean up our cgroup"
|
||||||
@@ -616,15 +621,41 @@ class CPULimitedHost( Host ):
|
|||||||
self.chrt( prio=20 )
|
self.chrt( prio=20 )
|
||||||
info( '(%s %d/%dus) ' % ( sched, quota, period ) )
|
info( '(%s %d/%dus) ' % ( sched, quota, period ) )
|
||||||
|
|
||||||
def config( self, cpu=None, **params ):
|
def setCPUs( self, cores ):
|
||||||
|
"Specify (real) cores that our cgroup can run on"
|
||||||
|
if type( cores ) is list:
|
||||||
|
cores = ','.join( [ str( c ) for c in cores ] )
|
||||||
|
self.cgroupSet( resource='cpuset', param='cpus',
|
||||||
|
value= cores )
|
||||||
|
# Memory placement is probably not relevant, but we
|
||||||
|
# must specify it anyway
|
||||||
|
self.cgroupSet( resource='cpuset', param='mems',
|
||||||
|
value= cores )
|
||||||
|
# We have to do this here after we've specified
|
||||||
|
# cpus and mems
|
||||||
|
errFail( 'cgclassify -g cpuset:/%s %s' % (
|
||||||
|
self.name, self.pid ) )
|
||||||
|
|
||||||
|
def config( self, cpu=None, cores=None, **params ):
|
||||||
"""cpu: desired overall system CPU fraction
|
"""cpu: desired overall system CPU fraction
|
||||||
|
cores: (real) core(s) this host can run on
|
||||||
params: parameters for Node.config()"""
|
params: parameters for Node.config()"""
|
||||||
r = Node.config( self, **params )
|
r = Node.config( self, **params )
|
||||||
# Was considering cpu={'cpu': cpu , 'sched': sched}, but
|
# Was considering cpu={'cpu': cpu , 'sched': sched}, but
|
||||||
# that seems redundant
|
# that seems redundant
|
||||||
self.setParam( r, 'setCPUFrac', cpu=cpu )
|
self.setParam( r, 'setCPUFrac', cpu=cpu )
|
||||||
|
self.setParam( r, 'setCPUs', cores=cores )
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
inited = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def init( cls ):
|
||||||
|
"Initialization for CPULimitedHost class"
|
||||||
|
mountCgroups()
|
||||||
|
cls.inited = True
|
||||||
|
|
||||||
|
|
||||||
# Some important things to note:
|
# Some important things to note:
|
||||||
#
|
#
|
||||||
# The "IP" address which setIP() assigns to the switch is not
|
# The "IP" address which setIP() assigns to the switch is not
|
||||||
|
|||||||
Reference in New Issue
Block a user