[libvirt] [PATCH] openvz: read vmguarpages/privvmpages to set memory tunables

Guido Günther agx at sigxcpu.org
Mon Apr 23 21:29:48 UTC 2012


---
OpenVZ's memory paramters [1,2] aren't very well supported at the
moment. Let's make a start with privvmpages/vmguarpages using already
available memtune parameters. I hope the mapping looks correct.
Cheers,
 -- Guido

[1] http://wiki.openvz.org/UBC_primary_parameters
[2] http://wiki.openvz.org/UBC_secondary_parameters

 src/openvz/openvz_conf.c   |  103 +++++++++++++++++++++++
 src/openvz/openvz_driver.c |  200 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 303 insertions(+)

diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
index 5848ec4..579fcfc 100644
--- a/src/openvz/openvz_conf.c
+++ b/src/openvz/openvz_conf.c
@@ -423,6 +423,108 @@ error:
 }
 
 
+/* Parse config values of the form barrier:limit into barrier and limit */
+static int
+openvzParseBarrierAndLimit(const char* value,
+                           unsigned long *barrier,
+                           unsigned long *limit)
+{
+    char *token;
+    char *saveptr = NULL;
+    char *str = strdup(value);
+
+    if (str == NULL) {
+        virReportOOMError();
+        goto error;
+    }
+
+    token = strtok_r(str, ":", &saveptr);
+    if (token == NULL) {
+        goto error;
+    } else {
+        if (barrier != NULL) {
+            if (virStrToLong_ul(token, NULL, 10, barrier))
+                goto error;
+        }
+    }
+    token = strtok_r(NULL, ":", &saveptr);
+    if (token == NULL) {
+        goto error;
+    } else {
+        if (limit != NULL) {
+            if (virStrToLong_ul(token, NULL, 10, limit))
+                goto error;
+        }
+    }
+    return 0;
+error:
+    VIR_FREE(str);
+    return -1;
+}
+
+
+static int
+openvzReadMemConf(virDomainDefPtr def, int veid)
+{
+    int ret;
+    char *temp = NULL;
+    unsigned long barrier, limit;
+    const char *param;
+    unsigned long kb_per_pages;
+
+    kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+    if (kb_per_pages == -1) {
+        openvzError(VIR_ERR_INTERNAL_ERROR,
+                    _("Can't determine page size"));
+        goto error;
+    }
+
+    /* Memory allocation guarantee */
+    param = "VMGUARPAGES";
+    ret = openvzReadVPSConfigParam(veid, param, &temp);
+    if (ret < 0) {
+        openvzError(VIR_ERR_INTERNAL_ERROR,
+                    _("Could not read '%s' from config for container %d"),
+                    param, veid);
+        goto error;
+    } else if (ret > 0) {
+        ret = openvzParseBarrierAndLimit(temp, &barrier, NULL);
+        if (ret < 0) {
+            openvzError(VIR_ERR_INTERNAL_ERROR,
+                        _("Could not parse  barrier of '%s' "
+                          "from config for container %d"), param, veid);
+            goto error;
+        }
+        def->mem.min_guarantee = barrier * kb_per_pages;
+    }
+
+    /* Memory hard and soft limits */
+    param = "PRIVVMPAGES";
+    ret = openvzReadVPSConfigParam(veid, param, &temp);
+    if (ret < 0) {
+        openvzError(VIR_ERR_INTERNAL_ERROR,
+                    _("Could not read '%s' from config for container %d"),
+                    param, veid);
+        goto error;
+    } else if (ret > 0) {
+        ret = openvzParseBarrierAndLimit(temp, &barrier, &limit);
+        if (ret < 0) {
+            openvzError(VIR_ERR_INTERNAL_ERROR,
+                        _("Could not parse barrier and limit of '%s' "
+                          "from config for container %d"), param, veid);
+            goto error;
+        }
+        def->mem.soft_limit = barrier * kb_per_pages;
+        def->mem.hard_limit = limit * kb_per_pages;
+    }
+
+    ret = 0;
+error:
+    VIR_FREE(temp);
+    return ret;
+}
+
+
 /* Free all memory associated with a openvz_driver structure */
 void
 openvzFreeDriver(struct openvz_driver *driver)
