[libvirt] [PATCH 5/6] cputune: support cputune xml config

Osier Yang jyang at redhat.com
Sun Feb 27 14:39:20 UTC 2011


cputune XML:
  <cputune>
    <vcpupin vcpu='0' cpuset='0'/>
    <vcpupin vcpu='1' cpuset='1'/>
  </cputune>

* src/conf/domain_conf.h (New struct for vcputune and vcpupin,
  declarations for new internal helper functions for cputune
  support)
* src/conf/domain_conf.c (Update "virDomainDefParseXML" to parse,
  and "declaration" to build cputune xml, implementations for
  new internal helper functions).
* src/libvirt_private.syms (Add new internal functions, and also
  "virAllocVar", as VIR_ALLOC_VAR is used in the patch series)
---
 src/conf/domain_conf.c   |  278 ++++++++++++++++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h   |   27 +++++
 src/libvirt_private.syms |    4 +
 3 files changed, 309 insertions(+), 0 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b97c1f0..698f738 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -848,6 +848,22 @@ virDomainClockDefClear(virDomainClockDefPtr def)
     VIR_FREE(def->timers);
 }
 
+static void
+virDomainVcpupinDefFree(virDomainVcpupinDefPtr *def,
+                        int nvcpupin)
+{
+    int i;
+
+    if (!def || !nvcpupin)
+        return;
+
+    for(i = 0; i < nvcpupin; i++) {
+        VIR_FREE(def[i]);
+    }
+
+    VIR_FREE(def);
+}
+
 void virDomainDefFree(virDomainDefPtr def)
 {
     unsigned int i;
@@ -936,6 +952,8 @@ void virDomainDefFree(virDomainDefPtr def)
 
     virCPUDefFree(def->cpu);
 
+    virDomainVcpupinDefFree(def->cputune.vcpupin, def->cputune.nvcpupin);
+
     virSysinfoDefFree(def->sysinfo);
 
     if (def->namespaceData && def->ns.free)
@@ -3522,6 +3540,196 @@ error:
     goto cleanup;
 }
 
