Export the cpu nodes and sockets from Xen
authorIustin Pop <iustin@google.com>
Mon, 9 Feb 2009 10:41:21 +0000 (10:41 +0000)
committerIustin Pop <iustin@google.com>
Mon, 9 Feb 2009 10:41:21 +0000 (10:41 +0000)
This is a hand-picked forward patch of commit 1755 on the 1.2 branch
(hand-picked since the trees diverged too much since then):

    The patch changed the xen hypervisor to compute the number of cpu
    sockets/nodes and enables the command line and the RAPI to show this
    information (for RAPI is enabled by default in node details, for gnt-one
    one can use the new “cnodes” and “csockets” fields).

    Originally-Reviewed-by: ultrotter

For the KVM and fake hypervisors, the patch just exports 1 for both
nodes and sockets. This can be fixed, by looking at the
/sys/devices/system/cpu/cpuN/topology directories, and computing the
actual information, but that should be done in a separate patch.

Reviewed-by: imsnah

lib/cmdlib.py
lib/hypervisor/hv_fake.py
lib/hypervisor/hv_kvm.py
lib/hypervisor/hv_xen.py
lib/rapi/rlib2.py
scripts/gnt-node

index 7bde623..f406751 100644 (file)
@@ -1759,7 +1759,7 @@ class LUQueryNodes(NoHooksLU):
     "dtotal", "dfree",
     "mtotal", "mnode", "mfree",
     "bootid",
-    "ctotal",
+    "ctotal", "cnodes", "csockets",
     )
 
   _FIELDS_STATIC = utils.FieldSet(
@@ -1838,6 +1838,8 @@ class LUQueryNodes(NoHooksLU):
             "dfree": fn(int, nodeinfo.get('vg_free', None)),
             "ctotal": fn(int, nodeinfo.get('cpu_total', None)),
             "bootid": nodeinfo.get('bootid', None),
+            "cnodes": fn(int, nodeinfo.get('cpu_nodes', None)),
+            "csockets": fn(int, nodeinfo.get('cpu_sockets', None)),
             }
         else:
           live_data[name] = {}
index a1daf01..1211cbd 100644 (file)
@@ -200,6 +200,9 @@ class FakeHypervisor(hv_base.BaseHypervisor):
     except EnvironmentError, err:
       raise errors.HypervisorError("Failed to list node info: %s" % err)
     result['cpu_total'] = cpu_total
+    # FIXME: export correct data here
+    result['cpu_nodes'] = 1
+    result['cpu_sockets'] = 1
 
     return result
 
index e43a24c..c3d1db5 100644 (file)
@@ -639,6 +639,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     except EnvironmentError, err:
       raise errors.HypervisorError("Failed to list node info: %s" % err)
     result['cpu_total'] = cpu_total
+    # FIXME: export correct data here
+    result['cpu_nodes'] = 1
+    result['cpu_sockets'] = 1
 
     return result
 
@@ -779,5 +782,3 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     if iso_path and not os.path.isfile(iso_path):
       raise errors.HypervisorError("Instance cdrom image '%s' not found or"
                                    " not a file" % iso_path)
-
-
index b34b221..fb5a28d 100644 (file)
@@ -199,10 +199,13 @@ class XenHypervisor(hv_base.BaseHypervisor):
   def GetNodeInfo(self):
     """Return information about the node.
 
-    @return: a dict with the following keys (values in MiB):
+    @return: a dict with the following keys (memory values in MiB):
           - memory_total: the total memory size on the node
           - memory_free: the available memory on the node for instances
           - memory_dom0: the memory used by the node itself, if available
+          - nr_cpus: total number of CPUs
+          - nr_nodes: in a NUMA system, the number of domains
+          - nr_sockets: the number of physical CPU sockets in the node
 
     """
     # note: in xen 3, memory has changed to total_memory
@@ -214,6 +217,7 @@ class XenHypervisor(hv_base.BaseHypervisor):
 
     xmoutput = result.stdout.splitlines()
     result = {}
+    cores_per_socket = threads_per_core = nr_cpus = None
     for line in xmoutput:
       splitfields = line.split(":", 1)
 
@@ -225,7 +229,18 @@ class XenHypervisor(hv_base.BaseHypervisor):
         elif key == 'free_memory':
           result['memory_free'] = int(val)
         elif key == 'nr_cpus':
-          result['cpu_total'] = int(val)
+          nr_cpus = result['cpu_total'] = int(val)
+        elif key == 'nr_nodes':
+          result['cpu_nodes'] = int(val)
+        elif key == 'cores_per_socket':
+          cores_per_socket = int(val)
+        elif key == 'threads_per_core':
+          threads_per_core = int(val)
+
+    if (cores_per_socket is not None and
+        threads_per_core is not None and nr_cpus is not None):
+      result['cpu_sockets'] = nr_cpus / (cores_per_socket * threads_per_core)
+
     dom0_info = self.GetInstanceInfo("Domain-0")
     if dom0_info is not None:
       result['memory_dom0'] = dom0_info[2]
index 050ab66..67d802d 100644 (file)
@@ -42,7 +42,9 @@ I_FIELDS = ["name", "admin_state", "os",
 N_FIELDS = ["name", "offline", "master_candidate",
             "dtotal", "dfree",
             "mtotal", "mnode", "mfree",
-            "pinst_cnt", "sinst_cnt", "tags"]
+            "pinst_cnt", "sinst_cnt", "tags",
+            "ctotal", "cnodes", "csockets",
+            ]
 
 
 class R_version(baserlib.R_Generic):
index 606b7c8..b6552ab 100755 (executable)
@@ -50,7 +50,7 @@ _LIST_HEADERS = {
   "dtotal": "DTotal", "dfree": "DFree",
   "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree",
   "bootid": "BootID",
-  "ctotal": "CTotal",
+  "ctotal": "CTotal", "cnodes": "CNodes", "csockets": "CSockets",
   "tags": "Tags",
   "serial_no": "SerialNo",
   "master_candidate": "MasterC",