@@ -535,6 +637,7 @@ int openvzLoadDomains(struct openvz_driver *driver) {
 
         openvzReadNetworkConf(dom->def, veid);
         openvzReadFSConf(dom->def, veid);
+        openvzReadMemConf(dom->def, veid);
 
         virUUIDFormat(dom->def->uuid, uuidstr);
         if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0)
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index e8b6915..6f8a6a8 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -54,6 +54,7 @@
 #include "nodeinfo.h"
 #include "memory.h"
 #include "virfile.h"
+#include "virtypedparam.h"
 #include "logging.h"
 #include "command.h"
 #include "viruri.h"
@@ -65,6 +66,8 @@
 #define CMDBUF_LEN 1488
 #define CMDOP_LEN 288
 
+#define OPENVZ_NB_MEM_PARAM 3
+
 static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid);
 static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type);
 static int openvzDomainGetMaxVcpus(virDomainPtr dom);
@@ -1631,6 +1634,201 @@ cleanup:
     return -1;
 }
 
+
+static int
+openvzDomainGetBarrierLimit(virDomainPtr domain,
+                            const char *param,
+                            long *barrier,
+                            long *limit)
+{
+    int status, ret = -1;
+    char *output = NULL;
+    virCommandPtr cmd = virCommandNewArgList(VZLIST, "--no-header", NULL);
+
+    virCommandSetOutputBuffer(cmd, &output);
+    virCommandAddArgFormat(cmd, "-o%s.b,%s.l", param, param);
+    virCommandAddArg(cmd, domain->name);
+    if (virCommandRun(cmd, &status)) {
+        openvzError(VIR_ERR_OPERATION_FAILED,
+                    _("Failed to get %s for %s: %d"), param, domain->name,
+                    status);
+        goto cleanup;
+    }
+
+    if (sscanf(output, "%ld %ld", barrier, limit) != 2) {
+        openvzError(VIR_ERR_INTERNAL_ERROR,
+                    _("Can't parse "VZLIST" output, got %s"), output);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    VIR_FREE(output);
+    virCommandFree(cmd);
+    return ret;
+}
+
+
+static int
+openvzDomainSetBarrierLimit(virDomainPtr domain,
+                            const  char *param,
+                            long barrier,
+                            long limit)
+{
+    int status, ret = -1;
+    virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL);
+
+    virCommandAddArg(cmd, domain->name);
+    virCommandAddArgFormat(cmd, "--%s", param);
+    virCommandAddArgFormat(cmd, "%ld:%ld", barrier, limit);
+    virCommandAddArg(cmd, "--save");
+    if (virCommandRun(cmd, &status)) {
+        openvzError(VIR_ERR_OPERATION_FAILED,
+                    _("Failed to set %s for %s: %d"), param, domain->name,
+                    status);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
+}
+
+
+static int
+openvzDomainGetMemoryParameters(virDomainPtr domain,
+                                virTypedParameterPtr params,
+                                int *nparams,
+                                unsigned int flags)
+{
+    int i, result = -1;
+    const char *name;
+    long barrier, limit, kb_per_pages;
+    unsigned long long int val;
+
+    virCheckFlags(0, -1);
+
+    kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+    if (kb_per_pages == -1) {
+        openvzError(VIR_ERR_INTERNAL_ERROR,
+                    _("Can't determine page size"));
+        goto cleanup;
+    }
+
+    if (*nparams == 0) {
+        *nparams = OPENVZ_NB_MEM_PARAM;
+        return 0;
+    }
+
+    for (i = 0; i <= *nparams; i++) {
+        virMemoryParameterPtr param = &params[i];
+
+        switch (i) {
+        case 0:
+            name = "privvmpages";
+            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
+                goto cleanup;
+
+            val = limit * kb_per_pages;
+            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
+                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
+                goto cleanup;
+            break;
+
+        case 1:
+            name = "privvmpages";
+            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
+                goto cleanup;
+
+            val = barrier * kb_per_pages;
+            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
+                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
+                goto cleanup;
+            break;
+
+        case 2:
+            name = "vmguarpages";
+            if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
+                goto cleanup;
+
+            val = barrier * kb_per_pages;
+            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
+                                VIR_TYPED_PARAM_ULLONG, val) < 0)
+                goto cleanup;
+            break;
+        }
+    }
+
+    if (*nparams > OPENVZ_NB_MEM_PARAM)
+        *nparams = OPENVZ_NB_MEM_PARAM;
+    result = 0;
+
+cleanup:
+    return result;
+}
+
+
+static int
+openvzDomainSetMemoryParameters(virDomainPtr domain,
+                                virTypedParameterPtr params,
+                                int nparams,
+                                unsigned int flags)
+{
+    int i, result = -1;
+    long kb_per_pages;
+
+    kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+    if (kb_per_pages == -1) {
+        openvzError(VIR_ERR_INTERNAL_ERROR,
+                    _("Can't determine page size"));
+        goto cleanup;
+    }
+
+    virCheckFlags(0, -1);
+    if (virTypedParameterArrayValidate(params, nparams,
+                                       VIR_DOMAIN_MEMORY_HARD_LIMIT,
+                                       VIR_TYPED_PARAM_ULLONG,
+                                       VIR_DOMAIN_MEMORY_SOFT_LIMIT,
+                                       VIR_TYPED_PARAM_ULLONG,
+                                       VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
+                                       VIR_TYPED_PARAM_ULLONG,
+                                       NULL) < 0)
+        return -1;
+
+    for (i = 0; i < nparams; i++) {
+        virTypedParameterPtr param = &params[i];
+        long barrier, limit;
+
+        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
+            if (openvzDomainGetBarrierLimit(domain, "privvmpages",
+                                            &barrier, &limit) < 0)
+                goto cleanup;
+            limit = params[i].value.ul / kb_per_pages;
+            if (openvzDomainSetBarrierLimit(domain, "privvmpages",
+                                            barrier, limit) < 0)
+                goto cleanup;
+        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
+            if (openvzDomainGetBarrierLimit(domain, "privvmpages",
+                                            &barrier, &limit) < 0)
+                goto cleanup;
+            barrier = params[i].value.ul / kb_per_pages;
+            if (openvzDomainSetBarrierLimit(domain, "privvmpages",
+                                            barrier, limit) < 0)
+                goto cleanup;
+        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
+            barrier = params[i].value.ul / kb_per_pages;
+            if (openvzDomainSetBarrierLimit(domain, "vmguarpages",
+                                            barrier, LONG_MAX) < 0)
+                goto cleanup;
+        }
+    }
+    result = 0;
+cleanup:
+    return result;
+}
+
+
 static int
 openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason)
 {
@@ -1752,6 +1950,8 @@ static virDriver openvzDriver = {
     .domainDestroy = openvzDomainShutdown, /* 0.3.1 */
     .domainDestroyFlags = openvzDomainShutdownFlags, /* 0.9.4 */
     .domainGetOSType = openvzGetOSType, /* 0.3.1 */
+    .domainGetMemoryParameters = openvzDomainGetMemoryParameters, /* 0.9.12 */
+    .domainSetMemoryParameters = openvzDomainSetMemoryParameters, /* 0.9.12 */
     .domainGetInfo = openvzDomainGetInfo, /* 0.3.1 */
     .domainGetState = openvzDomainGetState, /* 0.9.2 */
     .domainSetVcpus = openvzDomainSetVcpus, /* 0.4.6 */
-- 
1.7.10




More information about the libvir-list mailing list