+/* Check if vcpupin with same vcpuid already exists.
+ * Return 1 if exists, 0 if not. */
+int
+virDomainVcpupinIsDuplicate(virDomainVcpupinDefPtr *def,
+                            int nvcpupin,
+                            int vcpu)
+{
+    int i;
+
+    if (!def || !nvcpupin)
+        return 0;
+
+    for (i = 0; i < nvcpupin; i++) {
+        if (def[i]->vcpuid == vcpu)
+            return 1;
+    }
+
+    return 0;
+}
+
+virDomainVcpupinDefPtr
+virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
+                           int nvcpupin,
+                           int vcpu)
+{
+    int i;
+
+    if (!def || !nvcpupin)
+        return NULL;
+
+    for (i = 0; i < nvcpupin; i++) {
+        if (def[i]->vcpuid == vcpu)
+            return def[i];
+    }
+
+    return NULL;
+}
+
+int
+virDomainVcpupinAdd(virDomainDefPtr def,
+                    unsigned char *cpumap,
+                    int maplen,
+                    int vcpu)
+{
+    virDomainVcpupinDefPtr *vcpupin_list = NULL;
+    virDomainVcpupinDefPtr vcpupin = NULL;
+    char *cpumask = NULL;
+    int i;
+
+    if (VIR_ALLOC_N(cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* Reset cpumask to all 0s. */
+    for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++)
+        cpumask[i] = 0;
+
+    /* Convert bitmap (cpumap) to cpumask, which is byte map? */
+    for (i = 0; i < maplen; i++) {
+        int cur;
+
+        for (cur = 0; cur < 8; cur++) {
+            if (cpumap[i] & (1 << cur))
+                cpumask[i * 8 + cur] = 1;
+        }
+    }
+
+    /* No vcpupin exists yet. */
+    if (!def->cputune.nvcpupin) {
+        if (VIR_ALLOC(vcpupin) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (VIR_ALLOC(vcpupin_list) < 0) {
+            virReportOOMError();
+            VIR_FREE(vcpupin);
+            goto cleanup;
+        }
+
+        vcpupin->vcpuid = vcpu;
+        vcpupin->cpumask = cpumask;
+        vcpupin_list[def->cputune.nvcpupin++] = vcpupin;
+
+        def->cputune.vcpupin = vcpupin_list;
+    } else {
+        vcpupin_list = def->cputune.vcpupin;
+
+        if (virDomainVcpupinIsDuplicate(vcpupin_list,
+                                        def->cputune.nvcpupin,
+                                        vcpu)) {
+            vcpupin = virDomainVcpupinFindByVcpu(vcpupin_list,
+                                                 def->cputune.nvcpupin,
+                                                 vcpu);
+            vcpupin->vcpuid = vcpu;
+            vcpupin->cpumask = cpumask;
+        } else {
+            if (VIR_ALLOC(vcpupin) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            if (VIR_REALLOC_N(vcpupin_list, def->cputune.nvcpupin + 1) < 0) {
+                virReportOOMError();
+                VIR_FREE(vcpupin);
+                goto cleanup;
+            }
+
+            vcpupin->vcpuid = vcpu;
+            vcpupin->cpumask = cpumask;
+            vcpupin_list[def->cputune.nvcpupin++] = vcpupin;
+       }
+    }
+
+    return 0;
+
+cleanup:
+    VIR_FREE(cpumask);
+    return -1;
+}
+
+/* Parse the XML definition for a vcpupin */
+static virDomainVcpupinDefPtr
+virDomainVcpupinDefParseXML(const xmlNodePtr node,
+                            xmlXPathContextPtr ctxt,
+                            int maxvcpus,
+                            int flags ATTRIBUTE_UNUSED)
+{
+    virDomainVcpupinDefPtr def;
+    xmlNodePtr oldnode = ctxt->node;
+    unsigned int vcpuid;
+    char *tmp = NULL;
+    int ret;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    ctxt->node = node;
+
+    ret = virXPathUInt("string(./@vcpu)", ctxt, &vcpuid);
+    if (ret == -2) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("vcpu id must be an unsigned integer"));
+        goto error;
+    } else if (ret == -1) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("can't parse vcpupin node"));
+        goto error;
+    }
+
+    if (vcpuid >= maxvcpus) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("vcpu id must be less than maxvcpus"));
+        goto error;
+    }
+
+    def->vcpuid = vcpuid;
+
+    tmp = virXMLPropString(node, "cpuset");
+
+    if (tmp) {
+        char *set = tmp;
+        int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+
+        if (VIR_ALLOC_N(def->cpumask, cpumasklen) < 0) {
+            virReportOOMError();
+            goto error;
+        }
+        if (virDomainCpuSetParse((const char **)&set,
+                                 0, def->cpumask,
+                                 cpumasklen) < 0)
+            goto error;
+        VIR_FREE(tmp);
+    } else {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("missing cpuset for vcpupin"));
+        goto error;
+    }
+
+cleanup:
+    ctxt->node = oldnode;
+    return def;
+
+error:
+    VIR_FREE(def);
+    goto cleanup;
+}
 
 /* Parse the XML definition for a clock timer */
 static virDomainTimerDefPtr
@@ -5244,6 +5452,46 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
         VIR_FREE(tmp);
     }
 
+    /* Extract cpu tunables. */
+    if (virXPathULong("string(./cputune/shares[1])", ctxt,
+                      &def->cputune.shares) < 0)
+        def->cputune.shares = 0;
+
+    if ((n = virXPathNodeSet("./cputune/vcpupin", ctxt, &nodes)) < 0) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract vcpupin nodes"));
+        goto error;
+    }
+
+    if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
+        goto no_memory;
+
+    if (n > def->maxvcpus) {
+        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("vcpupin nodes must be less than maxvcpus"));
+        goto error;
+    }
+
+    for (i = 0 ; i < n ; i++) {
+        virDomainVcpupinDefPtr vcpupin = NULL;
+        vcpupin = virDomainVcpupinDefParseXML(nodes[i], ctxt, def->maxvcpus, 0);
+
+        if (!vcpupin)
+            goto error;
+
+        if (virDomainVcpupinIsDuplicate(def->cputune.vcpupin,
+                                        def->cputune.nvcpupin,
+                                        vcpupin->vcpuid)) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                 "%s", _("duplicate vcpupin for same vcpu"));
+            VIR_FREE(vcpupin);
+            goto error;
+        }
+
+        def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
+    }
+    VIR_FREE(nodes);
+
     n = virXPathNodeSet("./features/*", ctxt, &nodes);
     if (n < 0)
         goto error;
