Here is my first pass at a patch for accessing the available memory associated with each NUMA cell through libvirt.

The initial framework patch provided by Daniel Veillard is a prereq of this patch:
https://www.redhat.com/archives/libvir-list/2007-September/msg00069.html

I have not yet tested this. I'm just distributing for comments.

A few comments/questions:
1) I think I got the versioning stuff right but that deserves a close look.
2) In Daniel's patch, libvirt.h and libvirt.h.in were identical. I assumed the patch would be before running autogen.sh, and only contain changes in libvirt.h.in, so that's how I did mine. Let me know if I misunderstand something here. 3) I had to put #ifdef PROXY around calls to virXenErrorFunc in xenHypervisorNodeGetCellsFreeMemory to get this to build. I haven't figured out how the proxy code works so am not sure if this is the right approach.

--
Elizabeth Kon (Beth)
IBM Linux Technology Center
Open Hypervisor Team
email: [EMAIL PROTECTED]

diff -urpN libvirt.danielpatch/include/libvirt/libvirt.h.in libvirt.cellsMemory/include/libvirt/libvirt.h.in
--- libvirt.danielpatch/include/libvirt/libvirt.h.in	2007-09-11 15:29:43.000000000 -0400
+++ libvirt.cellsMemory/include/libvirt/libvirt.h.in	2007-09-20 14:11:32.000000000 -0400
@@ -586,8 +586,9 @@ int virDomainDetachDevice(virDomainPtr d
  */
 
 int			 virNodeGetCellsFreeMemory(virConnectPtr conn,
-						   unsigned long *freeMems,
-						   int nbCells);
+						   long long *freeMems,
+						   int startCell,
+						   int maxCells);
 
 /*
  * Virtual Networks API
diff -urpN libvirt.danielpatch/src/driver.h libvirt.cellsMemory/src/driver.h
--- libvirt.danielpatch/src/driver.h	2007-09-11 15:29:43.000000000 -0400
+++ libvirt.cellsMemory/src/driver.h	2007-09-20 14:16:41.000000000 -0400
@@ -258,8 +258,9 @@ typedef virDriver *virDriverPtr;
 typedef int
     (*virDrvNodeGetCellsFreeMemory)
                     (virConnectPtr conn,
-                     unsigned long *freeMems,
-		     int nbCells);
+                     long long *freeMems,
+                     int startCell,
+                     int maxCells);
 
 /**
  * _virDriver:
diff -urpN libvirt.danielpatch/src/libvirt.c libvirt.cellsMemory/src/libvirt.c
--- libvirt.danielpatch/src/libvirt.c	2007-09-11 15:29:43.000000000 -0400
+++ libvirt.cellsMemory/src/libvirt.c	2007-09-20 14:20:34.000000000 -0400
@@ -2650,36 +2650,43 @@ virDomainDetachDevice(virDomainPtr domai
 
 /**
  * virNodeGetCellFreeMemory:
+
  * @conn: pointer to the hypervisor connection
- * @freeMems: pointer to the array of unsigned long
- * @nbCells: number of entries available in freeMems
+ * @freeMems: pointer to the array of long long
+ * @startCell: index of first cell to return freeMems info on (0 to
+ *             maxCells - 1).
+ * @maxCells: number of entries available in freeMems (-1 for sum of
+ *            free memory across all cells, returned in freeMems[0])
  *
- * This call allows to ask the amount of free memory in each NUMA cell.
+ * This call is a request for the amount of free memory, either in the whole
+ * node, or in each NUMA cell.
  * The @freeMems array must be allocated by the caller and will be filled
  * with the amounts of free memory in kilobytes for each cell starting
- * from cell #0 and up to @nbCells -1 or the number of cell in the Node
+ * from cell #0 and up to @maxCells -1 or the number of cells in the Node
  * (which can be found using virNodeGetInfo() see the nodes entry in the
  * structure).
+ * If maxCells == -1, the free memory will be summed across all cells and
+ * returned in freeMems[0].
  *
  * Returns the number of entries filled in freeMems, or -1 in case of error.
  */
 
 int
-virNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long *freeMems,
-                          int nbCells)
+virNodeGetCellsFreeMemory(virConnectPtr conn, long long *freeMems,
+                          int startCell, int maxCells)
 {
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
     }
 
-    if ((freeMems == NULL) || (nbCells <= 0)) {
+    if ((freeMems == NULL) || (maxCells <= 0) || (startCell > maxCells - 1)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return (-1);
     }
 
     if (conn->driver->nodeGetCellsFreeMemory)
-        return conn->driver->nodeGetCellsFreeMemory (conn, freeMems, nbCells);
+        return conn->driver->nodeGetCellsFreeMemory (conn, freeMems, startCell, maxCells);
 
     virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return -1;
diff -urpN libvirt.danielpatch/src/xen_internal.c libvirt.cellsMemory/src/xen_internal.c
--- libvirt.danielpatch/src/xen_internal.c	2007-09-11 15:29:44.000000000 -0400
+++ libvirt.cellsMemory/src/xen_internal.c	2007-09-20 13:17:51.000000000 -0400
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include <sys/utsname.h>
 #include "xs_internal.h"
+#include "xend_internal.h"
 
 /* required for dom0_getdomaininfo_t */
 #include <xen/dom0_ops.h>
@@ -201,6 +202,15 @@ union xen_getschedulerid {
 };
 typedef union xen_getschedulerid xen_getschedulerid;
 
+struct xen_v2s4_availheap {
+    uint32_t min_bitwidth;  /* Smallest address width (zero if don't care). */
+    uint32_t max_bitwidth;  /* Largest address width (zero if don't care). */
+    int32_t  node;          /* NUMA node (-1 for sum across all nodes). */
+    uint64_t avail_bytes;   /* Bytes available in the specified region. */
+};
+
+typedef struct xen_v2s4_availheap  xen_v2s4_availheap;
+
 
 #define XEN_GETDOMAININFOLIST_ALLOC(domlist, size)                      \
     (hypervisor_version < 2 ?                                           \
@@ -524,6 +534,11 @@ typedef struct xen_v2d5_setvcpumap xen_v
 #define XEN_V2_OP_GETSCHEDULERID	4
 
 /*
+ * from V2 we get the available heap information
+ */
+#define XEN_V2_OP_GETAVAILHEAP  	9
+
+/*
  * from V2 we get the scheduler parameter
  */
 #define XEN_V2_OP_SCHEDULER		16
@@ -584,6 +599,7 @@ struct xen_op_v2_sys {
         xen_v2_getdomaininfolistop   getdomaininfolist;
         xen_v2s3_getdomaininfolistop getdomaininfolists3;
         xen_v2_getschedulerid        getschedulerid;
+        xen_v2s4_availheap           availheap;
         uint8_t padding[128];
     } u;
 };
@@ -2012,7 +2028,7 @@ xenHypervisorInit(void)
 #endif
         return(-1);
     }
-    /* Currently consider RHEL5.0 Fedora7 and xen-unstable */
+    /* Currently consider RHEL5.0 Fedora7, xen-3.1, and xen-unstable */
     sys_interface_version = 2; /* XEN_SYSCTL_INTERFACE_VERSION */
     if (virXen_getdomaininfo(fd, 0, &info) == 1) {
         /* RHEL 5.0 */
@@ -2035,7 +2051,7 @@ xenHypervisorInit(void)
 
     sys_interface_version = 3; /* XEN_SYSCTL_INTERFACE_VERSION */
     if (virXen_getdomaininfo(fd, 0, &info) == 1) {
-        /* xen-unstable */
+        /* xen-3.1 */
         dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
         if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
 #ifdef DEBUG
@@ -2045,6 +2061,18 @@ xenHypervisorInit(void)
         }
     }
 
+    sys_interface_version = 4; /* XEN_SYSCTL_INTERFACE_VERSION */
+    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
+        /* xen-unstable */
+        dom_interface_version = 5; /* XEN_DOMCTL_INTERFACE_VERSION */
+        if (virXen_getvcpusinfo(fd, 0, 0, ipt, NULL, 0) == 0){
+#ifdef DEBUG
+            fprintf(stderr, "Using hypervisor call v2, sys ver4 dom ver5\n");
+#endif
+            goto done;
+        }
+    }
+
     hypervisor_version = 1;
     sys_interface_version = -1;
     if (virXen_getdomaininfo(fd, 0, &info) == 1) {
@@ -2940,34 +2968,92 @@ xenHypervisorGetDomainInfo(virDomainPtr 
 /**
  * xenHypervisorNodeGetCellsFreeMemory:
  * @conn: pointer to the hypervisor connection
- * @freeMems: pointer to the array of unsigned long
- * @nbCells: number of entries available in freeMems
+ * @freeMems: pointer to the array of long long
+ * @startCell: index of first cell to return freeMems info on (0 to 
+ *             maxCells - 1).  
+ * @maxCells: number of entries available in freeMems (-1 for sum of 
+ *            free memory across all cells, returned in freeMems[0])
  *
- * This call allows to ask the amount of free memory in each NUMA cell.
+ * This call is a request for the amount of free memory, either in the whole
+ * node, or in each NUMA cell.
  * The @freeMems array must be allocated by the caller and will be filled
  * with the amounts of free memory in kilobytes for each cell starting
- * from cell #0 and up to @nbCells -1 or the number of cell in the Node
+ * from cell #0 and up to @maxCells -1 or the number of cell in the Node
  * (which can be found using virNodeGetInfo() see the nodes entry in the
  * structure).
+ * If maxCells == -1, startCell will be ignored and the free memory will be 
+ * summed across all cells and returned in freeMems[0].
  *
  * Returns the number of entries filled in freeMems, or -1 in case of error.
  */
 int
-xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long *freeMems,
-                                    int nbCells)
+xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn, long long *freeMems,
+                                    int startCell, int maxCells)
 {
-    if ((conn == NULL) || (freeMems == NULL) || (nbCells < 0))
-        return -1;
+    xen_op_v2_sys op_sys;
+    int i, ret, nbCells;
+    virNodeInfo nodeInfo;
+    virNodeInfoPtr nodeInfoPtr = &nodeInfo;
+    xenUnifiedPrivatePtr priv;
+    
 
+    if ((conn == NULL) || (freeMems == NULL) || (maxCells < 0))
+        return -1;
     /*
-     * TODO:
-     *   - get the number of cell in the node
-     *   - if not NUMA returns the available memeoy directly in freeMems[0]
-     *     return 1
-     *   - if NUMA iterates over the cells using a specific hypercall
-     *     filling up entries until full or at the end of the NUMA cells
+     * Support only sys_interface_version >=4
      */
-    return(-1);
+    if (sys_interface_version < 4) {
+#ifndef PROXY
+        virXenErrorFunc (VIR_ERR_NO_XEN, __FUNCTION__,
+                        "unsupported in sys interface < 4", 0);
+#endif
+        return -1;
+    }
+
+    priv = (xenUnifiedPrivatePtr) conn->privateData;
+    if (priv->handle < 0) {
+#ifndef PROXY
+        virXenErrorFunc (VIR_ERR_INTERNAL_ERROR, __FUNCTION__,
+                        "priv->handle invalid", 0);
+#endif
+        return -1;
+    }
+
+    memset(&op_sys, 0, sizeof(op_sys));
+    op_sys.cmd = XEN_V2_OP_GETAVAILHEAP;
+
+    if (maxCells == -1) {
+        /* return total free memory for all cells */
+        op_sys.u.availheap.node = -1;
+        ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
+        if (ret < 0)
+            return(-1);
+        freeMems[0] = op_sys.u.availheap.avail_bytes;
+        return(1);
+    }
+
+
+    /* get actual number of cells */
+    if (xenDaemonNodeGetInfo(conn, nodeInfoPtr)) {
+        virXenError(VIR_ERR_XEN_CALL, " cannot determine actual number of cells", 0);
+        return -1;
+    }
+    nbCells = nodeInfoPtr->nodes;
+
+    if (maxCells > nbCells)
+        maxCells = nbCells;
+
+    if (startCell > nbCells - 1)
+        return -1;
+
+    for (i = startCell; i < maxCells; i++) {
+        op_sys.u.availheap.node = i;
+        ret = xenHypervisorDoV2Sys(priv->handle, &op_sys);
+        if (ret < 0)
+            return(-1);
+        freeMems[i] = op_sys.u.availheap.avail_bytes;
+    }
+    return (maxCells - startCell);
 }
 
 
diff -urpN libvirt.danielpatch/src/xen_internal.h libvirt.cellsMemory/src/xen_internal.h
--- libvirt.danielpatch/src/xen_internal.h	2007-09-11 15:29:44.000000000 -0400
+++ libvirt.cellsMemory/src/xen_internal.h	2007-09-20 13:18:00.000000000 -0400
@@ -11,6 +11,8 @@
 #ifndef __VIR_XEN_INTERNAL_H__
 #define __VIR_XEN_INTERNAL_H__
 
+#include "libvirt/libvirt.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -94,8 +96,9 @@ int     xenHypervisorDomainInterfaceStat
 					 struct _virDomainInterfaceStats *stats);
 
 int	xenHypervisorNodeGetCellsFreeMemory(virConnectPtr conn,
-					  unsigned long *freeMems,
-					  int nbCells);
+					  long long *freeMems,
+					  int startCell,
+					  int maxCells);
 #ifdef __cplusplus
 }
 #endif
diff -urpN libvirt.danielpatch/src/xen_unified.c libvirt.cellsMemory/src/xen_unified.c
--- libvirt.danielpatch/src/xen_unified.c	2007-09-11 15:29:44.000000000 -0400
+++ libvirt.cellsMemory/src/xen_unified.c	2007-09-20 13:18:08.000000000 -0400
@@ -1050,13 +1050,14 @@ xenUnifiedDomainInterfaceStats (virDomai
 }
 
 static int
-xenUnifiedNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long *freeMems,
-                                  int nbCells)
+xenUnifiedNodeGetCellsFreeMemory (virConnectPtr conn, long long *freeMems,
+                                  int startCell, int maxCells)
 {
     GET_PRIVATE (conn);
 
     if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET])
-        return xenHypervisorNodeGetCellsFreeMemory (conn, freeMems, nbCells);
+        return xenHypervisorNodeGetCellsFreeMemory (conn, freeMems, 
+                                                    startCell, maxCells);
 
     xenUnifiedError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return -1;
--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to