This patch includes NUMA topology info in the QEMU driver capabilities XML output. It also implements the free memory driver APIs. This is done with the LGPL'd numactl library. The configure script probes for it and only enables this functionality if it is found. The numactl library has been around for quite a while - RHEL-3 vintage at least configure.in | 39 ++++++++++++++++++++++++++++++ libvirt.spec.in | 3 ++ src/Makefile.am | 2 + src/qemu_conf.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+) Regards, Daniel Index: src/qemu_conf.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_conf.c,v retrieving revision 1.64 diff -u -p -r1.64 qemu_conf.c --- src/qemu_conf.c 15 May 2008 20:07:34 -0000 1.64 +++ src/qemu_conf.c 15 May 2008 21:07:42 -0000 @@ -42,6 +42,10 @@ #include <libxml/xpath.h> #include <libxml/uri.h> +#if HAVE_NUMACTL +#include <numa.h> +#endif + #include "libvirt/virterror.h" #include "qemu_conf.h" @@ -49,6 +53,7 @@ #include "buf.h" #include "conf.h" #include "util.h" +#include "memory.h" #include <verify.h> #define qemudLog(level, msg...) fprintf(stderr, msg) @@ -389,6 +394,67 @@ qemudCapsInitGuest(virCapsPtr caps, return 0; } +#if HAVE_NUMACTL +#define MAX_CPUS 4096 +#define MAX_CPUS_MASK_SIZE (sizeof(unsigned long)) +#define MAX_CPUS_MASK_LEN (MAX_CPUS / MAX_CPUS_MASK_SIZE) +#define MAX_CPUS_MASK_BYTES (MAX_CPUS / 8) +static int +qemudCapsInitNUMA(virCapsPtr caps) +{ + int n, i; + unsigned long *mask = NULL; + int ncpus; + int *cpus = NULL; + int ret = -1; + + fprintf(stderr, "Add numa\n"); + + if (numa_available() < 0) + return 0; + + fprintf(stderr, "Start\n"); + if (VIR_ALLOC_N(mask, MAX_CPUS_MASK_LEN) < 0) + goto cleanup; + + for (n = 0 ; n <= numa_max_node() ; n++) { + fprintf(stderr, "Do node %d\n", n); + + if (numa_node_to_cpus(n, mask, MAX_CPUS_MASK_BYTES) < 0) + goto cleanup; + + for (ncpus = 0, i = 0 ; i < MAX_CPUS ; i++) + if ((mask[(i / MAX_CPUS_MASK_SIZE)] >> (i % MAX_CPUS_MASK_SIZE)) & 1) + ncpus++; + + if (VIR_ALLOC_N(cpus, ncpus) < 0) + goto cleanup; + + for (ncpus = 0, i = 0 ; i < MAX_CPUS ; i++) + if ((mask[(i / MAX_CPUS_MASK_SIZE)] >> (i % MAX_CPUS_MASK_SIZE)) & 1) + cpus[ncpus++] = i; + + fprintf(stderr, "Do node %d %d\n", n, ncpus); + if (virCapabilitiesAddHostNUMACell(caps, + n, + ncpus, + cpus) < 0) + goto cleanup; + + VIR_FREE(cpus); + } + + ret = 0; + +cleanup: + VIR_FREE(cpus); + VIR_FREE(mask); + return ret; +} +#else +static int qemudCapsInitNUMA(virCapsPtr caps ATTRIBUTE_UNUSED) { return 0; } +#endif + virCapsPtr qemudCapsInit(void) { struct utsname utsname; virCapsPtr caps; @@ -401,6 +467,9 @@ virCapsPtr qemudCapsInit(void) { 0, 0)) == NULL) goto no_memory; + if (qemudCapsInitNUMA(caps) < 0) + goto no_memory; + for (i = 0 ; i < (sizeof(arch_info_hvm)/sizeof(arch_info_hvm[0])) ; i++) if (qemudCapsInitGuest(caps, utsname.machine, Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.74 diff -u -p -r1.74 qemu_driver.c --- src/qemu_driver.c 15 May 2008 16:11:40 -0000 1.74 +++ src/qemu_driver.c 15 May 2008 21:07:50 -0000 @@ -47,6 +47,10 @@ #include <sys/wait.h> #include <libxml/uri.h> +#if HAVE_NUMACTL +#include <numa.h> +#endif + #include "libvirt/virterror.h" #include "event.h" @@ -1605,6 +1609,62 @@ static char *qemudGetCapabilities(virCon } +#if HAVE_NUMACTL +static int +qemudNodeGetCellsFreeMemory(virConnectPtr conn, + unsigned long long *freeMems, + int startCell, + int maxCells) +{ + int n, lastCell, numCells; + fprintf(stderr, "Foo %d %d\n", startCell, maxCells); + if (numa_available() < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, + "%s", _("NUMA not supported on this host")); + return -1; + } + lastCell = startCell + maxCells - 1; + if (lastCell > numa_max_node()) + lastCell = numa_max_node(); + + for (numCells = 0, n = startCell ; n <= lastCell ; n++) { + long long mem; + if (numa_node_size64(n, &mem) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to query NUMA free memory")); + return -1; + } + fprintf(stderr, "baro %d %llu\n", n, mem); + freeMems[numCells++] = mem; + } + return numCells; +} + +static unsigned long long +qemudNodeGetFreeMemory (virConnectPtr conn) +{ + unsigned long long freeMem = 0; + int n; + if (numa_available() < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT, + "%s", _("NUMA not supported on this host")); + return -1; + } + + for (n = 0 ; n <= numa_max_node() ; n++) { + long long mem; + if (numa_node_size64(n, &mem) < 0) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to query NUMA free memory")); + return -1; + } + freeMem += mem; + } + + return freeMem; +} + +#endif static int qemudGetProcessInfo(unsigned long long *cpuTime, int pid) { char proc[PATH_MAX]; @@ -3168,8 +3228,13 @@ static virDriver qemuDriver = { NULL, /* domainMigrateFinish */ qemudDomainBlockStats, /* domainBlockStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */ +#if HAVE_NUMACTL + qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ + qemudNodeGetFreeMemory, /* getFreeMemory */ +#else NULL, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ +#endif }; static virNetworkDriver qemuNetworkDriver = { Index: src/Makefile.am =================================================================== RCS file: /data/cvs/libvirt/src/Makefile.am,v retrieving revision 1.79 diff -u -p -r1.79 Makefile.am --- src/Makefile.am 29 Apr 2008 15:38:13 -0000 1.79 +++ src/Makefile.am 15 May 2008 21:07:57 -0000 @@ -9,6 +9,7 @@ INCLUDES = \ $(GNUTLS_CFLAGS) \ $(SASL_CFLAGS) \ $(SELINUX_CFLAGS) \ + $(NUMACTL_CFLAGS) \ -DBINDIR=\""$(libexecdir)"\" \ -DSBINDIR=\""$(sbindir)"\" \ -DSYSCONF_DIR="\"$(sysconfdir)\"" \ @@ -100,6 +101,7 @@ endif libvirt_la_SOURCES = $(CLIENT_SOURCES) $(SERVER_SOURCES) libvirt_la_LIBADD = $(LIBXML_LIBS) $(GNUTLS_LIBS) $(SASL_LIBS) $(SELINUX_LIBS) \ + $(NUMACTL_LIBS) \ @CYGWIN_EXTRA_LIBADD@ ../gnulib/lib/libgnu.la libvirt_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libvirt_sym.version \ -version-info @LIBVIRT_VERSION_INFO@ \ Index: configure.in =================================================================== RCS file: /data/cvs/libvirt/configure.in,v retrieving revision 1.143 diff -u -p -r1.143 configure.in --- configure.in 5 May 2008 19:58:56 -0000 1.143 +++ configure.in 15 May 2008 21:08:05 -0000 @@ -534,6 +534,40 @@ AM_CONDITIONAL(HAVE_SELINUX, [test "$wit AC_SUBST(SELINUX_CFLAGS) AC_SUBST(SELINUX_LIBS) +dnl NUMA lib +AC_ARG_WITH(numactl, + [ --with-numactl use numactl for host topology info], + [], + [with_numactl=check]) + +NUMACTL_CFLAGS= +NUMACTL_LIBS= +if test "$with_qemu" = "yes" -a "$with_numactl" != "no"; then + old_cflags="$CFLAGS" + old_libs="$LIBS" + if test "$with_numactl" = "check"; then + AC_CHECK_HEADER([numa.h],[],[with_numactl=no]) + AC_CHECK_LIB(numa, numa_available,[],[with_numactl=no]) + if test "$with_numactl" != "no"; then + with_numactl="yes" + fi + else + AC_CHECK_HEADER([numa.h],[], + [AC_MSG_ERROR([You must install the numactl development package in order to compile libvirt])]) + AC_CHECK_LIB(numa, numa_available,[], + [AC_MSG_ERROR([You must install the numactl development package in order to compile and run libvirt])]) + fi + CFLAGS="$old_cflags" + LIBS="$old_libs" +fi +if test "$with_numactl" = "yes"; then + NUMACTL_LIBS="-lnuma" + AC_DEFINE_UNQUOTED(HAVE_NUMACTL, 1, [whether Numactl is available for security]) +fi +AM_CONDITIONAL(HAVE_NUMACTL, [test "$with_numactl" != "no"]) +AC_SUBST(NUMACTL_CFLAGS) +AC_SUBST(NUMACTL_LIBS) + dnl virsh libraries AC_CHECK_HEADERS([readline/readline.h]) @@ -1001,6 +1035,11 @@ AC_MSG_NOTICE([ selinux: $SELINUX_CFLAG else AC_MSG_NOTICE([ selinux: no]) fi +if test "$with_numactl" = "yes" ; then +AC_MSG_NOTICE([ numactl: $NUMACTL_CFLAGS $NUMACTL_LIBS]) +else +AC_MSG_NOTICE([ numactl: no]) +fi AC_MSG_NOTICE([]) AC_MSG_NOTICE([Miscellaneous]) AC_MSG_NOTICE([]) Index: libvirt.spec.in =================================================================== RCS file: /data/cvs/libvirt/libvirt.spec.in,v retrieving revision 1.83 diff -u -p -r1.83 libvirt.spec.in --- libvirt.spec.in 8 Apr 2008 16:45:57 -0000 1.83 +++ libvirt.spec.in 15 May 2008 21:08:14 -0000 @@ -67,6 +67,9 @@ BuildRequires: dnsmasq BuildRequires: bridge-utils BuildRequires: qemu BuildRequires: cyrus-sasl-devel +%if %{with_qemu} +BuildRequires: numactl-devel +%endif %if %{with_polkit} BuildRequires: PolicyKit-devel >= 0.6 %endif -- |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list