@@ -7708,6 +7956,36 @@ char *virDomainDefFormat(virDomainDefPtr def,
         virBufferVSprintf(&buf, " current='%u'", def->vcpus);
     virBufferVSprintf(&buf, ">%u</vcpu>\n", def->maxvcpus);
 
+    if (def->cputune.shares || def->cputune.vcpupin)
+        virBufferAddLit(&buf, "  <cputune>\n");
+
+    if (def->cputune.shares)
+        virBufferVSprintf(&buf, "    <shares>%lu</shares>\n",
+                          def->cputune.shares);
+    if (def->cputune.vcpupin) {
+        int i;
+        for (i = 0; i < def->cputune.nvcpupin; i++) {
+            virBufferVSprintf(&buf, "    <vcpupin vcpu='%u' ",
+                              def->cputune.vcpupin[i]->vcpuid);
+
+            char *cpumask = NULL;
+            cpumask = virDomainCpuSetFormat(def->cputune.vcpupin[i]->cpumask,
+                                            VIR_DOMAIN_CPUMASK_LEN);
+
+            if (cpumask == NULL) {
+                virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                     "%s", _("failed to format cpuset for vcpupin"));
+                goto cleanup;
+            }
+
+            virBufferVSprintf(&buf, "cpuset='%s'/>\n", cpumask);
+            VIR_FREE(cpumask);
+        }
+    }
+
+    if (def->cputune.shares || def->cputune.vcpupin)
+        virBufferAddLit(&buf, "  </cputune>\n");
+
     if (def->sysinfo)
         virDomainSysinfoDefFormat(&buf, def->sysinfo);
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 30aeccc..53467cd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1032,6 +1032,21 @@ int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot);
 int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
                                 virDomainSnapshotObjListPtr snapshots);
 
+typedef struct _virDomainVcpupinDef virDomainVcpupinDef;
+typedef virDomainVcpupinDef *virDomainVcpupinDefPtr;
+struct _virDomainVcpupinDef {
+    int vcpuid;
+    char *cpumask;
+};
+
+int virDomainVcpupinIsDuplicate(virDomainVcpupinDefPtr *def,
+                                int nvcpupin,
+                                int vcpu);
+
+virDomainVcpupinDefPtr virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
+                                                  int nvcpupin,
+                                                  int vcpu);
+
 /* Guest VM main configuration */
 typedef struct _virDomainDef virDomainDef;
 typedef virDomainDef *virDomainDefPtr;
@@ -1060,6 +1075,12 @@ struct _virDomainDef {
     int cpumasklen;
     char *cpumask;
 
+    struct {
+        unsigned long shares;
+        int nvcpupin;
+        virDomainVcpupinDefPtr *vcpupin;
+    } cputune;
+
     /* These 3 are based on virDomainLifeCycleAction enum flags */
     int onReboot;
     int onPoweroff;
@@ -1196,6 +1217,12 @@ int virDomainDeviceVirtioSerialAddressIsValid(virDomainDeviceVirtioSerialAddress
 int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info);
 void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
 void virDomainDefClearPCIAddresses(virDomainDefPtr def);
+
+int virDomainVcpupinAdd(virDomainDefPtr def,
+                        unsigned char *cpumap,
+                        int maplen,
+                        int vcpu);
+
 void virDomainDefClearDeviceAliases(virDomainDefPtr def);
 
 typedef int (*virDomainDeviceInfoCallback)(virDomainDefPtr def,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 66917ca..10b97ce 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -315,6 +315,9 @@ virDomainTimerTickpolicyTypeFromString;
 virDomainTimerTickpolicyTypeToString;
 virDomainTimerTrackTypeFromString;
 virDomainTimerTrackTypeToString;
+virDomainVcpupinAdd;
+virDomainVcpupinFindByVcpu;
+virDomainVcpupinIsDuplicate;
 virDomainVideoDefFree;
 virDomainVideoDefaultRAM;
 virDomainVideoDefaultType;
@@ -563,6 +566,7 @@ virVMOperationTypeToString;
 # memory.h
 virAlloc;
 virAllocN;
+virAllocVar;
 virExpandN;
 virFree;
 virReallocN;
-- 
1.7.4




More information about the libvir-list mailing list