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