[libvirt] [PATCH] set cpu bandwidth for the vm

Wen Congyang wency at cn.fujitsu.com
Mon Jul 25 05:37:14 UTC 2011


The cpu bandwidth is applied at the vcpu group level. We should apply it
at the vm group level too, because the vm may do heavy I/O, and it will affect
the other vm.

We apply cpu bandwidth at the vcpu and the vm group level, so we must ensure
that max(child_quota) <= parent_quota when we modify cpu bandwidth.

---
 src/qemu/qemu_cgroup.c |   38 ++++++++++-------
 src/qemu/qemu_driver.c |  103 ++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 101 insertions(+), 40 deletions(-)

diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index d6e4cbc..2a10bd2 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -435,6 +435,7 @@ int qemuSetupCgroupForVcpu(struct qemud_driver *driver, virDomainObjPtr vm)
     unsigned int i;
     unsigned long long period = vm->def->cputune.period;
     long long quota = vm->def->cputune.quota;
+    long long vm_quota = 0;
 
     if (driver->cgroup == NULL)
         return 0; /* Not supported, so claim success */
@@ -447,26 +448,31 @@ int qemuSetupCgroupForVcpu(struct qemud_driver *driver, virDomainObjPtr vm)
         goto cleanup;
     }
 
+    /* Set cpu bandwidth for the vm */
+    if (period || quota) {
+        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
+            /* Ensure that we can multiply by vcpus without overflowing. */
+            if (quota > LLONG_MAX / vm->def->vcpus) {
+                virReportSystemError(EINVAL,
+                                     _("%s"),
+                                     "Unable to set cpu bandwidth quota");
+                goto cleanup;
+            }
+
+            if (quota > 0)
+                vm_quota = quota * vm->def->vcpus;
+            else
+                vm_quota = quota;
+            if (qemuSetupCgroupVcpuBW(cgroup, period, vm_quota) < 0)
+                goto cleanup;
+        }
+    }
+
     if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
         /* If we does not know VCPU<->PID mapping or all vcpu runs in the same
          * thread, we cannot control each vcpu.
          */
-        if (period || quota) {
-            if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
-                /* Ensure that we can multiply by vcpus without overflowing. */
-                if (quota > LLONG_MAX / vm->def->vcpus) {
-                    virReportSystemError(EINVAL,
-                                         _("%s"),
-                                         "Unable to set cpu bandwidth quota");
-                    goto cleanup;
-                }
-
-                if (quota > 0)
-                    quota *= vm->def->vcpus;
-                if (qemuSetupCgroupVcpuBW(cgroup, period, quota) < 0)
-                    goto cleanup;
-            }
-        }
+        virCgroupFree(&cgroup);
         return 0;
     }
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5df58b1..52e5d69 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6051,43 +6051,98 @@ qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virCgroupPtr cgroup_vcpu = NULL;
     int rc;
+    long long vm_quota = 0;
+    long long old_quota = 0;
+    unsigned long long old_period = 0;
 
     if (period == 0 && quota == 0)
         return 0;
 
-    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
-        /* If we does not know VCPU<->PID mapping or all vcpu runs in the same
-         * thread, we cannot control each vcpu.
-         */
-        /* Ensure that we can multiply by vcpus without overflowing. */
-        if (quota > LLONG_MAX / vm->def->vcpus) {
-            virReportSystemError(EINVAL,
-                                 _("%s"),
-                                 "Unable to set cpu bandwidth quota");
-            goto cleanup;
-        }
+    /* Ensure that we can multiply by vcpus without overflowing. */
+    if (quota > LLONG_MAX / vm->def->vcpus) {
+        virReportSystemError(EINVAL,
+                             _("%s"),
+                             "Unable to set cpu bandwidth quota");
+        goto cleanup;
+    }
+
+    if (quota > 0)
+        vm_quota = quota * vm->def->vcpus;
+    else
+        vm_quota = quota;
 
-        if (quota > 0)
-            quota *= vm->def->vcpus;
-        return qemuSetupCgroupVcpuBW(cgroup, period, quota);
+    rc = virCgroupGetCpuCfsQuota(cgroup, &old_quota);
+    if (rc < 0) {
+        virReportSystemError(-rc, "%s",
+                             _("unable to get cpu bandwidth tunable"));
+        goto cleanup;
     }
 
-    for (i = 0; i < priv->nvcpupids; i++) {
-        rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0);
-        if (rc < 0) {
-            virReportSystemError(-rc,
-                                 _("Unable to find vcpu cgroup for %s(vcpu:"
-                                   " %d)"),
-                                 vm->def->name, i);
-            goto cleanup;
+    rc = virCgroupGetCpuCfsPeriod(cgroup, &old_period);
+    if (rc < 0) {
+        virReportSystemError(-rc, "%s",
+                             _("unable to get cpu bandwidth period tunable"));
+        goto cleanup;
+    }
+
+    /*
+     * If quota will be changed to a small value, we should modify vcpu's quota
+     * first. Otherwise, we should modify vm's quota first.
+     *
+     * If period will be changed to a small value, we should modify vm's period
+     * first. Otherwise, we should modify vcpu's period first.
+     *
+     * If both quota and period will be changed to a big/small value, we cannot
+     * modify period and quota together.
+     */
+    if ((quota != 0) && (period != 0)) {
+        if (((quota > old_quota) && (period > old_period)) ||
+            ((quota < old_quota) && (period < old_period))) {
+            /* modify period */
+            if (qemuSetVcpusBWLive(vm, cgroup, period, 0) < 0)
+                goto cleanup;
+
+            /* modify quota */
+            if (qemuSetVcpusBWLive(vm, cgroup, 0, quota) < 0)
+                goto cleanup;
+            return 0;
         }
+    }
 
-        if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
+    if (((vm_quota != 0) && (vm_quota > old_quota)) ||
+        ((period != 0) && (period < old_period)))
+        /* Set cpu bandwidth for the vm */
+        if (qemuSetupCgroupVcpuBW(cgroup, period, vm_quota) < 0)
             goto cleanup;
 
-        virCgroupFree(&cgroup_vcpu);
+    /* If we does not know VCPU<->PID mapping or all vcpu runs in the same
+     * thread, we cannot control each vcpu. So we only modify cpu bandwidth
+     * when each vcpu has a separated thread.
+     */
+    if (priv->nvcpupids != 0 && priv->vcpupids[0] != vm->pid) {
+        for (i = 0; i < priv->nvcpupids; i++) {
+            rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0);
+            if (rc < 0) {
+                virReportSystemError(-rc,
+                                     _("Unable to find vcpu cgroup for %s(vcpu:"
+                                       " %d)"),
+                                     vm->def->name, i);
+                goto cleanup;
+            }
+
+            if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
+                goto cleanup;
+
+            virCgroupFree(&cgroup_vcpu);
+        }
     }
 
+    if (((vm_quota != 0) && (vm_quota <= old_quota)) ||
+        ((period != 0) && (period >= old_period)))
+        /* Set cpu bandwidth for the vm */
+        if (qemuSetupCgroupVcpuBW(cgroup, period, vm_quota) < 0)
+            goto cleanup;
+
     return 0;
 
 cleanup:
-- 
1.7.1




More information about the libvir-list mailing list