From 3d040733d21991fb8141b6a32dca2eca29652ace Mon Sep 17 00:00:00 2001 Message-Id: <3d040733d21991fb8141b6a32dca2eca29652ace@dist-git> From: Michal Privoznik Date: Fri, 17 Jul 2015 11:45:33 +0200 Subject: [PATCH] examples: Introduce nodestats example https://bugzilla.redhat.com/show_bug.cgi?id=1051494 So, this is an exercise to show libvirt capabilities. Firstly, for each host NUMA nodes some statistics are printed out, i.e. total memory and free memory. Then, for each running domain, that has memory strictly bound to certain host nodes, a small statistics of how much memory it takes is printed out too. For instance: # ./examples/nodestats.py NUMA stats NUMA nodes: 0 1 2 3 MemTotal: 3950 3967 3937 3943 MemFree: 66 56 42 41 Domain 'fedora': Overall memory: 1536 MiB Domain 'fedora22': Overall memory: 2048 MiB Domain 'fedora21': Overall memory: 1024 MiB nodes 0-1 Node 0: 1024 MiB nodes 0-1 Domain 'gentoo': Overall memory: 4096 MiB nodes 0-3 Node 0: 1024 MiB nodes 0 Node 1: 1024 MiB nodes 1 Node 2: 1024 MiB nodes 2 Node 3: 1024 MiB nodes 3 We can see 4 host NUMA nodes, all of them having roughly 4GB of RAM. Yeah, all of them has nearly all the memory consumed. Then, there are four domains running. For instance, domain 'fedora' has 1.5GB memory which is not pinned onto any specific host NUMA node. Domain 'gentoo' on the other hand has 4GB memory and has 4 NUMA nodes which are pinned 1:1 to host nodes. Signed-off-by: Michal Privoznik (cherry picked from commit fa21f3d927b29991741e2d7a8ebc2a920778ecba) Signed-off-by: Michal Privoznik Signed-off-by: Jiri Denemark --- examples/nodestats.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100755 examples/nodestats.py diff --git a/examples/nodestats.py b/examples/nodestats.py new file mode 100755 index 0000000..c01dead --- /dev/null +++ b/examples/nodestats.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# Print some host NUMA node statistics +# +# Authors: +# Michal Privoznik + +import libvirt +import sys +from xml.dom import minidom +import libxml2 + +def xpath_eval(ctxt, path): + res = ctxt.xpathEval(path) + if res is None or len(res) == 0: + value = None + else: + value = res[0].content + return value + +try: + conn = libvirt.openReadOnly(None) +except libvirt.libvirtError: + print("Failed to connect to the hypervisor") + sys.exit(1) + +try: + capsXML = conn.getCapabilities() +except libvirt.libvirtError: + print("Failed to request capabilities") + sys.exit(1) + +caps = minidom.parseString(capsXML) +cells = caps.getElementsByTagName("cells")[0] + +nodesIDs = [ int(proc.getAttribute("id")) + for proc in cells.getElementsByTagName("cell") ] + +nodesMem = [ conn.getMemoryStats(int(proc)) + for proc in nodesIDs] + +doms = conn.listAllDomains(libvirt.VIR_CONNECT_LIST_DOMAINS_ACTIVE) + +domsStrict = [ proc + for proc in doms + if proc.numaParameters()["numa_mode"] == libvirt.VIR_DOMAIN_NUMATUNE_MEM_STRICT ] + +domsStrictCfg = {} +for dom in domsStrict: + xmlStr = dom.XMLDesc() + doc = libxml2.parseDoc(xmlStr) + ctxt = doc.xpathNewContext() + + domsStrictCfg[dom] = {} + + pin = ctxt.xpathEval("string(/domain/numatune/memory/@nodeset)") + memsize = ctxt.xpathEval("string(/domain/memory)") + domsStrictCfg[dom]["memory"] = {"size": int(memsize), "pin": pin} + + for memnode in ctxt.xpathEval("/domain/numatune/memnode"): + ctxt.setContextNode(memnode) + cellid = xpath_eval(ctxt, "@cellid") + nodeset = xpath_eval(ctxt, "@nodeset") + + nodesize = xpath_eval(ctxt, "/domain/cpu/numa/cell[@id='%s']/@memory" % cellid) + domsStrictCfg[dom][cellid] = {"size": int(nodesize), "pin": nodeset} + + +print("NUMA stats") +print("NUMA nodes:\t" + "\t".join(str(node) for node in nodesIDs)) +print("MemTotal:\t" + "\t".join(str(i.get("total") // 1024) for i in nodesMem)) +print("MemFree:\t" + "\t".join(str(i.get("free") // 1024) for i in nodesMem)) + +for dom, v in domsStrictCfg.items(): + print("Domain '%s':\t" % dom.name()) + + toPrint = "\tOverall memory: %d MiB" % (v["memory"]["size"] // 1024) + if v["memory"]["pin"] is not None and v["memory"]["pin"] is not "": + toPrint = toPrint + " nodes %s" % v["memory"]["pin"] + print(toPrint) + + for k, node in sorted(v.items()): + if k is "memory": + continue + toPrint = "\tNode %s:\t%d MiB" % (k, node["size"] // 1024) + if node["pin"] is not None and node["pin"] is not "": + toPrint = toPrint + " nodes %s" % node["pin"] + print(toPrint) -- 2.5.0