2007-07-25 23:16:30 +00:00
|
|
|
/*
|
|
|
|
* nodeinfo.c: Helper routines for OS specific node information
|
|
|
|
*
|
2012-03-02 02:54:22 +00:00
|
|
|
* Copyright (C) 2006-2008, 2010-2012 Red Hat, Inc.
|
2007-07-25 23:16:30 +00:00
|
|
|
* Copyright (C) 2006 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2007-07-25 23:16:30 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-12-05 21:40:15 +00:00
|
|
|
|
2007-07-25 23:16:30 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#include <stdint.h>
|
2007-07-25 23:16:30 +00:00
|
|
|
#include <errno.h>
|
2010-03-04 22:28:40 +00:00
|
|
|
#include <dirent.h>
|
2010-04-29 03:06:46 +00:00
|
|
|
#include <sys/utsname.h>
|
2011-10-03 12:45:30 +00:00
|
|
|
#include <sched.h>
|
2012-03-02 02:54:22 +00:00
|
|
|
#include "conf/domain_conf.h"
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
|
|
|
|
#if HAVE_NUMACTL
|
|
|
|
# define NUMA_VERSION1_COMPATIBILITY 1
|
|
|
|
# include <numa.h>
|
|
|
|
#endif
|
2007-07-25 23:16:30 +00:00
|
|
|
|
2012-12-17 18:12:44 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
# include <sys/types.h>
|
|
|
|
# include <sys/sysctl.h>
|
|
|
|
#endif
|
|
|
|
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#include "c-ctype.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2007-07-25 23:16:30 +00:00
|
|
|
#include "nodeinfo.h"
|
Use gnulib, starting with its physmem and getaddrinfo modules.
New files go into these directories:
gnulib/lib
gnulib/m4
gnulib/tests
* bootstrap: A wrapper around gnulib-tool.
* configure.in: Invoke gl_EARLY and gl_INIT, being careful to put gl_EARLY
before any macro that uses AC_COMPILE_IFELSE.
(AC_OUTPUT): Add lib/Makefile and gl-tests/Makefile. Remove m4/Makefile.
* Makefile.am (SUBDIRS): Add gnulib/lib and remove m4. Add gnulib/tests
early enough that those tests run before any libvirt unit tests.
* m4/Makefile.am: Remove file. Not needed.
* src/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS, libvirt_la_LIBADD): Add ../gnulib/lib/libgnu.la.
* src/nodeinfo.c: Include "physmem.h".
* qemud/qemud.c, src/remote_internal.c: Include "getaddrinfo.h".
(MEMINFO_PATH, linuxNodeInfoMemPopulate): Remove definitions.
(virNodeInfoPopulate): Use physmem_total, not linuxNodeInfoMemPopulate.
* tests/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS): Add ../gnulib/lib/libgnu.la.
* qemud/Makefile.am (libvirtd_LDADD): Add ../gnulib/lib/libgnu.la.
* tests/nodeinfotest.c (linuxTestCompareFiles): No longer read total
memory from a file.
Update expected output not to include "Memory: NNNN"
* tests/nodeinfodata/linux-nodeinfo-1.txt:
* tests/nodeinfodata/linux-nodeinfo-2.txt:
* tests/nodeinfodata/linux-nodeinfo-3.txt:
* tests/nodeinfodata/linux-nodeinfo-4.txt:
* tests/nodeinfodata/linux-nodeinfo-5.txt:
* tests/nodeinfodata/linux-nodeinfo-6.txt:
* src/test.c [WITH_TEST]: Remove definition of _GNU_SOURCE that
would conflict with the one now in "config.h".
* autogen.sh: Add -I gnulib/m4.
* src/conf.c, src/sexpr.c: Don't define _GNU_SOURCE.
Instead, include "config.h".
* qemud/qemud.c: Remove definition of _GNU_SOURCE.
* src/openvz_driver.c: Likewise.
* src/qemu_driver.c: Likewise.
* src/remote_internal.c: Likewise.
* configure.in: Use AC_CONFIG_AUX_DIR(build-aux), so that a bunch
of gettextize-generated files go into build-aux/, rather than in
the top-level directory.
* .cvsignore: Adjust.
* build-aux/.cvsignore: New file.
Author: Jim Meyering <meyering@redhat.com>
2007-12-05 21:31:07 +00:00
|
|
|
#include "physmem.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2010-03-04 22:28:40 +00:00
|
|
|
#include "count-one-bits.h"
|
2010-08-10 21:33:37 +00:00
|
|
|
#include "intprops.h"
|
2012-12-10 21:58:16 +00:00
|
|
|
#include "virarch.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2012-09-14 14:42:16 +00:00
|
|
|
#include "virtypedparam.h"
|
2007-07-25 23:16:30 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2012-12-17 18:12:44 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
static int
|
|
|
|
freebsdNodeGetCPUCount(void)
|
|
|
|
{
|
|
|
|
int ncpu_mib[2] = { CTL_HW, HW_NCPU };
|
|
|
|
unsigned long ncpu;
|
|
|
|
size_t ncpu_len = sizeof(ncpu);
|
|
|
|
|
|
|
|
if (sysctl(ncpu_mib, 2, &ncpu, &ncpu_len, NULL, 0) == -1) {
|
|
|
|
virReportSystemError(errno, "%s", _("Cannot obtain CPU count"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ncpu;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-07-25 23:16:30 +00:00
|
|
|
#ifdef __linux__
|
2010-03-09 18:22:22 +00:00
|
|
|
# define CPUINFO_PATH "/proc/cpuinfo"
|
2012-05-11 19:59:59 +00:00
|
|
|
# define SYSFS_SYSTEM_PATH "/sys/devices/system"
|
2011-06-07 01:02:55 +00:00
|
|
|
# define PROCSTAT_PATH "/proc/stat"
|
2011-06-07 01:11:17 +00:00
|
|
|
# define MEMINFO_PATH "/proc/meminfo"
|
2012-09-14 14:42:16 +00:00
|
|
|
# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm"
|
2011-06-07 01:02:55 +00:00
|
|
|
|
|
|
|
# define LINUX_NB_CPU_STATS 4
|
2011-06-07 01:11:17 +00:00
|
|
|
# define LINUX_NB_MEMORY_STATS_ALL 4
|
|
|
|
# define LINUX_NB_MEMORY_STATS_CELL 2
|
2007-07-25 23:16:30 +00:00
|
|
|
|
2010-03-04 22:28:40 +00:00
|
|
|
/* NB, this is not static as we need to call it from the testsuite */
|
2010-04-03 00:06:51 +00:00
|
|
|
int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
|
2012-05-11 19:59:59 +00:00
|
|
|
const char *sysfs_dir,
|
2011-10-03 12:45:30 +00:00
|
|
|
virNodeInfoPtr nodeinfo);
|
2007-07-25 23:16:30 +00:00
|
|
|
|
2011-06-07 01:02:55 +00:00
|
|
|
static int linuxNodeGetCPUStats(FILE *procstat,
|
|
|
|
int cpuNum,
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeCPUStatsPtr params,
|
2011-06-07 01:02:55 +00:00
|
|
|
int *nparams);
|
2011-06-07 01:11:17 +00:00
|
|
|
static int linuxNodeGetMemoryStats(FILE *meminfo,
|
|
|
|
int cellNum,
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeMemoryStatsPtr params,
|
2011-06-07 01:11:17 +00:00
|
|
|
int *nparams);
|
2011-06-07 01:02:55 +00:00
|
|
|
|
2010-08-10 21:33:37 +00:00
|
|
|
/* Return the positive decimal contents of the given
|
2012-11-01 22:20:09 +00:00
|
|
|
* DIR/cpu%u/FILE, or -1 on error. If DEFAULT_VALUE is non-negative
|
|
|
|
* and the file could not be found, return that instead of an error;
|
|
|
|
* this is useful for machines that cannot hot-unplug cpu0, or where
|
|
|
|
* hot-unplugging is disabled, or where the kernel is too old
|
|
|
|
* to support NUMA cells, etc. */
|
2010-08-10 21:33:37 +00:00
|
|
|
static int
|
nodeinfo: drop static variable
We were wasting time to malloc a copy of a constant string, then
copy it into static storage, for every call to nodeGetInfo. At
least we were lucky that it was a constant source, and thus not
subject to even worse issues with one thread clobbering the static
storage while another was using it. This gets rid of the waste,
by passing the string through the stack instead, as well as renaming
internal functions to better match our conventions.
* src/nodeinfo.c (sysfs_path): Delete.
(get_cpu_value, count_thread_siblings, parse_socket): Add
parameter, and rename...
(virNodeGetCpuValue, virNodeCountThreadSiblings)
(virNodeParseSocket): ... into a common namespace.
(cpu_online, parse_core): Inline into callers.
(linuxNodeInfoCPUPopulate): Update caller.
(nodeGetInfo): Drop a useless malloc.
2012-05-11 18:50:08 +00:00
|
|
|
virNodeGetCpuValue(const char *dir, unsigned int cpu, const char *file,
|
2012-11-01 22:20:09 +00:00
|
|
|
int default_value)
|
2010-08-10 21:33:37 +00:00
|
|
|
{
|
|
|
|
char *path;
|
|
|
|
FILE *pathfp;
|
|
|
|
int value = -1;
|
|
|
|
char value_str[INT_BUFSIZE_BOUND(value)];
|
|
|
|
char *tmp;
|
|
|
|
|
nodeinfo: drop static variable
We were wasting time to malloc a copy of a constant string, then
copy it into static storage, for every call to nodeGetInfo. At
least we were lucky that it was a constant source, and thus not
subject to even worse issues with one thread clobbering the static
storage while another was using it. This gets rid of the waste,
by passing the string through the stack instead, as well as renaming
internal functions to better match our conventions.
* src/nodeinfo.c (sysfs_path): Delete.
(get_cpu_value, count_thread_siblings, parse_socket): Add
parameter, and rename...
(virNodeGetCpuValue, virNodeCountThreadSiblings)
(virNodeParseSocket): ... into a common namespace.
(cpu_online, parse_core): Inline into callers.
(linuxNodeInfoCPUPopulate): Update caller.
(nodeGetInfo): Drop a useless malloc.
2012-05-11 18:50:08 +00:00
|
|
|
if (virAsprintf(&path, "%s/cpu%u/%s", dir, cpu, file) < 0) {
|
2010-08-10 21:33:37 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pathfp = fopen(path, "r");
|
|
|
|
if (pathfp == NULL) {
|
2012-11-01 22:20:09 +00:00
|
|
|
if (default_value >= 0 && errno == ENOENT)
|
|
|
|
value = default_value;
|
2010-08-10 21:33:37 +00:00
|
|
|
else
|
|
|
|
virReportSystemError(errno, _("cannot open %s"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fgets(value_str, sizeof(value_str), pathfp) == NULL) {
|
|
|
|
virReportSystemError(errno, _("cannot read from %s"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (virStrToLong_i(value_str, &tmp, 10, &value) < 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("could not convert '%s' to an integer"),
|
|
|
|
value_str);
|
2010-08-10 21:33:37 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
2010-11-17 02:13:29 +00:00
|
|
|
VIR_FORCE_FCLOSE(pathfp);
|
2010-08-10 21:33:37 +00:00
|
|
|
VIR_FREE(path);
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
nodeinfo: drop static variable
We were wasting time to malloc a copy of a constant string, then
copy it into static storage, for every call to nodeGetInfo. At
least we were lucky that it was a constant source, and thus not
subject to even worse issues with one thread clobbering the static
storage while another was using it. This gets rid of the waste,
by passing the string through the stack instead, as well as renaming
internal functions to better match our conventions.
* src/nodeinfo.c (sysfs_path): Delete.
(get_cpu_value, count_thread_siblings, parse_socket): Add
parameter, and rename...
(virNodeGetCpuValue, virNodeCountThreadSiblings)
(virNodeParseSocket): ... into a common namespace.
(cpu_online, parse_core): Inline into callers.
(linuxNodeInfoCPUPopulate): Update caller.
(nodeGetInfo): Drop a useless malloc.
2012-05-11 18:50:08 +00:00
|
|
|
static unsigned long
|
|
|
|
virNodeCountThreadSiblings(const char *dir, unsigned int cpu)
|
2010-03-04 22:28:40 +00:00
|
|
|
{
|
|
|
|
unsigned long ret = 0;
|
2010-03-09 15:17:59 +00:00
|
|
|
char *path;
|
|
|
|
FILE *pathfp;
|
2010-03-04 22:28:40 +00:00
|
|
|
char str[1024];
|
|
|
|
int i;
|
|
|
|
|
2011-10-03 12:45:30 +00:00
|
|
|
if (virAsprintf(&path, "%s/cpu%u/topology/thread_siblings",
|
nodeinfo: drop static variable
We were wasting time to malloc a copy of a constant string, then
copy it into static storage, for every call to nodeGetInfo. At
least we were lucky that it was a constant source, and thus not
subject to even worse issues with one thread clobbering the static
storage while another was using it. This gets rid of the waste,
by passing the string through the stack instead, as well as renaming
internal functions to better match our conventions.
* src/nodeinfo.c (sysfs_path): Delete.
(get_cpu_value, count_thread_siblings, parse_socket): Add
parameter, and rename...
(virNodeGetCpuValue, virNodeCountThreadSiblings)
(virNodeParseSocket): ... into a common namespace.
(cpu_online, parse_core): Inline into callers.
(linuxNodeInfoCPUPopulate): Update caller.
(nodeGetInfo): Drop a useless malloc.
2012-05-11 18:50:08 +00:00
|
|
|
dir, cpu) < 0) {
|
2010-03-04 22:28:40 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pathfp = fopen(path, "r");
|
|
|
|
if (pathfp == NULL) {
|
|
|
|
virReportSystemError(errno, _("cannot open %s"), path);
|
|
|
|
VIR_FREE(path);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fgets(str, sizeof(str), pathfp) == NULL) {
|
|
|
|
virReportSystemError(errno, _("cannot read from %s"), path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (str[i] != '\0') {
|
2010-03-09 15:17:59 +00:00
|
|
|
if (c_isdigit(str[i]))
|
2010-03-04 22:28:40 +00:00
|
|
|
ret += count_one_bits(str[i] - '0');
|
2010-03-09 15:17:59 +00:00
|
|
|
else if (str[i] >= 'A' && str[i] <= 'F')
|
|
|
|
ret += count_one_bits(str[i] - 'A' + 10);
|
|
|
|
else if (str[i] >= 'a' && str[i] <= 'f')
|
|
|
|
ret += count_one_bits(str[i] - 'a' + 10);
|
2010-03-04 22:28:40 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
2010-11-17 02:13:29 +00:00
|
|
|
VIR_FORCE_FCLOSE(pathfp);
|
2010-03-04 22:28:40 +00:00
|
|
|
VIR_FREE(path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
nodeinfo: drop static variable
We were wasting time to malloc a copy of a constant string, then
copy it into static storage, for every call to nodeGetInfo. At
least we were lucky that it was a constant source, and thus not
subject to even worse issues with one thread clobbering the static
storage while another was using it. This gets rid of the waste,
by passing the string through the stack instead, as well as renaming
internal functions to better match our conventions.
* src/nodeinfo.c (sysfs_path): Delete.
(get_cpu_value, count_thread_siblings, parse_socket): Add
parameter, and rename...
(virNodeGetCpuValue, virNodeCountThreadSiblings)
(virNodeParseSocket): ... into a common namespace.
(cpu_online, parse_core): Inline into callers.
(linuxNodeInfoCPUPopulate): Update caller.
(nodeGetInfo): Drop a useless malloc.
2012-05-11 18:50:08 +00:00
|
|
|
static int
|
|
|
|
virNodeParseSocket(const char *dir, unsigned int cpu)
|
2010-03-04 22:28:40 +00:00
|
|
|
{
|
nodeinfo: drop static variable
We were wasting time to malloc a copy of a constant string, then
copy it into static storage, for every call to nodeGetInfo. At
least we were lucky that it was a constant source, and thus not
subject to even worse issues with one thread clobbering the static
storage while another was using it. This gets rid of the waste,
by passing the string through the stack instead, as well as renaming
internal functions to better match our conventions.
* src/nodeinfo.c (sysfs_path): Delete.
(get_cpu_value, count_thread_siblings, parse_socket): Add
parameter, and rename...
(virNodeGetCpuValue, virNodeCountThreadSiblings)
(virNodeParseSocket): ... into a common namespace.
(cpu_online, parse_core): Inline into callers.
(linuxNodeInfoCPUPopulate): Update caller.
(nodeGetInfo): Drop a useless malloc.
2012-05-11 18:50:08 +00:00
|
|
|
int ret = virNodeGetCpuValue(dir, cpu, "topology/physical_package_id",
|
2012-11-01 22:20:09 +00:00
|
|
|
0);
|
2011-04-14 19:32:25 +00:00
|
|
|
# if defined(__powerpc__) || \
|
2011-04-21 15:27:40 +00:00
|
|
|
defined(__powerpc64__) || \
|
|
|
|
defined(__s390__) || \
|
|
|
|
defined(__s390x__)
|
|
|
|
/* ppc and s390(x) has -1 */
|
2011-04-14 18:50:22 +00:00
|
|
|
if (ret < 0)
|
|
|
|
ret = 0;
|
2011-04-14 19:32:25 +00:00
|
|
|
# endif
|
2011-04-14 18:50:22 +00:00
|
|
|
return ret;
|
2010-03-04 22:28:40 +00:00
|
|
|
}
|
|
|
|
|
2012-08-21 17:10:14 +00:00
|
|
|
# ifndef CPU_COUNT
|
|
|
|
static int
|
|
|
|
CPU_COUNT(cpu_set_t *set)
|
|
|
|
{
|
|
|
|
int i, count = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < CPU_SETSIZE; i++)
|
|
|
|
if (CPU_ISSET(i, set))
|
|
|
|
count++;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
# endif /* !CPU_COUNT */
|
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
/* parses a node entry, returning number of processors in the node and
|
|
|
|
* filling arguments */
|
2012-05-11 19:59:59 +00:00
|
|
|
static int
|
2012-10-29 22:37:05 +00:00
|
|
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
|
|
|
|
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
2012-11-07 13:53:36 +00:00
|
|
|
ATTRIBUTE_NONNULL(5)
|
|
|
|
virNodeParseNode(const char *node,
|
|
|
|
int *sockets,
|
|
|
|
int *cores,
|
|
|
|
int *threads,
|
|
|
|
int *offline)
|
2012-05-11 19:59:59 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
2012-07-09 14:57:49 +00:00
|
|
|
int processors = 0;
|
|
|
|
DIR *cpudir = NULL;
|
|
|
|
struct dirent *cpudirent = NULL;
|
|
|
|
int sock_max = 0;
|
|
|
|
cpu_set_t sock_map;
|
|
|
|
int sock;
|
|
|
|
cpu_set_t *core_maps = NULL;
|
|
|
|
int core;
|
|
|
|
int i;
|
|
|
|
int siblings;
|
|
|
|
unsigned int cpu;
|
|
|
|
int online;
|
2012-05-11 19:59:59 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
*threads = 0;
|
|
|
|
*cores = 0;
|
|
|
|
*sockets = 0;
|
|
|
|
|
|
|
|
if (!(cpudir = opendir(node))) {
|
|
|
|
virReportSystemError(errno, _("cannot opendir %s"), node);
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
|
|
|
/* enumerate sockets in the node */
|
|
|
|
CPU_ZERO(&sock_map);
|
|
|
|
errno = 0;
|
|
|
|
while ((cpudirent = readdir(cpudir))) {
|
|
|
|
if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
|
|
|
|
continue;
|
|
|
|
|
2012-11-01 22:20:09 +00:00
|
|
|
if ((online = virNodeGetCpuValue(node, cpu, "online", 1)) < 0)
|
2012-07-18 01:46:29 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!online)
|
|
|
|
continue;
|
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
/* Parse socket */
|
2012-11-01 22:20:09 +00:00
|
|
|
if ((sock = virNodeParseSocket(node, cpu)) < 0)
|
|
|
|
goto cleanup;
|
2012-07-09 14:57:49 +00:00
|
|
|
CPU_SET(sock, &sock_map);
|
|
|
|
|
|
|
|
if (sock > sock_max)
|
|
|
|
sock_max = sock;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errno) {
|
|
|
|
virReportSystemError(errno, _("problem reading %s"), node);
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
|
|
|
sock_max++;
|
|
|
|
|
|
|
|
/* allocate cpu maps for each socket */
|
|
|
|
if (VIR_ALLOC_N(core_maps, sock_max) < 0) {
|
|
|
|
virReportOOMError();
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2012-07-09 14:57:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < sock_max; i++)
|
|
|
|
CPU_ZERO(&core_maps[i]);
|
|
|
|
|
|
|
|
/* iterate over all CPU's in the node */
|
|
|
|
rewinddir(cpudir);
|
|
|
|
errno = 0;
|
|
|
|
while ((cpudirent = readdir(cpudir))) {
|
|
|
|
if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
|
|
|
|
continue;
|
|
|
|
|
2012-11-01 22:20:09 +00:00
|
|
|
if ((online = virNodeGetCpuValue(node, cpu, "online", 1)) < 0)
|
2012-07-09 14:57:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2012-11-07 13:53:36 +00:00
|
|
|
if (!online) {
|
|
|
|
(*offline)++;
|
2012-07-09 14:57:49 +00:00
|
|
|
continue;
|
2012-11-07 13:53:36 +00:00
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
|
|
|
processors++;
|
|
|
|
|
|
|
|
/* Parse socket */
|
2012-11-01 22:20:09 +00:00
|
|
|
if ((sock = virNodeParseSocket(node, cpu)) < 0)
|
|
|
|
goto cleanup;
|
2012-07-09 14:57:49 +00:00
|
|
|
if (!CPU_ISSET(sock, &sock_map)) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("CPU socket topology has changed"));
|
2012-07-09 14:57:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse core */
|
|
|
|
# if defined(__s390__) || \
|
|
|
|
defined(__s390x__)
|
|
|
|
/* logical cpu is equivalent to a core on s390 */
|
|
|
|
core = cpu;
|
|
|
|
# else
|
2012-11-01 22:20:09 +00:00
|
|
|
core = virNodeGetCpuValue(node, cpu, "topology/core_id", 0);
|
2012-07-09 14:57:49 +00:00
|
|
|
# endif
|
|
|
|
|
|
|
|
CPU_SET(core, &core_maps[sock]);
|
|
|
|
|
|
|
|
if (!(siblings = virNodeCountThreadSiblings(node, cpu)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (siblings > *threads)
|
|
|
|
*threads = siblings;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (errno) {
|
|
|
|
virReportSystemError(errno, _("problem reading %s"), node);
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
|
|
|
/* finalize the returned data */
|
|
|
|
*sockets = CPU_COUNT(&sock_map);
|
|
|
|
|
|
|
|
for (i = 0; i < sock_max; i++) {
|
|
|
|
if (!CPU_ISSET(i, &sock_map))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
core = CPU_COUNT(&core_maps[i]);
|
|
|
|
if (core > *cores)
|
|
|
|
*cores = core;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = processors;
|
2012-05-11 19:59:59 +00:00
|
|
|
|
|
|
|
cleanup:
|
2012-07-09 14:57:49 +00:00
|
|
|
/* don't shadow a more serious error */
|
|
|
|
if (cpudir && closedir(cpudir) < 0 && ret >= 0) {
|
|
|
|
virReportSystemError(errno, _("problem closing %s"), node);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
VIR_FREE(core_maps);
|
|
|
|
|
2012-05-11 19:59:59 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-04-03 00:06:51 +00:00
|
|
|
int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
|
2012-05-11 19:59:59 +00:00
|
|
|
const char *sysfs_dir,
|
2011-10-03 12:45:30 +00:00
|
|
|
virNodeInfoPtr nodeinfo)
|
2010-03-04 22:28:40 +00:00
|
|
|
{
|
2007-07-25 23:16:30 +00:00
|
|
|
char line[1024];
|
2012-07-09 14:57:49 +00:00
|
|
|
DIR *nodedir = NULL;
|
|
|
|
struct dirent *nodedirent = NULL;
|
2012-11-07 13:53:36 +00:00
|
|
|
int cpus, cores, socks, threads, offline = 0;
|
2012-07-09 14:57:49 +00:00
|
|
|
unsigned int node;
|
2012-05-11 19:59:59 +00:00
|
|
|
int ret = -1;
|
2012-07-09 14:57:49 +00:00
|
|
|
char *sysfs_nodedir = NULL;
|
2012-05-11 19:59:59 +00:00
|
|
|
char *sysfs_cpudir = NULL;
|
2007-07-25 23:16:30 +00:00
|
|
|
|
|
|
|
nodeinfo->cpus = 0;
|
|
|
|
nodeinfo->mhz = 0;
|
2011-10-03 12:45:30 +00:00
|
|
|
nodeinfo->cores = 0;
|
2012-07-09 14:57:49 +00:00
|
|
|
nodeinfo->nodes = 0;
|
2010-03-12 15:41:49 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
/* Start with parsing CPU clock speed from /proc/cpuinfo */
|
2007-07-25 23:16:30 +00:00
|
|
|
while (fgets(line, sizeof(line), cpuinfo) != NULL) {
|
2011-04-14 19:32:25 +00:00
|
|
|
# if defined(__x86_64__) || \
|
2011-04-14 18:50:22 +00:00
|
|
|
defined(__amd64__) || \
|
|
|
|
defined(__i386__)
|
2012-04-10 15:46:01 +00:00
|
|
|
char *buf = line;
|
2011-10-03 12:45:30 +00:00
|
|
|
if (STRPREFIX(buf, "cpu MHz")) {
|
2007-11-14 10:53:05 +00:00
|
|
|
char *p;
|
|
|
|
unsigned int ui;
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
buf += 7;
|
2008-05-09 13:50:14 +00:00
|
|
|
while (*buf && c_isspace(*buf))
|
2007-07-25 23:16:30 +00:00
|
|
|
buf++;
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2007-07-25 23:16:30 +00:00
|
|
|
if (*buf != ':' || !buf[1]) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("parsing cpu MHz from cpuinfo"));
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2007-07-25 23:16:30 +00:00
|
|
|
}
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 &&
|
2007-11-14 10:53:05 +00:00
|
|
|
/* Accept trailing fractional part. */
|
2012-07-09 14:57:49 +00:00
|
|
|
(*p == '\0' || *p == '.' || c_isspace(*p)))
|
2007-11-14 10:53:05 +00:00
|
|
|
nodeinfo->mhz = ui;
|
2011-12-30 06:15:26 +00:00
|
|
|
}
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2011-04-14 19:32:25 +00:00
|
|
|
# elif defined(__powerpc__) || \
|
2011-04-14 18:50:22 +00:00
|
|
|
defined(__powerpc64__)
|
2012-04-10 15:46:01 +00:00
|
|
|
char *buf = line;
|
2011-10-03 12:45:30 +00:00
|
|
|
if (STRPREFIX(buf, "clock")) {
|
2011-04-14 18:50:22 +00:00
|
|
|
char *p;
|
|
|
|
unsigned int ui;
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2011-04-14 18:50:22 +00:00
|
|
|
buf += 5;
|
|
|
|
while (*buf && c_isspace(*buf))
|
|
|
|
buf++;
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2011-04-14 18:50:22 +00:00
|
|
|
if (*buf != ':' || !buf[1]) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("parsing cpu MHz from cpuinfo"));
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2011-04-14 18:50:22 +00:00
|
|
|
}
|
2012-05-14 13:12:53 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 &&
|
2011-04-14 18:50:22 +00:00
|
|
|
/* Accept trailing fractional part. */
|
2012-07-09 14:57:49 +00:00
|
|
|
(*p == '\0' || *p == '.' || c_isspace(*p)))
|
2011-04-14 18:50:22 +00:00
|
|
|
nodeinfo->mhz = ui;
|
2011-04-21 15:27:40 +00:00
|
|
|
/* No other interesting infos are available in /proc/cpuinfo.
|
|
|
|
* However, there is a line identifying processor's version,
|
|
|
|
* identification and machine, but we don't want it to be caught
|
|
|
|
* and parsed in next iteration, because it is not in expected
|
|
|
|
* format and thus lead to error. */
|
2011-12-30 06:15:26 +00:00
|
|
|
}
|
2012-07-26 13:32:07 +00:00
|
|
|
# elif defined(__arm__)
|
|
|
|
char *buf = line;
|
|
|
|
if (STRPREFIX(buf, "BogoMIPS")) {
|
|
|
|
char *p;
|
|
|
|
unsigned int ui;
|
|
|
|
|
|
|
|
buf += 8;
|
|
|
|
while (*buf && c_isspace(*buf))
|
|
|
|
buf++;
|
|
|
|
|
|
|
|
if (*buf != ':' || !buf[1]) {
|
2012-10-09 09:46:48 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("parsing cpu MHz from cpuinfo"));
|
2012-07-26 13:32:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
|
|
|
|
/* Accept trailing fractional part. */
|
|
|
|
&& (*p == '\0' || *p == '.' || c_isspace(*p)))
|
|
|
|
nodeinfo->mhz = ui;
|
|
|
|
}
|
2012-06-22 11:50:12 +00:00
|
|
|
# elif defined(__s390__) || \
|
|
|
|
defined(__s390x__)
|
|
|
|
/* s390x has no realistic value for CPU speed,
|
|
|
|
* assign a value of zero to signify this */
|
|
|
|
nodeinfo->mhz = 0;
|
2011-04-14 19:32:25 +00:00
|
|
|
# else
|
|
|
|
# warning Parser for /proc/cpuinfo needs to be adapted for your architecture
|
|
|
|
# endif
|
2007-07-25 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2012-05-11 19:59:59 +00:00
|
|
|
/* OK, we've parsed clock speed out of /proc/cpuinfo. Get the
|
|
|
|
* core, node, socket, thread and topology information from /sys
|
2007-07-25 23:16:30 +00:00
|
|
|
*/
|
2012-07-09 14:57:49 +00:00
|
|
|
if (virAsprintf(&sysfs_nodedir, "%s/node", sysfs_dir) < 0) {
|
2012-05-11 19:59:59 +00:00
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-10-03 12:45:30 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
if (!(nodedir = opendir(sysfs_nodedir))) {
|
|
|
|
/* the host isn't probably running a NUMA architecture */
|
|
|
|
goto fallback;
|
|
|
|
}
|
2011-10-03 12:45:30 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
errno = 0;
|
|
|
|
while ((nodedirent = readdir(nodedir))) {
|
|
|
|
if (sscanf(nodedirent->d_name, "node%u", &node) != 1)
|
2010-03-04 22:28:40 +00:00
|
|
|
continue;
|
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
nodeinfo->nodes++;
|
|
|
|
|
|
|
|
if (virAsprintf(&sysfs_cpudir, "%s/node/%s",
|
|
|
|
sysfs_dir, nodedirent->d_name) < 0) {
|
|
|
|
virReportOOMError();
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2010-08-10 21:33:37 +00:00
|
|
|
}
|
|
|
|
|
2012-11-07 13:53:36 +00:00
|
|
|
if ((cpus = virNodeParseNode(sysfs_cpudir, &socks, &cores,
|
|
|
|
&threads, &offline)) < 0)
|
2012-07-09 14:57:49 +00:00
|
|
|
goto cleanup;
|
2011-10-03 12:45:30 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
VIR_FREE(sysfs_cpudir);
|
2010-03-04 22:28:40 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
nodeinfo->cpus += cpus;
|
|
|
|
|
|
|
|
if (socks > nodeinfo->sockets)
|
|
|
|
nodeinfo->sockets = socks;
|
|
|
|
|
|
|
|
if (cores > nodeinfo->cores)
|
|
|
|
nodeinfo->cores = cores;
|
|
|
|
|
|
|
|
if (threads > nodeinfo->threads)
|
|
|
|
nodeinfo->threads = threads;
|
|
|
|
|
|
|
|
errno = 0;
|
2010-03-04 22:28:40 +00:00
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
2010-08-10 21:33:37 +00:00
|
|
|
if (errno) {
|
2012-07-09 14:57:49 +00:00
|
|
|
virReportSystemError(errno, _("problem reading %s"), sysfs_nodedir);
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
|
|
|
if (nodeinfo->cpus && nodeinfo->nodes)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
fallback:
|
|
|
|
VIR_FREE(sysfs_cpudir);
|
|
|
|
|
|
|
|
if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_dir) < 0) {
|
|
|
|
virReportOOMError();
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2010-08-10 21:33:37 +00:00
|
|
|
}
|
2010-03-04 22:28:40 +00:00
|
|
|
|
2012-11-07 13:53:36 +00:00
|
|
|
if ((cpus = virNodeParseNode(sysfs_cpudir, &socks, &cores,
|
|
|
|
&threads, &offline)) < 0)
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2007-07-25 23:16:30 +00:00
|
|
|
|
2012-07-09 14:57:49 +00:00
|
|
|
nodeinfo->nodes = 1;
|
|
|
|
nodeinfo->cpus = cpus;
|
|
|
|
nodeinfo->sockets = socks;
|
|
|
|
nodeinfo->cores = cores;
|
|
|
|
nodeinfo->threads = threads;
|
|
|
|
|
|
|
|
done:
|
2012-05-11 19:59:59 +00:00
|
|
|
/* There should always be at least one cpu, socket, node, and thread. */
|
2011-10-03 12:45:30 +00:00
|
|
|
if (nodeinfo->cpus == 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found"));
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2011-10-03 12:45:30 +00:00
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
2010-03-09 15:17:59 +00:00
|
|
|
if (nodeinfo->sockets == 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found"));
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2010-03-09 15:17:59 +00:00
|
|
|
}
|
2012-07-09 14:57:49 +00:00
|
|
|
|
2010-03-09 15:17:59 +00:00
|
|
|
if (nodeinfo->threads == 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found"));
|
2012-05-11 19:59:59 +00:00
|
|
|
goto cleanup;
|
2010-03-09 15:17:59 +00:00
|
|
|
}
|
|
|
|
|
2012-11-07 13:53:36 +00:00
|
|
|
/* Now check if the topology makes sense. There are machines that don't
|
|
|
|
* expose their real number of nodes or for example the AMD Bulldozer
|
|
|
|
* architecture that exposes their Clustered integer core modules as both
|
|
|
|
* threads and cores. This approach throws off our detection. Unfortunately
|
|
|
|
* the nodeinfo structure isn't designed to carry the full topology so
|
|
|
|
* we're going to lie about the detected topology to notify the user
|
|
|
|
* to check the host capabilities for the actual topology. */
|
|
|
|
if ((nodeinfo->nodes *
|
|
|
|
nodeinfo->sockets *
|
|
|
|
nodeinfo->cores *
|
|
|
|
nodeinfo->threads) != (nodeinfo->cpus + offline)) {
|
|
|
|
nodeinfo->nodes = 1;
|
|
|
|
nodeinfo->sockets = 1;
|
|
|
|
nodeinfo->cores = nodeinfo->cpus + offline;
|
|
|
|
nodeinfo->threads = 1;
|
|
|
|
}
|
|
|
|
|
2012-05-11 19:59:59 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2012-07-09 14:57:49 +00:00
|
|
|
/* don't shadow a more serious error */
|
|
|
|
if (nodedir && closedir(nodedir) < 0 && ret >= 0) {
|
|
|
|
virReportSystemError(errno, _("problem closing %s"), sysfs_nodedir);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(sysfs_nodedir);
|
2012-05-11 19:59:59 +00:00
|
|
|
VIR_FREE(sysfs_cpudir);
|
|
|
|
return ret;
|
2007-07-25 23:16:30 +00:00
|
|
|
}
|
|
|
|
|
2011-06-07 01:02:55 +00:00
|
|
|
# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / sysconf(_SC_CLK_TCK))
|
|
|
|
|
|
|
|
int linuxNodeGetCPUStats(FILE *procstat,
|
|
|
|
int cpuNum,
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeCPUStatsPtr params,
|
2011-06-07 01:02:55 +00:00
|
|
|
int *nparams)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char line[1024];
|
|
|
|
unsigned long long usr, ni, sys, idle, iowait;
|
|
|
|
unsigned long long irq, softirq, steal, guest, guest_nice;
|
|
|
|
char cpu_header[3 + INT_BUFSIZE_BOUND(cpuNum)];
|
|
|
|
|
|
|
|
if ((*nparams) == 0) {
|
|
|
|
/* Current number of cpu stats supported by linux */
|
|
|
|
*nparams = LINUX_NB_CPU_STATS;
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*nparams) != LINUX_NB_CPU_STATS) {
|
Santize the reporting of VIR_ERR_INVALID_ERROR
To ensure consistent error reporting of invalid arguments,
provide a number of predefined helper methods & macros.
- An arg which must not be NULL:
virCheckNonNullArgReturn(argname, retvalue)
virCheckNonNullArgGoto(argname, label)
- An arg which must be NULL
virCheckNullArgGoto(argname, label)
- An arg which must be positive (ie 1 or greater)
virCheckPositiveArgGoto(argname, label)
- An arg which must not be 0
virCheckNonZeroArgGoto(argname, label)
- An arg which must be zero
virCheckZeroArgGoto(argname, label)
- An arg which must not be negative (ie 0 or greater)
virCheckNonNegativeArgGoto(argname, label)
* src/libvirt.c, src/libvirt-qemu.c,
src/nodeinfo.c, src/datatypes.c: Update to use
virCheckXXXX macros
* po/POTFILES.in: Add libvirt-qemu.c and virterror_internal.h
* src/internal.h: Define macros for checking invalid args
* src/util/virterror_internal.h: Define macros for reporting
invalid args
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-05-25 17:41:07 +00:00
|
|
|
virReportInvalidArg(*nparams,
|
|
|
|
_("nparams in %s must be equal to %d"),
|
|
|
|
__FUNCTION__, LINUX_NB_CPU_STATS);
|
2011-06-07 01:02:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-06-15 10:39:57 +00:00
|
|
|
if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS) {
|
2011-06-07 01:02:55 +00:00
|
|
|
strcpy(cpu_header, "cpu");
|
|
|
|
} else {
|
|
|
|
snprintf(cpu_header, sizeof(cpu_header), "cpu%d", cpuNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), procstat) != NULL) {
|
|
|
|
char *buf = line;
|
|
|
|
|
|
|
|
if (STRPREFIX(buf, cpu_header)) { /* aka logical CPU time */
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (sscanf(buf,
|
|
|
|
"%*s %llu %llu %llu %llu %llu" // user ~ iowait
|
|
|
|
"%llu %llu %llu %llu %llu", // irq ~ guest_nice
|
|
|
|
&usr, &ni, &sys, &idle, &iowait,
|
|
|
|
&irq, &softirq, &steal, &guest, &guest_nice) < 4) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < *nparams; i++) {
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeCPUStatsPtr param = ¶ms[i];
|
2011-06-07 01:02:55 +00:00
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
case 0: /* fill kernel cpu time here */
|
2011-06-15 10:39:57 +00:00
|
|
|
if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_KERNEL) == NULL) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Field kernel cpu time too long for destination"));
|
2011-06-07 01:02:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
param->value = (sys + irq + softirq) * TICK_TO_NSEC;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* fill user cpu time here */
|
2011-06-15 10:39:57 +00:00
|
|
|
if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_USER) == NULL) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Field kernel cpu time too long for destination"));
|
2011-06-07 01:02:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
param->value = (usr + ni) * TICK_TO_NSEC;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: /* fill idle cpu time here */
|
2011-06-15 10:39:57 +00:00
|
|
|
if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_IDLE) == NULL) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Field kernel cpu time too long for destination"));
|
2011-06-07 01:02:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
param->value = idle * TICK_TO_NSEC;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: /* fill iowait cpu time here */
|
2011-06-15 10:39:57 +00:00
|
|
|
if (virStrcpyStatic(param->field, VIR_NODE_CPU_STATS_IOWAIT) == NULL) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Field kernel cpu time too long for destination"));
|
2011-06-07 01:02:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
param->value = iowait * TICK_TO_NSEC;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
/* should not hit here */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Santize the reporting of VIR_ERR_INVALID_ERROR
To ensure consistent error reporting of invalid arguments,
provide a number of predefined helper methods & macros.
- An arg which must not be NULL:
virCheckNonNullArgReturn(argname, retvalue)
virCheckNonNullArgGoto(argname, label)
- An arg which must be NULL
virCheckNullArgGoto(argname, label)
- An arg which must be positive (ie 1 or greater)
virCheckPositiveArgGoto(argname, label)
- An arg which must not be 0
virCheckNonZeroArgGoto(argname, label)
- An arg which must be zero
virCheckZeroArgGoto(argname, label)
- An arg which must not be negative (ie 0 or greater)
virCheckNonNegativeArgGoto(argname, label)
* src/libvirt.c, src/libvirt-qemu.c,
src/nodeinfo.c, src/datatypes.c: Update to use
virCheckXXXX macros
* po/POTFILES.in: Add libvirt-qemu.c and virterror_internal.h
* src/internal.h: Define macros for checking invalid args
* src/util/virterror_internal.h: Define macros for reporting
invalid args
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-05-25 17:41:07 +00:00
|
|
|
virReportInvalidArg(cpuNum,
|
|
|
|
_("Invalid cpuNum in %s"),
|
|
|
|
__FUNCTION__);
|
2011-06-07 01:02:55 +00:00
|
|
|
|
2011-06-07 01:11:17 +00:00
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int linuxNodeGetMemoryStats(FILE *meminfo,
|
|
|
|
int cellNum,
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeMemoryStatsPtr params,
|
2011-06-07 01:11:17 +00:00
|
|
|
int *nparams)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int i = 0, j = 0, k = 0;
|
|
|
|
int found = 0;
|
|
|
|
int nr_param;
|
|
|
|
char line[1024];
|
2011-06-15 10:39:57 +00:00
|
|
|
char meminfo_hdr[VIR_NODE_MEMORY_STATS_FIELD_LENGTH];
|
2011-06-07 01:11:17 +00:00
|
|
|
unsigned long val;
|
|
|
|
struct field_conv {
|
|
|
|
const char *meminfo_hdr; // meminfo header
|
|
|
|
const char *field; // MemoryStats field name
|
|
|
|
} field_conv[] = {
|
2011-06-15 10:39:57 +00:00
|
|
|
{"MemTotal:", VIR_NODE_MEMORY_STATS_TOTAL},
|
|
|
|
{"MemFree:", VIR_NODE_MEMORY_STATS_FREE},
|
|
|
|
{"Buffers:", VIR_NODE_MEMORY_STATS_BUFFERS},
|
|
|
|
{"Cached:", VIR_NODE_MEMORY_STATS_CACHED},
|
2011-06-07 01:11:17 +00:00
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2011-06-15 10:39:57 +00:00
|
|
|
if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) {
|
2011-06-07 01:11:17 +00:00
|
|
|
nr_param = LINUX_NB_MEMORY_STATS_ALL;
|
|
|
|
} else {
|
|
|
|
nr_param = LINUX_NB_MEMORY_STATS_CELL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*nparams) == 0) {
|
|
|
|
/* Current number of memory stats supported by linux */
|
|
|
|
*nparams = nr_param;
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((*nparams) != nr_param) {
|
Santize the reporting of VIR_ERR_INVALID_ERROR
To ensure consistent error reporting of invalid arguments,
provide a number of predefined helper methods & macros.
- An arg which must not be NULL:
virCheckNonNullArgReturn(argname, retvalue)
virCheckNonNullArgGoto(argname, label)
- An arg which must be NULL
virCheckNullArgGoto(argname, label)
- An arg which must be positive (ie 1 or greater)
virCheckPositiveArgGoto(argname, label)
- An arg which must not be 0
virCheckNonZeroArgGoto(argname, label)
- An arg which must be zero
virCheckZeroArgGoto(argname, label)
- An arg which must not be negative (ie 0 or greater)
virCheckNonNegativeArgGoto(argname, label)
* src/libvirt.c, src/libvirt-qemu.c,
src/nodeinfo.c, src/datatypes.c: Update to use
virCheckXXXX macros
* po/POTFILES.in: Add libvirt-qemu.c and virterror_internal.h
* src/internal.h: Define macros for checking invalid args
* src/util/virterror_internal.h: Define macros for reporting
invalid args
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-05-25 17:41:07 +00:00
|
|
|
virReportInvalidArg(nparams,
|
|
|
|
_("nparams in %s must be %d"),
|
|
|
|
__FUNCTION__, nr_param);
|
2011-06-07 01:11:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), meminfo) != NULL) {
|
|
|
|
char *buf = line;
|
|
|
|
|
|
|
|
if (STRPREFIX(buf, "Node ")) {
|
|
|
|
/*
|
|
|
|
* /sys/devices/system/node/nodeX/meminfo format is below.
|
|
|
|
* So, skip prefix "Node XX ".
|
|
|
|
*
|
|
|
|
* Node 0 MemTotal: 8386980 kB
|
|
|
|
* Node 0 MemFree: 5300920 kB
|
|
|
|
* :
|
|
|
|
*/
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
p = buf;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
p = strchr(p, ' ');
|
|
|
|
if (p == NULL) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no prefix found"));
|
2011-06-07 01:11:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
buf = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(buf, "%s %lu kB", meminfo_hdr, &val) < 2)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; field_conv[j].meminfo_hdr != NULL; j++) {
|
|
|
|
struct field_conv *convp = &field_conv[j];
|
|
|
|
|
|
|
|
if (STREQ(meminfo_hdr, convp->meminfo_hdr)) {
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeMemoryStatsPtr param = ¶ms[k++];
|
2011-06-07 01:11:17 +00:00
|
|
|
|
|
|
|
if (virStrcpyStatic(param->field, convp->field) == NULL) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Field kernel memory too long for destination"));
|
2011-06-07 01:11:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
param->value = val;
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found >= nr_param)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found == 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("no available memory line found"));
|
2011-06-07 01:11:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2011-06-07 01:02:55 +00:00
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
2012-03-02 02:54:22 +00:00
|
|
|
|
2012-10-24 22:43:26 +00:00
|
|
|
|
|
|
|
/* Determine the maximum cpu id from a Linux sysfs cpu/present file. */
|
|
|
|
static int
|
|
|
|
linuxParseCPUmax(const char *path)
|
|
|
|
{
|
|
|
|
char *str = NULL;
|
|
|
|
char *tmp;
|
|
|
|
int ret = -1;
|
|
|
|
|
2012-11-15 14:04:33 +00:00
|
|
|
if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0)
|
2012-10-24 22:43:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
tmp = str;
|
|
|
|
do {
|
|
|
|
if (virStrToLong_i(tmp, &tmp, 10, &ret) < 0 ||
|
|
|
|
!strchr(",-\n", *tmp)) {
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT,
|
|
|
|
_("failed to parse %s"), path);
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} while (*tmp++ != '\n');
|
|
|
|
ret++;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(str);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-02 02:54:22 +00:00
|
|
|
/*
|
2012-10-24 22:43:26 +00:00
|
|
|
* Linux maintains cpu bit map under cpu/online. For example, if
|
|
|
|
* cpuid=5's flag is not set and max cpu is 7, the map file shows
|
|
|
|
* 0-4,6-7. This function parses it and returns cpumap.
|
2012-03-02 02:54:22 +00:00
|
|
|
*/
|
2012-09-14 07:47:03 +00:00
|
|
|
static virBitmapPtr
|
2012-10-24 22:43:26 +00:00
|
|
|
linuxParseCPUmap(int max_cpuid, const char *path)
|
2012-03-02 02:54:22 +00:00
|
|
|
{
|
2012-09-14 07:47:03 +00:00
|
|
|
virBitmapPtr map = NULL;
|
2012-03-02 02:54:22 +00:00
|
|
|
char *str = NULL;
|
|
|
|
|
|
|
|
if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2012-10-24 22:43:26 +00:00
|
|
|
if (virBitmapParse(str, 0, &map, max_cpuid) < 0)
|
2012-03-02 02:54:22 +00:00
|
|
|
goto error;
|
|
|
|
|
2012-04-24 08:55:06 +00:00
|
|
|
VIR_FREE(str);
|
2012-03-02 02:54:22 +00:00
|
|
|
return map;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(str);
|
2012-09-14 07:47:03 +00:00
|
|
|
virBitmapFree(map);
|
2012-03-02 02:54:22 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-07-25 23:16:30 +00:00
|
|
|
#endif
|
|
|
|
|
2012-12-10 21:58:16 +00:00
|
|
|
int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo)
|
|
|
|
{
|
|
|
|
virArch hostarch = virArchFromHost();
|
2009-01-20 17:13:33 +00:00
|
|
|
|
2012-12-10 21:58:16 +00:00
|
|
|
if (virStrcpyStatic(nodeinfo->model, virArchToString(hostarch)) == NULL)
|
2009-08-03 12:37:44 +00:00
|
|
|
return -1;
|
2007-12-07 14:45:39 +00:00
|
|
|
|
2007-07-25 23:16:30 +00:00
|
|
|
#ifdef __linux__
|
Use gnulib, starting with its physmem and getaddrinfo modules.
New files go into these directories:
gnulib/lib
gnulib/m4
gnulib/tests
* bootstrap: A wrapper around gnulib-tool.
* configure.in: Invoke gl_EARLY and gl_INIT, being careful to put gl_EARLY
before any macro that uses AC_COMPILE_IFELSE.
(AC_OUTPUT): Add lib/Makefile and gl-tests/Makefile. Remove m4/Makefile.
* Makefile.am (SUBDIRS): Add gnulib/lib and remove m4. Add gnulib/tests
early enough that those tests run before any libvirt unit tests.
* m4/Makefile.am: Remove file. Not needed.
* src/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS, libvirt_la_LIBADD): Add ../gnulib/lib/libgnu.la.
* src/nodeinfo.c: Include "physmem.h".
* qemud/qemud.c, src/remote_internal.c: Include "getaddrinfo.h".
(MEMINFO_PATH, linuxNodeInfoMemPopulate): Remove definitions.
(virNodeInfoPopulate): Use physmem_total, not linuxNodeInfoMemPopulate.
* tests/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS): Add ../gnulib/lib/libgnu.la.
* qemud/Makefile.am (libvirtd_LDADD): Add ../gnulib/lib/libgnu.la.
* tests/nodeinfotest.c (linuxTestCompareFiles): No longer read total
memory from a file.
Update expected output not to include "Memory: NNNN"
* tests/nodeinfodata/linux-nodeinfo-1.txt:
* tests/nodeinfodata/linux-nodeinfo-2.txt:
* tests/nodeinfodata/linux-nodeinfo-3.txt:
* tests/nodeinfodata/linux-nodeinfo-4.txt:
* tests/nodeinfodata/linux-nodeinfo-5.txt:
* tests/nodeinfodata/linux-nodeinfo-6.txt:
* src/test.c [WITH_TEST]: Remove definition of _GNU_SOURCE that
would conflict with the one now in "config.h".
* autogen.sh: Add -I gnulib/m4.
* src/conf.c, src/sexpr.c: Don't define _GNU_SOURCE.
Instead, include "config.h".
* qemud/qemud.c: Remove definition of _GNU_SOURCE.
* src/openvz_driver.c: Likewise.
* src/qemu_driver.c: Likewise.
* src/remote_internal.c: Likewise.
* configure.in: Use AC_CONFIG_AUX_DIR(build-aux), so that a bunch
of gettextize-generated files go into build-aux/, rather than in
the top-level directory.
* .cvsignore: Adjust.
* build-aux/.cvsignore: New file.
Author: Jim Meyering <meyering@redhat.com>
2007-12-05 21:31:07 +00:00
|
|
|
{
|
2012-05-02 15:18:03 +00:00
|
|
|
int ret = -1;
|
Use gnulib, starting with its physmem and getaddrinfo modules.
New files go into these directories:
gnulib/lib
gnulib/m4
gnulib/tests
* bootstrap: A wrapper around gnulib-tool.
* configure.in: Invoke gl_EARLY and gl_INIT, being careful to put gl_EARLY
before any macro that uses AC_COMPILE_IFELSE.
(AC_OUTPUT): Add lib/Makefile and gl-tests/Makefile. Remove m4/Makefile.
* Makefile.am (SUBDIRS): Add gnulib/lib and remove m4. Add gnulib/tests
early enough that those tests run before any libvirt unit tests.
* m4/Makefile.am: Remove file. Not needed.
* src/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS, libvirt_la_LIBADD): Add ../gnulib/lib/libgnu.la.
* src/nodeinfo.c: Include "physmem.h".
* qemud/qemud.c, src/remote_internal.c: Include "getaddrinfo.h".
(MEMINFO_PATH, linuxNodeInfoMemPopulate): Remove definitions.
(virNodeInfoPopulate): Use physmem_total, not linuxNodeInfoMemPopulate.
* tests/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS): Add ../gnulib/lib/libgnu.la.
* qemud/Makefile.am (libvirtd_LDADD): Add ../gnulib/lib/libgnu.la.
* tests/nodeinfotest.c (linuxTestCompareFiles): No longer read total
memory from a file.
Update expected output not to include "Memory: NNNN"
* tests/nodeinfodata/linux-nodeinfo-1.txt:
* tests/nodeinfodata/linux-nodeinfo-2.txt:
* tests/nodeinfodata/linux-nodeinfo-3.txt:
* tests/nodeinfodata/linux-nodeinfo-4.txt:
* tests/nodeinfodata/linux-nodeinfo-5.txt:
* tests/nodeinfodata/linux-nodeinfo-6.txt:
* src/test.c [WITH_TEST]: Remove definition of _GNU_SOURCE that
would conflict with the one now in "config.h".
* autogen.sh: Add -I gnulib/m4.
* src/conf.c, src/sexpr.c: Don't define _GNU_SOURCE.
Instead, include "config.h".
* qemud/qemud.c: Remove definition of _GNU_SOURCE.
* src/openvz_driver.c: Likewise.
* src/qemu_driver.c: Likewise.
* src/remote_internal.c: Likewise.
* configure.in: Use AC_CONFIG_AUX_DIR(build-aux), so that a bunch
of gettextize-generated files go into build-aux/, rather than in
the top-level directory.
* .cvsignore: Adjust.
* build-aux/.cvsignore: New file.
Author: Jim Meyering <meyering@redhat.com>
2007-12-05 21:31:07 +00:00
|
|
|
FILE *cpuinfo = fopen(CPUINFO_PATH, "r");
|
2007-07-25 23:16:30 +00:00
|
|
|
if (!cpuinfo) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot open %s"), CPUINFO_PATH);
|
2007-07-25 23:16:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2011-10-03 12:45:30 +00:00
|
|
|
|
2012-05-11 19:59:59 +00:00
|
|
|
ret = linuxNodeInfoCPUPopulate(cpuinfo, SYSFS_SYSTEM_PATH, nodeinfo);
|
2012-05-02 15:18:03 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
2007-07-25 23:16:30 +00:00
|
|
|
|
Use gnulib, starting with its physmem and getaddrinfo modules.
New files go into these directories:
gnulib/lib
gnulib/m4
gnulib/tests
* bootstrap: A wrapper around gnulib-tool.
* configure.in: Invoke gl_EARLY and gl_INIT, being careful to put gl_EARLY
before any macro that uses AC_COMPILE_IFELSE.
(AC_OUTPUT): Add lib/Makefile and gl-tests/Makefile. Remove m4/Makefile.
* Makefile.am (SUBDIRS): Add gnulib/lib and remove m4. Add gnulib/tests
early enough that those tests run before any libvirt unit tests.
* m4/Makefile.am: Remove file. Not needed.
* src/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS, libvirt_la_LIBADD): Add ../gnulib/lib/libgnu.la.
* src/nodeinfo.c: Include "physmem.h".
* qemud/qemud.c, src/remote_internal.c: Include "getaddrinfo.h".
(MEMINFO_PATH, linuxNodeInfoMemPopulate): Remove definitions.
(virNodeInfoPopulate): Use physmem_total, not linuxNodeInfoMemPopulate.
* tests/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS): Add ../gnulib/lib/libgnu.la.
* qemud/Makefile.am (libvirtd_LDADD): Add ../gnulib/lib/libgnu.la.
* tests/nodeinfotest.c (linuxTestCompareFiles): No longer read total
memory from a file.
Update expected output not to include "Memory: NNNN"
* tests/nodeinfodata/linux-nodeinfo-1.txt:
* tests/nodeinfodata/linux-nodeinfo-2.txt:
* tests/nodeinfodata/linux-nodeinfo-3.txt:
* tests/nodeinfodata/linux-nodeinfo-4.txt:
* tests/nodeinfodata/linux-nodeinfo-5.txt:
* tests/nodeinfodata/linux-nodeinfo-6.txt:
* src/test.c [WITH_TEST]: Remove definition of _GNU_SOURCE that
would conflict with the one now in "config.h".
* autogen.sh: Add -I gnulib/m4.
* src/conf.c, src/sexpr.c: Don't define _GNU_SOURCE.
Instead, include "config.h".
* qemud/qemud.c: Remove definition of _GNU_SOURCE.
* src/openvz_driver.c: Likewise.
* src/qemu_driver.c: Likewise.
* src/remote_internal.c: Likewise.
* configure.in: Use AC_CONFIG_AUX_DIR(build-aux), so that a bunch
of gettextize-generated files go into build-aux/, rather than in
the top-level directory.
* .cvsignore: Adjust.
* build-aux/.cvsignore: New file.
Author: Jim Meyering <meyering@redhat.com>
2007-12-05 21:31:07 +00:00
|
|
|
/* Convert to KB. */
|
2012-10-17 09:23:12 +00:00
|
|
|
nodeinfo->memory = physmem_total() / 1024;
|
2007-07-25 23:16:30 +00:00
|
|
|
|
2012-05-02 15:18:03 +00:00
|
|
|
cleanup:
|
|
|
|
VIR_FORCE_FCLOSE(cpuinfo);
|
2007-07-25 23:16:30 +00:00
|
|
|
return ret;
|
Use gnulib, starting with its physmem and getaddrinfo modules.
New files go into these directories:
gnulib/lib
gnulib/m4
gnulib/tests
* bootstrap: A wrapper around gnulib-tool.
* configure.in: Invoke gl_EARLY and gl_INIT, being careful to put gl_EARLY
before any macro that uses AC_COMPILE_IFELSE.
(AC_OUTPUT): Add lib/Makefile and gl-tests/Makefile. Remove m4/Makefile.
* Makefile.am (SUBDIRS): Add gnulib/lib and remove m4. Add gnulib/tests
early enough that those tests run before any libvirt unit tests.
* m4/Makefile.am: Remove file. Not needed.
* src/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS, libvirt_la_LIBADD): Add ../gnulib/lib/libgnu.la.
* src/nodeinfo.c: Include "physmem.h".
* qemud/qemud.c, src/remote_internal.c: Include "getaddrinfo.h".
(MEMINFO_PATH, linuxNodeInfoMemPopulate): Remove definitions.
(virNodeInfoPopulate): Use physmem_total, not linuxNodeInfoMemPopulate.
* tests/Makefile.am (INCLUDES): Add -I$(top_srcdir)/gnulib/lib -I../gnulib/lib.
(LDADDS): Add ../gnulib/lib/libgnu.la.
* qemud/Makefile.am (libvirtd_LDADD): Add ../gnulib/lib/libgnu.la.
* tests/nodeinfotest.c (linuxTestCompareFiles): No longer read total
memory from a file.
Update expected output not to include "Memory: NNNN"
* tests/nodeinfodata/linux-nodeinfo-1.txt:
* tests/nodeinfodata/linux-nodeinfo-2.txt:
* tests/nodeinfodata/linux-nodeinfo-3.txt:
* tests/nodeinfodata/linux-nodeinfo-4.txt:
* tests/nodeinfodata/linux-nodeinfo-5.txt:
* tests/nodeinfodata/linux-nodeinfo-6.txt:
* src/test.c [WITH_TEST]: Remove definition of _GNU_SOURCE that
would conflict with the one now in "config.h".
* autogen.sh: Add -I gnulib/m4.
* src/conf.c, src/sexpr.c: Don't define _GNU_SOURCE.
Instead, include "config.h".
* qemud/qemud.c: Remove definition of _GNU_SOURCE.
* src/openvz_driver.c: Likewise.
* src/qemu_driver.c: Likewise.
* src/remote_internal.c: Likewise.
* configure.in: Use AC_CONFIG_AUX_DIR(build-aux), so that a bunch
of gettextize-generated files go into build-aux/, rather than in
the top-level directory.
* .cvsignore: Adjust.
* build-aux/.cvsignore: New file.
Author: Jim Meyering <meyering@redhat.com>
2007-12-05 21:31:07 +00:00
|
|
|
}
|
2012-12-17 18:12:44 +00:00
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
{
|
|
|
|
nodeinfo->nodes = 1;
|
|
|
|
nodeinfo->sockets = 1;
|
|
|
|
nodeinfo->threads = 1;
|
|
|
|
|
|
|
|
nodeinfo->cpus = freebsdNodeGetCPUCount();
|
|
|
|
if (nodeinfo->cpus == -1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nodeinfo->cores = nodeinfo->cpus;
|
|
|
|
|
|
|
|
unsigned long cpu_freq;
|
|
|
|
size_t cpu_freq_len = sizeof(cpu_freq);
|
|
|
|
|
|
|
|
if (sysctlbyname("dev.cpu.0.freq", &cpu_freq, &cpu_freq_len, NULL, 0) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("cannot obtain CPU freq"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeinfo->mhz = cpu_freq;
|
|
|
|
|
|
|
|
/* get memory information */
|
|
|
|
int mib[2] = { CTL_HW, HW_PHYSMEM };
|
|
|
|
unsigned long physmem;
|
|
|
|
size_t len = sizeof(physmem);
|
|
|
|
|
|
|
|
if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {
|
|
|
|
virReportSystemError(errno, "%s", _("cannot obtain memory size"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeinfo->memory = (unsigned long)(physmem / 1024);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2007-07-25 23:16:30 +00:00
|
|
|
#else
|
|
|
|
/* XXX Solaris will need an impl later if they port QEMU driver */
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node info not implemented on this platform"));
|
2007-07-25 23:16:30 +00:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
|
2011-06-07 01:02:55 +00:00
|
|
|
int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2011-06-15 17:21:28 +00:00
|
|
|
int cpuNum ATTRIBUTE_UNUSED,
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeCPUStatsPtr params ATTRIBUTE_UNUSED,
|
2011-06-15 17:21:28 +00:00
|
|
|
int *nparams ATTRIBUTE_UNUSED,
|
2011-06-07 01:02:55 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
FILE *procstat = fopen(PROCSTAT_PATH, "r");
|
|
|
|
if (!procstat) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot open %s"), PROCSTAT_PATH);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ret = linuxNodeGetCPUStats(procstat, cpuNum, params, nparams);
|
|
|
|
VIR_FORCE_FCLOSE(procstat);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node CPU stats not implemented on this platform"));
|
2011-06-07 01:02:55 +00:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-06-07 01:11:17 +00:00
|
|
|
int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2011-06-15 17:21:28 +00:00
|
|
|
int cellNum ATTRIBUTE_UNUSED,
|
2011-06-15 10:39:57 +00:00
|
|
|
virNodeMemoryStatsPtr params ATTRIBUTE_UNUSED,
|
2011-06-15 17:21:28 +00:00
|
|
|
int *nparams ATTRIBUTE_UNUSED,
|
2011-06-07 01:11:17 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *meminfo_path = NULL;
|
|
|
|
FILE *meminfo;
|
|
|
|
|
2011-06-15 10:39:57 +00:00
|
|
|
if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) {
|
2011-06-07 01:11:17 +00:00
|
|
|
meminfo_path = strdup(MEMINFO_PATH);
|
|
|
|
if (!meminfo_path) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2011-06-20 08:39:09 +00:00
|
|
|
# if HAVE_NUMACTL
|
2011-06-07 01:11:17 +00:00
|
|
|
if (numa_available() < 0) {
|
2011-06-20 08:39:09 +00:00
|
|
|
# endif
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("NUMA not supported on this host"));
|
2011-06-07 01:11:17 +00:00
|
|
|
return -1;
|
2011-06-20 08:39:09 +00:00
|
|
|
# if HAVE_NUMACTL
|
2011-06-07 01:11:17 +00:00
|
|
|
}
|
2011-06-20 08:39:09 +00:00
|
|
|
# endif
|
2011-06-07 01:11:17 +00:00
|
|
|
|
2011-06-20 08:39:09 +00:00
|
|
|
# if HAVE_NUMACTL
|
2011-06-07 01:11:17 +00:00
|
|
|
if (cellNum > numa_max_node()) {
|
Santize the reporting of VIR_ERR_INVALID_ERROR
To ensure consistent error reporting of invalid arguments,
provide a number of predefined helper methods & macros.
- An arg which must not be NULL:
virCheckNonNullArgReturn(argname, retvalue)
virCheckNonNullArgGoto(argname, label)
- An arg which must be NULL
virCheckNullArgGoto(argname, label)
- An arg which must be positive (ie 1 or greater)
virCheckPositiveArgGoto(argname, label)
- An arg which must not be 0
virCheckNonZeroArgGoto(argname, label)
- An arg which must be zero
virCheckZeroArgGoto(argname, label)
- An arg which must not be negative (ie 0 or greater)
virCheckNonNegativeArgGoto(argname, label)
* src/libvirt.c, src/libvirt-qemu.c,
src/nodeinfo.c, src/datatypes.c: Update to use
virCheckXXXX macros
* po/POTFILES.in: Add libvirt-qemu.c and virterror_internal.h
* src/internal.h: Define macros for checking invalid args
* src/util/virterror_internal.h: Define macros for reporting
invalid args
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-05-25 17:41:07 +00:00
|
|
|
virReportInvalidArg(cellNum,
|
|
|
|
_("cellNum in %s must be less than or equal to %d"),
|
|
|
|
__FUNCTION__, numa_max_node());
|
2011-06-07 01:11:17 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2011-06-20 08:39:09 +00:00
|
|
|
# endif
|
2011-06-07 01:11:17 +00:00
|
|
|
|
2012-05-11 19:59:59 +00:00
|
|
|
if (virAsprintf(&meminfo_path, "%s/node/node%d/meminfo",
|
|
|
|
SYSFS_SYSTEM_PATH, cellNum) < 0) {
|
2011-06-07 01:11:17 +00:00
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
meminfo = fopen(meminfo_path, "r");
|
|
|
|
|
|
|
|
if (!meminfo) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("cannot open %s"), meminfo_path);
|
|
|
|
VIR_FREE(meminfo_path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ret = linuxNodeGetMemoryStats(meminfo, cellNum, params, nparams);
|
|
|
|
VIR_FORCE_FCLOSE(meminfo);
|
|
|
|
VIR_FREE(meminfo_path);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#else
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node memory stats not implemented on this platform"));
|
2011-06-07 01:11:17 +00:00
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-10-25 20:44:32 +00:00
|
|
|
int
|
|
|
|
nodeGetCPUCount(void)
|
|
|
|
{
|
2012-12-17 18:12:44 +00:00
|
|
|
#if defined(__linux__)
|
2012-11-13 12:54:36 +00:00
|
|
|
/* To support older kernels that lack cpu/present, such as 2.6.18
|
|
|
|
* in RHEL5, we fall back to count cpu/cpuNN entries; this assumes
|
|
|
|
* that such kernels also lack hotplug, and therefore cpu/cpuNN
|
|
|
|
* will be consecutive.
|
|
|
|
*/
|
|
|
|
char *cpupath = NULL;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (virFileExists(SYSFS_SYSTEM_PATH "/cpu/present")) {
|
|
|
|
i = linuxParseCPUmax(SYSFS_SYSTEM_PATH "/cpu/present");
|
|
|
|
} else if (virFileExists(SYSFS_SYSTEM_PATH "/cpu/cpu0")) {
|
|
|
|
do {
|
|
|
|
i++;
|
|
|
|
VIR_FREE(cpupath);
|
|
|
|
if (virAsprintf(&cpupath, "%s/cpu/cpu%d",
|
|
|
|
SYSFS_SYSTEM_PATH, i) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} while (virFileExists(cpupath));
|
|
|
|
} else {
|
|
|
|
/* no cpu/cpu0: we give up */
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("host cpu counting not supported on this node"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(cpupath);
|
|
|
|
return i;
|
2012-12-17 18:12:44 +00:00
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
return freebsdNodeGetCPUCount();
|
2012-10-25 20:44:32 +00:00
|
|
|
#else
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("host cpu counting not implemented on this platform"));
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-09-14 07:47:03 +00:00
|
|
|
virBitmapPtr
|
2012-10-25 20:44:32 +00:00
|
|
|
nodeGetCPUBitmap(int *max_id ATTRIBUTE_UNUSED)
|
2012-03-02 02:54:22 +00:00
|
|
|
{
|
|
|
|
#ifdef __linux__
|
2012-09-14 07:47:03 +00:00
|
|
|
virBitmapPtr cpumap;
|
2012-10-24 22:43:26 +00:00
|
|
|
int present;
|
|
|
|
|
2012-11-15 14:04:33 +00:00
|
|
|
present = nodeGetCPUCount();
|
2012-10-24 22:43:26 +00:00
|
|
|
if (present < 0)
|
2012-03-02 02:54:22 +00:00
|
|
|
return NULL;
|
2012-11-15 14:04:33 +00:00
|
|
|
|
|
|
|
if (virFileExists(SYSFS_SYSTEM_PATH "/cpu/online")) {
|
|
|
|
cpumap = linuxParseCPUmap(present, SYSFS_SYSTEM_PATH "/cpu/online");
|
|
|
|
} else {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cpumap = virBitmapNew(present);
|
|
|
|
if (!cpumap) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
for (i = 0; i < present; i++) {
|
|
|
|
int online = virNodeGetCpuValue(SYSFS_SYSTEM_PATH, i, "online", 1);
|
|
|
|
if (online < 0) {
|
|
|
|
virBitmapFree(cpumap);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (online)
|
|
|
|
ignore_value(virBitmapSetBit(cpumap, i));
|
|
|
|
}
|
|
|
|
}
|
2012-10-24 22:43:26 +00:00
|
|
|
if (max_id && cpumap)
|
|
|
|
*max_id = present;
|
2012-03-02 02:54:22 +00:00
|
|
|
return cpumap;
|
|
|
|
#else
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node cpumap not implemented on this platform"));
|
2012-03-02 02:54:22 +00:00
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-09-18 23:04:50 +00:00
|
|
|
#ifdef __linux__
|
2012-09-14 14:42:16 +00:00
|
|
|
static int
|
2012-11-28 14:11:06 +00:00
|
|
|
nodeSetMemoryParameterValue(virTypedParameterPtr param)
|
2012-09-14 14:42:16 +00:00
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
char *strval = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
int rc = -1;
|
|
|
|
|
2012-11-28 14:11:06 +00:00
|
|
|
char *field = strchr(param->field, '_');
|
|
|
|
field++;
|
2012-09-14 14:42:16 +00:00
|
|
|
if (virAsprintf(&path, "%s/%s",
|
|
|
|
SYSFS_MEMORY_SHARED_PATH, field) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
ret = -2;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virAsprintf(&strval, "%u", param->value.ui) == -1) {
|
|
|
|
virReportOOMError();
|
|
|
|
ret = -2;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rc = virFileWriteStr(path, strval, 0)) < 0) {
|
2012-11-28 14:11:06 +00:00
|
|
|
virReportSystemError(-rc, _("failed to set %s"), param->field);
|
2012-09-14 14:42:16 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(path);
|
|
|
|
VIR_FREE(strval);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-11-28 14:11:06 +00:00
|
|
|
|
|
|
|
static bool
|
|
|
|
nodeMemoryParametersIsAllSupported(virTypedParameterPtr params,
|
|
|
|
int nparams)
|
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
|
|
|
|
|
|
|
char *field = strchr(param->field, '_');
|
|
|
|
field++;
|
|
|
|
if (virAsprintf(&path, "%s/%s",
|
|
|
|
SYSFS_MEMORY_SHARED_PATH, field) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virFileExists(path)) {
|
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("Parameter '%s' is not supported by "
|
|
|
|
"this kernel"), param->field);
|
|
|
|
VIR_FREE(path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2012-09-18 23:04:50 +00:00
|
|
|
#endif
|
2012-09-14 14:42:16 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2012-09-17 14:05:48 +00:00
|
|
|
virTypedParameterPtr params ATTRIBUTE_UNUSED,
|
|
|
|
int nparams ATTRIBUTE_UNUSED,
|
2012-09-14 14:42:16 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
int i;
|
2012-11-28 14:11:06 +00:00
|
|
|
int rc;
|
2012-09-14 14:42:16 +00:00
|
|
|
|
|
|
|
if (virTypedParameterArrayValidate(params, nparams,
|
|
|
|
VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN,
|
|
|
|
VIR_TYPED_PARAM_UINT,
|
|
|
|
VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS,
|
|
|
|
VIR_TYPED_PARAM_UINT,
|
2012-10-12 08:25:42 +00:00
|
|
|
VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
|
|
|
|
VIR_TYPED_PARAM_UINT,
|
2012-09-14 14:42:16 +00:00
|
|
|
NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2012-11-28 14:11:06 +00:00
|
|
|
if (!nodeMemoryParametersIsAllSupported(params, nparams))
|
|
|
|
return -1;
|
2012-09-14 14:42:16 +00:00
|
|
|
|
2012-11-28 14:11:06 +00:00
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
rc = nodeSetMemoryParameterValue(¶ms[i]);
|
2012-10-12 08:25:42 +00:00
|
|
|
|
2012-11-28 14:11:06 +00:00
|
|
|
/* Out of memory */
|
|
|
|
if (rc == -2)
|
|
|
|
return -1;
|
2012-09-14 14:42:16 +00:00
|
|
|
}
|
|
|
|
|
2012-11-28 14:11:06 +00:00
|
|
|
return 0;
|
2012-09-14 14:42:16 +00:00
|
|
|
#else
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node set memory parameters not implemented"
|
|
|
|
" on this platform"));
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-09-18 23:04:50 +00:00
|
|
|
#ifdef __linux__
|
2012-09-14 14:42:16 +00:00
|
|
|
static int
|
|
|
|
nodeGetMemoryParameterValue(const char *field,
|
|
|
|
void *value)
|
|
|
|
{
|
|
|
|
char *path = NULL;
|
|
|
|
char *buf = NULL;
|
|
|
|
char *tmp = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
int rc = -1;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "%s/%s",
|
|
|
|
SYSFS_MEMORY_SHARED_PATH, field) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-11-28 14:11:06 +00:00
|
|
|
if (!virFileExists(path)) {
|
|
|
|
ret = -2;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-09-14 14:42:16 +00:00
|
|
|
if (virFileReadAll(path, 1024, &buf) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((tmp = strchr(buf, '\n')))
|
|
|
|
*tmp = '\0';
|
|
|
|
|
2012-10-12 08:25:42 +00:00
|
|
|
if (STREQ(field, "pages_to_scan") ||
|
|
|
|
STREQ(field, "sleep_millisecs") ||
|
|
|
|
STREQ(field, "merge_across_nodes"))
|
2012-09-14 14:42:16 +00:00
|
|
|
rc = virStrToLong_ui(buf, NULL, 10, (unsigned int *)value);
|
|
|
|
else if (STREQ(field, "pages_shared") ||
|
|
|
|
STREQ(field, "pages_sharing") ||
|
|
|
|
STREQ(field, "pages_unshared") ||
|
|
|
|
STREQ(field, "pages_volatile") ||
|
|
|
|
STREQ(field, "full_scans"))
|
|
|
|
rc = virStrToLong_ull(buf, NULL, 10, (unsigned long long *)value);
|
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("failed to parse %s"), field);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(path);
|
|
|
|
VIR_FREE(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-09-18 23:04:50 +00:00
|
|
|
#endif
|
2012-09-14 14:42:16 +00:00
|
|
|
|
2012-10-12 08:25:42 +00:00
|
|
|
#define NODE_MEMORY_PARAMETERS_NUM 8
|
2012-09-14 14:42:16 +00:00
|
|
|
int
|
|
|
|
nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2012-09-17 14:05:48 +00:00
|
|
|
virTypedParameterPtr params ATTRIBUTE_UNUSED,
|
|
|
|
int *nparams ATTRIBUTE_UNUSED,
|
2012-09-14 14:42:16 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
unsigned int pages_to_scan;
|
|
|
|
unsigned int sleep_millisecs;
|
2012-10-12 08:25:42 +00:00
|
|
|
unsigned int merge_across_nodes;
|
2012-09-14 14:42:16 +00:00
|
|
|
unsigned long long pages_shared;
|
|
|
|
unsigned long long pages_sharing;
|
|
|
|
unsigned long long pages_unshared;
|
|
|
|
unsigned long long pages_volatile;
|
|
|
|
unsigned long long full_scans = 0;
|
|
|
|
int i;
|
2012-11-28 14:11:06 +00:00
|
|
|
int ret;
|
2012-09-14 14:42:16 +00:00
|
|
|
|
|
|
|
if ((*nparams) == 0) {
|
|
|
|
*nparams = NODE_MEMORY_PARAMETERS_NUM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < *nparams && i < NODE_MEMORY_PARAMETERS_NUM; i++) {
|
|
|
|
virTypedParameterPtr param = ¶ms[i];
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
switch (i) {
|
2012-09-14 14:42:16 +00:00
|
|
|
case 0:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("pages_to_scan", &pages_to_scan);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN,
|
|
|
|
VIR_TYPED_PARAM_UINT, pages_to_scan) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("sleep_millisecs", &sleep_millisecs);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS,
|
|
|
|
VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("pages_shared", &pages_shared);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, pages_shared) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("pages_sharing", &pages_sharing);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("pages_unshared", &pages_unshared);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("pages_volatile", &pages_volatile);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 6:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("full_scans", &full_scans);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-09-14 14:42:16 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS,
|
|
|
|
VIR_TYPED_PARAM_ULLONG, full_scans) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2012-10-12 08:25:42 +00:00
|
|
|
case 7:
|
2012-11-28 14:11:06 +00:00
|
|
|
ret = nodeGetMemoryParameterValue("merge_across_nodes", &merge_across_nodes);
|
|
|
|
if (ret == -2)
|
|
|
|
continue;
|
|
|
|
else if (ret == -1)
|
2012-10-12 08:25:42 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
|
|
|
|
VIR_TYPED_PARAM_UINT, merge_across_nodes) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2012-09-14 14:42:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("node get memory parameters not implemented"
|
|
|
|
" on this platform"));
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-10-25 20:44:32 +00:00
|
|
|
int
|
|
|
|
nodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
|
|
unsigned char **cpumap,
|
|
|
|
unsigned int *online,
|
|
|
|
unsigned int flags)
|
2012-10-16 14:05:14 +00:00
|
|
|
{
|
|
|
|
virBitmapPtr cpus = NULL;
|
|
|
|
int maxpresent;
|
|
|
|
int ret = -1;
|
|
|
|
int dummy;
|
|
|
|
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2012-11-01 23:55:43 +00:00
|
|
|
if (!cpumap && !online)
|
|
|
|
return nodeGetCPUCount();
|
|
|
|
|
2012-10-25 20:44:32 +00:00
|
|
|
if (!(cpus = nodeGetCPUBitmap(&maxpresent)))
|
2012-10-16 14:05:14 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (cpumap && virBitmapToData(cpus, cpumap, &dummy) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (online)
|
|
|
|
*online = virBitmapCountBits(cpus);
|
|
|
|
|
|
|
|
ret = maxpresent;
|
|
|
|
cleanup:
|
|
|
|
if (ret < 0 && cpumap)
|
|
|
|
VIR_FREE(*cpumap);
|
|
|
|
virBitmapFree(cpus);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#if HAVE_NUMACTL
|
|
|
|
# if LIBNUMA_API_VERSION <= 1
|
|
|
|
# define NUMA_MAX_N_CPUS 4096
|
|
|
|
# else
|
|
|
|
# define NUMA_MAX_N_CPUS (numa_all_cpus_ptr->size)
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# define n_bits(var) (8 * sizeof(var))
|
|
|
|
# define MASK_CPU_ISSET(mask, cpu) \
|
|
|
|
(((mask)[((cpu) / n_bits(*(mask)))] >> ((cpu) % n_bits(*(mask)))) & 1)
|
|
|
|
|
|
|
|
int
|
2009-06-03 13:28:02 +00:00
|
|
|
nodeCapsInitNUMA(virCapsPtr caps)
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
{
|
|
|
|
int n;
|
2009-01-05 12:56:36 +00:00
|
|
|
unsigned long *mask = NULL;
|
2010-08-17 15:09:28 +00:00
|
|
|
unsigned long *allonesmask = NULL;
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
int *cpus = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
int max_n_cpus = NUMA_MAX_N_CPUS;
|
|
|
|
|
|
|
|
if (numa_available() < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int mask_n_bytes = max_n_cpus / 8;
|
2012-03-29 09:52:04 +00:00
|
|
|
if (VIR_ALLOC_N(mask, mask_n_bytes / sizeof(*mask)) < 0)
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
goto cleanup;
|
2012-03-29 09:52:04 +00:00
|
|
|
if (VIR_ALLOC_N(allonesmask, mask_n_bytes / sizeof(*mask)) < 0)
|
2010-08-17 15:09:28 +00:00
|
|
|
goto cleanup;
|
|
|
|
memset(allonesmask, 0xff, mask_n_bytes);
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
|
|
|
|
for (n = 0 ; n <= numa_max_node() ; n++) {
|
|
|
|
int i;
|
|
|
|
int ncpus;
|
2010-08-17 15:09:28 +00:00
|
|
|
/* The first time this returns -1, ENOENT if node doesn't exist... */
|
2009-06-26 20:08:07 +00:00
|
|
|
if (numa_node_to_cpus(n, mask, mask_n_bytes) < 0) {
|
|
|
|
VIR_WARN("NUMA topology for cell %d of %d not available, ignoring",
|
2010-08-17 15:09:28 +00:00
|
|
|
n, numa_max_node()+1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* second, third... times it returns an all-1's mask */
|
|
|
|
if (memcmp(mask, allonesmask, mask_n_bytes) == 0) {
|
|
|
|
VIR_DEBUG("NUMA topology for cell %d of %d is all ones, ignoring",
|
|
|
|
n, numa_max_node()+1);
|
2009-06-26 20:08:07 +00:00
|
|
|
continue;
|
|
|
|
}
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
|
|
|
|
for (ncpus = 0, i = 0 ; i < max_n_cpus ; i++)
|
|
|
|
if (MASK_CPU_ISSET(mask, i))
|
|
|
|
ncpus++;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(cpus, ncpus) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (ncpus = 0, i = 0 ; i < max_n_cpus ; i++)
|
|
|
|
if (MASK_CPU_ISSET(mask, i))
|
|
|
|
cpus[ncpus++] = i;
|
|
|
|
|
|
|
|
if (virCapabilitiesAddHostNUMACell(caps,
|
|
|
|
n,
|
|
|
|
ncpus,
|
|
|
|
cpus) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cpus);
|
|
|
|
VIR_FREE(mask);
|
2010-08-17 15:09:28 +00:00
|
|
|
VIR_FREE(allonesmask);
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2009-06-03 13:28:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
2010-04-03 00:06:51 +00:00
|
|
|
nodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2009-06-03 13:28:02 +00:00
|
|
|
unsigned long long *freeMems,
|
|
|
|
int startCell,
|
|
|
|
int maxCells)
|
|
|
|
{
|
|
|
|
int n, lastCell, numCells;
|
|
|
|
int ret = -1;
|
|
|
|
int maxCell;
|
|
|
|
|
|
|
|
if (numa_available() < 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("NUMA not supported on this host"));
|
2009-06-03 13:28:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
maxCell = numa_max_node();
|
|
|
|
if (startCell > maxCell) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("start cell %d out of range (0-%d)"),
|
|
|
|
startCell, maxCell);
|
2009-06-03 13:28:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
lastCell = startCell + maxCells - 1;
|
|
|
|
if (lastCell > maxCell)
|
|
|
|
lastCell = maxCell;
|
|
|
|
|
|
|
|
for (numCells = 0, n = startCell ; n <= lastCell ; n++) {
|
|
|
|
long long mem;
|
|
|
|
if (numa_node_size64(n, &mem) < 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2011-02-18 11:42:21 +00:00
|
|
|
_("Failed to query NUMA free memory for node: %d"),
|
|
|
|
n);
|
2009-06-03 13:28:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
freeMems[numCells++] = mem;
|
|
|
|
}
|
|
|
|
ret = numCells;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long long
|
2010-04-03 00:06:51 +00:00
|
|
|
nodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
|
2009-06-03 13:28:02 +00:00
|
|
|
{
|
|
|
|
unsigned long long freeMem = 0;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (numa_available() < 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("NUMA not supported on this host"));
|
2009-06-03 13:28:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (n = 0 ; n <= numa_max_node() ; n++) {
|
|
|
|
long long mem;
|
|
|
|
if (numa_node_size64(n, &mem) < 0) {
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("Failed to query NUMA free memory"));
|
2009-06-03 13:28:02 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
freeMem += mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return freeMem;
|
|
|
|
}
|
|
|
|
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#else
|
2009-06-03 13:28:02 +00:00
|
|
|
int nodeCapsInitNUMA(virCapsPtr caps ATTRIBUTE_UNUSED) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-06 09:47:28 +00:00
|
|
|
int nodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
|
2009-06-03 13:28:02 +00:00
|
|
|
unsigned long long *freeMems ATTRIBUTE_UNUSED,
|
|
|
|
int startCell ATTRIBUTE_UNUSED,
|
|
|
|
int maxCells ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("NUMA memory information not available on this platform"));
|
2009-06-03 13:28:02 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-04-06 09:47:28 +00:00
|
|
|
unsigned long long nodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
|
2009-06-03 13:28:02 +00:00
|
|
|
{
|
2012-07-18 18:19:23 +00:00
|
|
|
virReportError(VIR_ERR_NO_SUPPORT, "%s",
|
|
|
|
_("NUMA memory information not available on this platform"));
|
2009-06-03 13:28:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
make NUMA-initialization code more portable and more robust
qemudCapsInitNUMA and umlCapsInitNUMA were identical, so this change
factors them into a new function, virCapsInitNUMA, and puts it in
nodeinfo.c.
In addition to factoring out the duplicates, this change also
adjusts that function definition (along with its macros) so
that it works with Fedora 9's numactl version 1, and makes it
so the code will work even if someone builds the kernel with
CONFIG_NR_CPUS > 4096.
Finally, also perform this NUMA initialization for the lxc
and openvz drivers.
* src/nodeinfo.c: Include <stdint.h>, <numa.h> and "memory.h".
(virCapsInitNUMA): Rename from qemudCapsInitNUMA and umlCapsInitNUMA.
(NUMA_MAX_N_CPUS): Define depending on NUMA API version.
(n_bits, MASK_CPU_ISSET): Define, adjust, use uint64 rather than long.
* src/nodeinfo.h: Include "capabilities.h".
(virCapsInitNUMA): Declare it.
* examples/domain-events/events-c/Makefile.am:
* src/Makefile.am: Add $(NUMACTL_CFLAGS) and $(NUMACTL_LIBS) to various
compile/link-related variables.
* src/qemu_conf.c: Include "nodeinfo.h".
(qemudCapsInitNUMA): Remove duplicate code. Adjust caller.
* src/uml_conf.c (umlCapsInitNUMA): Likewise.
Include "nodeinfo.h".
* src/lxc_conf.c: Include "nodeinfo.h".
(lxcCapsInit): Perform NUMA initialization here, too.
* src/openvz_conf.c (openvzCapsInit): And here.
Include "nodeinfo.h".
* src/libvirt_sym.version.in: Add virCapsInitNUMA so that libvirtd
can link to this function.
2008-12-21 18:55:09 +00:00
|
|
|
#endif
|