[libvirt] [PATCH 12/12] [v2] virNodeGetMemoryStats: Implement linux support

Daniel P. Berrange berrange at redhat.com
Tue Jun 14 09:21:35 UTC 2011


On Tue, Jun 07, 2011 at 10:11:17AM +0900, Minoru Usui wrote:
> virNodeGetMemoryStats: Implement linux support
> 
> Signed-off-by: Minoru Usui <usui at mxm.nes.nec.co.jp>
> ---
>  src/libvirt_private.syms |    1 +
>  src/lxc/lxc_driver.c     |    1 +
>  src/nodeinfo.c           |  161 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/nodeinfo.h           |    5 ++
>  src/qemu/qemu_driver.c   |    1 +
>  src/uml/uml_driver.c     |    1 +
>  6 files changed, 170 insertions(+), 0 deletions(-)
> 
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index a8c77f2..4685e81 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -732,6 +732,7 @@ virNodeDeviceObjUnlock;
>  # nodeinfo.h
>  nodeCapsInitNUMA;
>  nodeGetCPUStats;
> +nodeGetMemoryStats;
>  nodeGetCellsFreeMemory;
>  nodeGetFreeMemory;
>  nodeGetInfo;
> diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
> index 3286154..daf93f2 100644
> --- a/src/lxc/lxc_driver.c
> +++ b/src/lxc/lxc_driver.c
> @@ -2780,6 +2780,7 @@ static virDriver lxcDriver = {
>      .domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
>      .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
>      .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
> +    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
>      .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.6.5 */
>      .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.6.5 */
>      .domainEventRegister = lxcDomainEventRegister, /* 0.7.0 */
> diff --git a/src/nodeinfo.c b/src/nodeinfo.c
> index 39afd0e..29afd1f 100644
> --- a/src/nodeinfo.c
> +++ b/src/nodeinfo.c
> @@ -58,8 +58,12 @@
>  # define CPUINFO_PATH "/proc/cpuinfo"
>  # define CPU_SYS_PATH "/sys/devices/system/cpu"
>  # define PROCSTAT_PATH "/proc/stat"
> +# define MEMINFO_PATH "/proc/meminfo"
> +# define NODE_SYS_PATH "/sys/devices/system/node"
>  
>  # define LINUX_NB_CPU_STATS 4
> +# define LINUX_NB_MEMORY_STATS_ALL 4
> +# define LINUX_NB_MEMORY_STATS_CELL 2
>  
>  /* NB, this is not static as we need to call it from the testsuite */
>  int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
> @@ -70,6 +74,10 @@ int linuxNodeGetCPUStats(FILE *procstat,
>                           int cpuNum,
>                           virCPUStatsPtr params,
>                           int *nparams);
> +int linuxNodeGetMemoryStats(FILE *meminfo,
> +                            int cellNum,
> +                            virMemoryStatsPtr params,
> +                            int *nparams);
>  
>  /* Return the positive decimal contents of the given
>   * CPU_SYS_PATH/cpu%u/FILE, or -1 on error.  If MISSING_OK and the
> @@ -488,6 +496,112 @@ int linuxNodeGetCPUStats(FILE *procstat,
>  cleanup:
>      return ret;
>  }
> +
> +int linuxNodeGetMemoryStats(FILE *meminfo,
> +                            int cellNum,
> +                            virMemoryStatsPtr params,
> +                            int *nparams)
> +{
> +    int ret = -1;
> +    int i = 0, j = 0, k = 0;
> +    int found = 0;
> +    int nr_param;
> +    char line[1024];
> +    char meminfo_hdr[VIR_MEMORY_STATS_FIELD_LENGTH];
> +    unsigned long val;
> +    struct field_conv {
> +        const char *meminfo_hdr;  // meminfo header
> +        const char *field;        // MemoryStats field name
> +    } field_conv[] = {
> +        {"MemTotal:", VIR_MEMORY_STATS_TOTAL},
> +        {"MemFree:",  VIR_MEMORY_STATS_FREE},
> +        {"Buffers:",  VIR_MEMORY_STATS_BUFFERS},
> +        {"Cached:",   VIR_MEMORY_STATS_CACHED},
> +        {NULL,        NULL}
> +    };
> +
> +    if (cellNum == VIR_MEMORY_STATS_ALL_CELLS) {
> +        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) {
> +        nodeReportError(VIR_ERR_INVALID_ARG,
> +                        "%s", _("Invalid stats count"));
> +        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) {
> +                    nodeReportError(VIR_ERR_INTERNAL_ERROR,
> +                                    "%s", _("no prefix found"));
> +                    goto cleanup;
> +                }
> +                p++;
> +            }
> +            buf = p;
> +        }
> +
> +        if (sscanf(buf, "%s %lu kB", meminfo_hdr, &val) < 2) {
> +                continue;
> +        }

Indentation is wrong here. Also no need for {} if there is only
one statement inside the 'if'.

> +
> +        for (j = 0; field_conv[j].meminfo_hdr != NULL; j++) {
> +            struct field_conv *convp = &field_conv[j];
> +
> +            if (STREQ(meminfo_hdr, convp->meminfo_hdr)) {
> +                virMemoryStatsPtr param = &params[k++];
> +
> +                if (virStrcpyStatic(param->field, convp->field) == NULL) {
> +                    nodeReportError(VIR_ERR_INTERNAL_ERROR,
> +                                    "%s", _("Field kernel memory too long for destination"));
> +                    goto cleanup;
> +                }
> +                param->value = val;
> +                found++;
> +                break;
> +            }
> +        }
> +        if (found >= nr_param) {
> +            break;
> +        }
> +    }
> +
> +    if (found == 0) {
> +        nodeReportError(VIR_ERR_INTERNAL_ERROR,
> +                        "%s", _("no available memory line found"));
> +        goto cleanup;
> +    }
> +
> +    ret = 0;
> +
> +cleanup:
> +    return ret;
> +}
>  #endif
>  
>  int nodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED, virNodeInfoPtr nodeinfo) {
> @@ -554,6 +668,53 @@ int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
>  #endif
>  }
>  
> +int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
> +                       int cellNum,
> +                       virMemoryStatsPtr params,
> +                       int *nparams,
> +                       unsigned int flags ATTRIBUTE_UNUSED)
> +{
> +#ifdef __linux__
> +    {
> +    int ret;
> +    char meminfo_path[1024];
> +    FILE *meminfo;
> +
> +    if (cellNum == VIR_MEMORY_STATS_ALL_CELLS) {
> +        sprintf(meminfo_path, MEMINFO_PATH);
> +    } else {
> +        if (numa_available() < 0) {
> +            nodeReportError(VIR_ERR_NO_SUPPORT,
> +                            "%s", _("NUMA not supported on this host"));
> +            return -1;
> +        }
> +
> +        if (cellNum > numa_max_node()) {
> +            nodeReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid cell number"));
> +            return -1;
> +        }
> +
> +        sprintf(meminfo_path, "%s/node%d/meminfo", NODE_SYS_PATH, cellNum);
> +    }

Instead of using a static buffer, it is preferrable to use
virAsprintf() here to construct meminfo_path.

> +    meminfo = fopen(meminfo_path, "r");
> +
> +    if (!meminfo) {
> +        virReportSystemError(errno,
> +                             _("cannot open %s"), MEMINFO_PATH);
> +        return -1;
> +    }
> +    ret = linuxNodeGetMemoryStats(meminfo, cellNum, params, nparams);
> +    VIR_FORCE_FCLOSE(meminfo);
> +
> +    return ret;
> +    }
> +#else
> +    nodeReportError(VIR_ERR_NO_SUPPORT, "%s",
> +                    _("node memory stats not implemented on this platform"));
> +    return -1;
> +#endif
> +}
> +
>  #if HAVE_NUMACTL
>  # if LIBNUMA_API_VERSION <= 1
>  #  define NUMA_MAX_N_CPUS 4096
> diff --git a/src/nodeinfo.h b/src/nodeinfo.h
> index 361e3e5..1ebcdb1 100644
> --- a/src/nodeinfo.h
> +++ b/src/nodeinfo.h
> @@ -35,6 +35,11 @@ int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
>                      virCPUStatsPtr params,
>                      int *nparams,
>                      unsigned int flags ATTRIBUTE_UNUSED);
> +int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
> +                       int cellNum,
> +                       virMemoryStatsPtr params,
> +                       int *nparams,
> +                       unsigned int flags ATTRIBUTE_UNUSED);
>  int nodeGetCellsFreeMemory(virConnectPtr conn,
>                             unsigned long long *freeMems,
>                             int startCell,
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 108a37f..ce93bf1 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -8045,6 +8045,7 @@ static virDriver qemuDriver = {
>      .domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
>      .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
>      .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
> +    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
>      .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
>      .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
>      .domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
> diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
> index 471277d..80b51dd 100644
> --- a/src/uml/uml_driver.c
> +++ b/src/uml/uml_driver.c
> @@ -2219,6 +2219,7 @@ static virDriver umlDriver = {
>      .domainSetAutostart = umlDomainSetAutostart, /* 0.5.0 */
>      .domainBlockPeek = umlDomainBlockPeek, /* 0.5.0 */
>      .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
> +    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
>      .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.5.0 */
>      .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.5.0 */
>      .isEncrypted = umlIsEncrypted, /* 0.7.3 */


Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list