]> xenbits.xensource.com Git - libvirt.git/commitdiff
virNodeGetMemoryStats: Implement linux support
authorMinoru Usui <usui@mxm.nes.nec.co.jp>
Tue, 7 Jun 2011 01:11:17 +0000 (10:11 +0900)
committerEric Blake <eblake@redhat.com>
Tue, 14 Jun 2011 22:54:01 +0000 (16:54 -0600)
Signed-off-by: Minoru Usui <usui@mxm.nes.nec.co.jp>
src/libvirt_private.syms
src/lxc/lxc_driver.c
src/nodeinfo.c
src/nodeinfo.h
src/qemu/qemu_driver.c
src/uml/uml_driver.c

index 32523a07875b0117c28a90dbdeaf7a8c5724aa84..7a05539ce57693b2f156121b436253a11f45d05c 100644 (file)
@@ -737,6 +737,7 @@ nodeGetCPUStats;
 nodeGetCellsFreeMemory;
 nodeGetFreeMemory;
 nodeGetInfo;
+nodeGetMemoryStats;
 
 
 # nwfilter_conf.h
index 338ea7304a41d37f8e818729f3000669055ec58f..a9156f447353523a7083b9784ed183e241d3c7c3 100644 (file)
@@ -2886,6 +2886,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 */
index bdf8f8a7b0161c84b7a645b54d2d7c30cdcfb9a4..cb2f80549d371d8b37901811817a34665023c3fc 100644 (file)
 # 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 @@ static int linuxNodeGetCPUStats(FILE *procstat,
                                 int cpuNum,
                                 virCPUStatsPtr params,
                                 int *nparams);
+static 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
@@ -482,6 +490,110 @@ int linuxNodeGetCPUStats(FILE *procstat,
 
     nodeReportError(VIR_ERR_INVALID_ARG, "%s", _("Invalid cpu number"));
 
+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;
+
+        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;
 }
@@ -552,6 +664,66 @@ int nodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
 #endif
 }
 
+int nodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
+                       int cellNum,
+                       virMemoryStatsPtr params,
+                       int *nparams,
+                       unsigned int flags)
+{
+    virCheckFlags(0, -1);
+
+#ifdef __linux__
+    {
+        int ret;
+        char *meminfo_path = NULL;
+        FILE *meminfo;
+
+        if (cellNum == VIR_MEMORY_STATS_ALL_CELLS) {
+            meminfo_path = strdup(MEMINFO_PATH);
+            if (!meminfo_path) {
+                virReportOOMError();
+                return -1;
+            }
+        } 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;
+            }
+
+            if (virAsprintf(&meminfo_path, "%s/node%d/meminfo",
+                            NODE_SYS_PATH, cellNum) < 0) {
+                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
+    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
index 361e3e5d9c3e444423dbd1fef5a46a6a5db0db42..1ebcdb14ee5ec0cd6e17ba8636752225c0f567ad 100644 (file)
@@ -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,
index 890769bc3cb5aa605f44d58f9bad0bdd614ad9df..333619b8a43f439afb3b6bbde43f48d547673f6e 100644 (file)
@@ -8093,6 +8093,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 */
index 59b910ae5a472fe34734579d3e0d094160ea33c9..1d26422a14d32016966a734c4962c47cedc011ff 100644 (file)
@@ -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 */