-
-
Save furlongm/4350627 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Marcus Furlong <[email protected]> 4/4/2012 | |
# Pin vcpus on xen | |
import sys | |
sys.path.insert(1, '/usr/lib/xen-4.0/lib/python') | |
sys.path.insert(1, '/usr/lib/xen-4.0/lib/python/xen/xm') | |
import os | |
import sys | |
import xml.dom.minidom | |
import warnings | |
warnings.filterwarnings('ignore', category=FutureWarning) | |
from xen.xend import sxp | |
from xen.xend import XendClient | |
from xen.util.xmlrpcclient import ServerProxy | |
from xen.util import auxbin | |
from xen.xend import XendOptions | |
xoptions = XendOptions.instance() | |
import signal | |
signal.signal(signal.SIGINT, signal.SIG_DFL) | |
XM_CONFIG_FILE_ENVVAR = 'XM_CONFIG_FILE' | |
XM_CONFIG_FILE_DEFAULT = auxbin.xen_configdir() + '/xm-config.xml' | |
# Supported types of server | |
SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC' | |
SERVER_XEN_API = 'Xen-API' | |
def pin_vcpus(): | |
doms = server.xend.domains_with_state(False, 'all', False) | |
dominfo = map(server.xend.domain.getVCPUInfo, doms) | |
nr_cpus = 0 | |
for x in server.xend.node.info()[1:]: | |
if len(x) > 1 and x[0] == 'nr_cpus': | |
nr_cpus = int(x[1]) | |
print "Host has %s physical CPUS" % nr_cpus | |
nonpinned = [] | |
dom0_cpus = [] | |
pcpumap = {} | |
dom0 = server.xend.domain.getVCPUInfo(0) | |
for vcpu in sxp.children(dom0, 'vcpu'): | |
cpumap = list(sxp.child_value(vcpu, 'cpumap')) | |
for pcpu in cpumap: | |
dom0_cpus.append(pcpu) | |
for i in range(0, nr_cpus): | |
if i in dom0_cpus: | |
pcpumap[i] = [0] | |
else: | |
pcpumap[i] = [] | |
for dom in dominfo: | |
def get_info(n): | |
return sxp.child_value(dom, n) | |
name = get_info('name') | |
domid = get_info('domid') | |
if domid is not None: | |
domid = str(domid) | |
else: | |
domid = '' | |
for vcpu in sxp.children(dom, 'vcpu'): | |
def vinfo(n, t): | |
return t(sxp.child_value(vcpu, n)) | |
number = vinfo('number', int) | |
cpumap = vinfo('cpumap', list) | |
print '%(name)-32s %(domid)5s %(number)5d %(cpumap)s' % locals() | |
if domid != '0': | |
for cpu in cpumap: | |
pcpumap[cpu].append(int(domid)) | |
if len(cpumap) > 1: | |
nonpinned.append([domid, number]) | |
vcpus_to_pin = len(nonpinned) | |
print "There are %s vCPUS to pin" % vcpus_to_pin | |
print "Domain-0 is using CPUs %s" % dom0_cpus | |
print "%s CPUS are available for pinning" % (nr_cpus - len(dom0_cpus)) | |
if vcpus_to_pin > 0: | |
def get_minlevel(pcpumap, minlevel=50): | |
for pcpu in pcpumap: | |
if len(pcpumap[pcpu]) < minlevel and pcpu not in dom0_cpus: | |
minlevel = len(pcpumap[pcpu]) | |
return minlevel | |
minlevel = get_minlevel(pcpumap) | |
for dom_vcpu in nonpinned: | |
for pcpu in pcpumap: | |
if len(pcpumap[pcpu]) > minlevel or pcpu in dom0_cpus: | |
continue | |
else: | |
domain_id = str(dom_vcpu[0]) | |
vcpu_id = str(dom_vcpu[1]) | |
cpu_id = str(pcpu) | |
pcpumap[pcpu].append(int(dom_vcpu[0])) | |
print >> sys.stderr, ("xm vcpu-pin %s %s %s" % | |
(domain_id, vcpu_id, cpu_id)) | |
xm_vcpu_pin([domain_id, vcpu_id, cpu_id]) | |
minlevel = get_minlevel(pcpumap) | |
break | |
print >> sys.stderr, ("%s vCPUs pinned" % vcpus_to_pin) | |
else: | |
print "No vCPUs need pinning." | |
def xm_vcpu_pin(args): | |
def cpu_make_map(cpulist): | |
cpus = [] | |
for c in cpulist.split(','): | |
if c == '': | |
continue | |
if c.find('-') != -1: | |
(x, y) = c.split('-') | |
for i in range(int(x), int(y) + 1): | |
cpus.append(int(i)) | |
else: | |
# remove this element from the list | |
if c[0] == '^': | |
cpus = [x for x in cpus if x != int(c[1:])] | |
else: | |
cpus.append(int(c)) | |
cpus.sort() | |
return ",".join(map(str, cpus)) | |
dom = args[0] | |
vcpu = args[1] | |
cpumap = cpu_make_map(args[2]) | |
server.xend.domain.pincpu(dom, vcpu, cpumap) | |
def parseServer(): | |
if config: | |
server = config.getElementsByTagName('server') | |
if server: | |
st = server[0].getAttribute('type') | |
if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC: | |
print >> sys.stderr, ('Invalid server type %s; using %s.' % | |
(st, SERVER_LEGACY_XMLRPC)) | |
st = SERVER_LEGACY_XMLRPC | |
return (st, server[0].getAttribute('uri')) | |
return SERVER_LEGACY_XMLRPC, XendClient.uri | |
def parseAuthentication(): | |
server = config.getElementsByTagName('server')[0] | |
return (server.getAttribute('username'), | |
server.getAttribute('password')) | |
if __name__ == "__main__": | |
print "WARNING: this program assumes that dom0_vcpus_pin=true has been" | |
print "set on the kernel command line." | |
xmConfigFile = os.getenv(XM_CONFIG_FILE_ENVVAR, XM_CONFIG_FILE_DEFAULT) | |
config = None | |
if os.path.isfile(xmConfigFile): | |
try: | |
config = xml.dom.minidom.parse(xmConfigFile) | |
except: | |
print >> sys.stderr, ('Ignoring invalid configuration file %s.' % | |
xmConfigFile) | |
serverType, serverURI = parseServer() | |
server = ServerProxy(serverURI) | |
pin_vcpus() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment