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: eak@xxxxxxxxxx
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@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list