9119d9
From 3b2c6fae4d780e5b1f9b4bc206492a9f6a92e18e Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <3b2c6fae4d780e5b1f9b4bc206492a9f6a92e18e@dist-git>
9119d9
From: Francesco Romani <fromani@redhat.com>
9119d9
Date: Wed, 1 Oct 2014 11:20:14 +0200
9119d9
Subject: [PATCH] qemu: bulk stats: implement VCPU group
9119d9
9119d9
https://bugzilla.redhat.com/show_bug.cgi?id=1113116
9119d9
9119d9
This patch implements the VIR_DOMAIN_STATS_VCPU group of statistics. To
9119d9
do so, this patch also extracts a helper to gather the vCPU information.
9119d9
9119d9
Signed-off-by: Francesco Romani <fromani@redhat.com>
9119d9
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
9119d9
(cherry picked from commit 74c066df4d8d9d49eee6a4416752440cdfaa8005)
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 include/libvirt/libvirt.h.in |   1 +
9119d9
 src/libvirt.c                |  12 +++
9119d9
 src/qemu/qemu_driver.c       | 205 +++++++++++++++++++++++++++++--------------
9119d9
 3 files changed, 154 insertions(+), 64 deletions(-)
9119d9
9119d9
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
9119d9
index 48ecea8..8754e1b 100644
9119d9
--- a/include/libvirt/libvirt.h.in
9119d9
+++ b/include/libvirt/libvirt.h.in
9119d9
@@ -2516,6 +2516,7 @@ typedef enum {
9119d9
     VIR_DOMAIN_STATS_STATE = (1 << 0), /* return domain state */
9119d9
     VIR_DOMAIN_STATS_CPU_TOTAL = (1 << 1), /* return domain CPU info */
9119d9
     VIR_DOMAIN_STATS_BALLOON = (1 << 2), /* return domain balloon info */
9119d9
+    VIR_DOMAIN_STATS_VCPU = (1 << 3), /* return domain virtual CPU info */
9119d9
 } virDomainStatsTypes;
9119d9
 
9119d9
 typedef enum {
9119d9
diff --git a/src/libvirt.c b/src/libvirt.c
9119d9
index 64ef74b..f2f6f43 100644
9119d9
--- a/src/libvirt.c
9119d9
+++ b/src/libvirt.c
9119d9
@@ -21569,6 +21569,18 @@ virConnectGetDomainCapabilities(virConnectPtr conn,
9119d9
  * "balloon.maximum" - the maximum memory in kiB allowed
9119d9
  *                     as unsigned long long.
9119d9
  *
9119d9
+ * VIR_DOMAIN_STATS_VCPU: Return virtual CPU statistics.
9119d9
+ * Due to VCPU hotplug, the vcpu.<num>.* array could be sparse.
9119d9
+ * The actual size of the array corresponds to "vcpu.current".
9119d9
+ * The array size will never exceed "vcpu.maximum".
9119d9
+ * The typed parameter keys are in this format:
9119d9
+ * "vcpu.current" - current number of online virtual CPUs as unsigned int.
9119d9
+ * "vcpu.maximum" - maximum number of online virtual CPUs as unsigned int.
9119d9
+ * "vcpu.<num>.state" - state of the virtual CPU <num>, as int
9119d9
+ *                      from virVcpuState enum.
9119d9
+ * "vcpu.<num>.time" - virtual cpu time spent by virtual CPU <num>
9119d9
+ *                     as unsigned long long.
9119d9
+ *
9119d9
  * Using 0 for @stats returns all stats groups supported by the given
9119d9
  * hypervisor.
9119d9
  *
9119d9
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
9119d9
index 71a0e0e..ef2e401 100644
9119d9
--- a/src/qemu/qemu_driver.c
9119d9
+++ b/src/qemu/qemu_driver.c
9119d9
@@ -1382,6 +1382,76 @@ qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
9119d9
 }
9119d9
 
9119d9
 
9119d9
+static int
9119d9
+qemuDomainHelperGetVcpus(virDomainObjPtr vm, virVcpuInfoPtr info, int maxinfo,
9119d9
+                         unsigned char *cpumaps, int maplen)
9119d9
+{
9119d9
+    int maxcpu, hostcpus;
9119d9
+    size_t i, v;
9119d9
+    qemuDomainObjPrivatePtr priv = vm->privateData;
9119d9
+
9119d9
+    if ((hostcpus = nodeGetCPUCount()) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
+    maxcpu = maplen * 8;
9119d9
+    if (maxcpu > hostcpus)
9119d9
+        maxcpu = hostcpus;
9119d9
+
9119d9
+    /* Clamp to actual number of vcpus */
9119d9
+    if (maxinfo > priv->nvcpupids)
9119d9
+        maxinfo = priv->nvcpupids;
9119d9
+
9119d9
+    if (maxinfo >= 1) {
9119d9
+        if (info != NULL) {
9119d9
+            memset(info, 0, sizeof(*info) * maxinfo);
9119d9
+            for (i = 0; i < maxinfo; i++) {
9119d9
+                info[i].number = i;
9119d9
+                info[i].state = VIR_VCPU_RUNNING;
9119d9
+
9119d9
+                if (priv->vcpupids != NULL &&
9119d9
+                    qemuGetProcessInfo(&(info[i].cpuTime),
9119d9
+                                       &(info[i].cpu),
9119d9
+                                       NULL,
9119d9
+                                       vm->pid,
9119d9
+                                       priv->vcpupids[i]) < 0) {
9119d9
+                    virReportSystemError(errno, "%s",
9119d9
+                                         _("cannot get vCPU placement & pCPU time"));
9119d9
+                    return -1;
9119d9
+                }
9119d9
+            }
9119d9
+        }
9119d9
+
9119d9
+        if (cpumaps != NULL) {
9119d9
+            memset(cpumaps, 0, maplen * maxinfo);
9119d9
+            if (priv->vcpupids != NULL) {
9119d9
+                for (v = 0; v < maxinfo; v++) {
9119d9
+                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
9119d9
+                    virBitmapPtr map = NULL;
9119d9
+                    unsigned char *tmpmap = NULL;
9119d9
+                    int tmpmapLen = 0;
9119d9
+
9119d9
+                    if (virProcessGetAffinity(priv->vcpupids[v],
9119d9
+                                              &map, maxcpu) < 0)
9119d9
+                        return -1;
9119d9
+                    virBitmapToData(map, &tmpmap, &tmpmapLen);
9119d9
+                    if (tmpmapLen > maplen)
9119d9
+                        tmpmapLen = maplen;
9119d9
+                    memcpy(cpumap, tmpmap, tmpmapLen);
9119d9
+
9119d9
+                    VIR_FREE(tmpmap);
9119d9
+                    virBitmapFree(map);
9119d9
+                }
9119d9
+            } else {
9119d9
+                virReportError(VIR_ERR_OPERATION_INVALID,
9119d9
+                               "%s", _("cpu affinity is not available"));
9119d9
+                return -1;
9119d9
+            }
9119d9
+        }
9119d9
+    }
9119d9
+    return maxinfo;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 static virDomainPtr qemuDomainLookupByID(virConnectPtr conn,
9119d9
                                          int id)
9119d9
 {
9119d9
@@ -5005,10 +5075,7 @@ qemuDomainGetVcpus(virDomainPtr dom,
9119d9
                    int maplen)
9119d9
 {
9119d9
     virDomainObjPtr vm;
9119d9
-    size_t i;
9119d9
-    int v, maxcpu, hostcpus;
9119d9
     int ret = -1;
9119d9
-    qemuDomainObjPrivatePtr priv;
9119d9
 
9119d9
     if (!(vm = qemuDomObjFromDomain(dom)))
9119d9
         goto cleanup;
9119d9
@@ -5023,67 +5090,7 @@ qemuDomainGetVcpus(virDomainPtr dom,
9119d9
         goto cleanup;
9119d9
     }
9119d9
 
9119d9
-    priv = vm->privateData;
9119d9
-
9119d9
-    if ((hostcpus = nodeGetCPUCount()) < 0)
9119d9
-        goto cleanup;
9119d9
-
9119d9
-    maxcpu = maplen * 8;
9119d9
-    if (maxcpu > hostcpus)
9119d9
-        maxcpu = hostcpus;
9119d9
-
9119d9
-    /* Clamp to actual number of vcpus */
9119d9
-    if (maxinfo > priv->nvcpupids)
9119d9
-        maxinfo = priv->nvcpupids;
9119d9
-
9119d9
-    if (maxinfo >= 1) {
9119d9
-        if (info != NULL) {
9119d9
-            memset(info, 0, sizeof(*info) * maxinfo);
9119d9
-            for (i = 0; i < maxinfo; i++) {
9119d9
-                info[i].number = i;
9119d9
-                info[i].state = VIR_VCPU_RUNNING;
9119d9
-
9119d9
-                if (priv->vcpupids != NULL &&
9119d9
-                    qemuGetProcessInfo(&(info[i].cpuTime),
9119d9
-                                       &(info[i].cpu),
9119d9
-                                       NULL,
9119d9
-                                       vm->pid,
9119d9
-                                       priv->vcpupids[i]) < 0) {
9119d9
-                    virReportSystemError(errno, "%s",
9119d9
-                                         _("cannot get vCPU placement & pCPU time"));
9119d9
-                    goto cleanup;
9119d9
-                }
9119d9
-            }
9119d9
-        }
9119d9
-
9119d9
-        if (cpumaps != NULL) {
9119d9
-            memset(cpumaps, 0, maplen * maxinfo);
9119d9
-            if (priv->vcpupids != NULL) {
9119d9
-                for (v = 0; v < maxinfo; v++) {
9119d9
-                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
9119d9
-                    virBitmapPtr map = NULL;
9119d9
-                    unsigned char *tmpmap = NULL;
9119d9
-                    int tmpmapLen = 0;
9119d9
-
9119d9
-                    if (virProcessGetAffinity(priv->vcpupids[v],
9119d9
-                                              &map, maxcpu) < 0)
9119d9
-                        goto cleanup;
9119d9
-                    virBitmapToData(map, &tmpmap, &tmpmapLen);
9119d9
-                    if (tmpmapLen > maplen)
9119d9
-                        tmpmapLen = maplen;
9119d9
-                    memcpy(cpumap, tmpmap, tmpmapLen);
9119d9
-
9119d9
-                    VIR_FREE(tmpmap);
9119d9
-                    virBitmapFree(map);
9119d9
-                }
9119d9
-            } else {
9119d9
-                virReportError(VIR_ERR_OPERATION_INVALID,
9119d9
-                               "%s", _("cpu affinity is not available"));
9119d9
-                goto cleanup;
9119d9
-            }
9119d9
-        }
9119d9
-    }
9119d9
-    ret = maxinfo;
9119d9
+    ret = qemuDomainHelperGetVcpus(vm, info, maxinfo, cpumaps, maplen);
9119d9
 
9119d9
  cleanup:
9119d9
     if (vm)
9119d9
@@ -17524,6 +17531,75 @@ qemuDomainGetStatsBalloon(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
9119d9
     return 0;
9119d9
 }
9119d9
 
9119d9
+
9119d9
+static int
9119d9
+qemuDomainGetStatsVcpu(virQEMUDriverPtr driver ATTRIBUTE_UNUSED,
9119d9
+                       virDomainObjPtr dom,
9119d9
+                       virDomainStatsRecordPtr record,
9119d9
+                       int *maxparams,
9119d9
+                       unsigned int privflags ATTRIBUTE_UNUSED)
9119d9
+{
9119d9
+    size_t i;
9119d9
+    int ret = -1;
9119d9
+    char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
9119d9
+    virVcpuInfoPtr cpuinfo = NULL;
9119d9
+
9119d9
+    if (virTypedParamsAddUInt(&record->params,
9119d9
+                              &record->nparams,
9119d9
+                              maxparams,
9119d9
+                              "vcpu.current",
9119d9
+                              (unsigned) dom->def->vcpus) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
+    if (virTypedParamsAddUInt(&record->params,
9119d9
+                              &record->nparams,
9119d9
+                              maxparams,
9119d9
+                              "vcpu.maximum",
9119d9
+                              (unsigned) dom->def->maxvcpus) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
+    if (VIR_ALLOC_N(cpuinfo, dom->def->vcpus) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
+    if (qemuDomainHelperGetVcpus(dom, cpuinfo, dom->def->vcpus,
9119d9
+                                 NULL, 0) < 0) {
9119d9
+        virResetLastError();
9119d9
+        ret = 0; /* it's ok to be silent and go ahead */
9119d9
+        goto cleanup;
9119d9
+    }
9119d9
+
9119d9
+    for (i = 0; i < dom->def->vcpus; i++) {
9119d9
+        snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
9119d9
+                 "vcpu.%zu.state", i);
9119d9
+        if (virTypedParamsAddInt(&record->params,
9119d9
+                                 &record->nparams,
9119d9
+                                 maxparams,
9119d9
+                                 param_name,
9119d9
+                                 cpuinfo[i].state) < 0)
9119d9
+            goto cleanup;
9119d9
+
9119d9
+        /* stats below are available only if the VM is alive */
9119d9
+        if (!virDomainObjIsActive(dom))
9119d9
+            continue;
9119d9
+
9119d9
+        snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
9119d9
+                 "vcpu.%zu.time", i);
9119d9
+        if (virTypedParamsAddULLong(&record->params,
9119d9
+                                    &record->nparams,
9119d9
+                                    maxparams,
9119d9
+                                    param_name,
9119d9
+                                    cpuinfo[i].cpuTime) < 0)
9119d9
+            goto cleanup;
9119d9
+    }
9119d9
+
9119d9
+    ret = 0;
9119d9
+
9119d9
+ cleanup:
9119d9
+    VIR_FREE(cpuinfo);
9119d9
+    return ret;
9119d9
+}
9119d9
+
9119d9
+
9119d9
 typedef int
9119d9
 (*qemuDomainGetStatsFunc)(virQEMUDriverPtr driver,
9119d9
                           virDomainObjPtr dom,
9119d9
@@ -17541,6 +17617,7 @@ static struct qemuDomainGetStatsWorker qemuDomainGetStatsWorkers[] = {
9119d9
     { qemuDomainGetStatsState, VIR_DOMAIN_STATS_STATE, false },
9119d9
     { qemuDomainGetStatsCpu, VIR_DOMAIN_STATS_CPU_TOTAL, false },
9119d9
     { qemuDomainGetStatsBalloon, VIR_DOMAIN_STATS_BALLOON, true },
9119d9
+    { qemuDomainGetStatsVcpu, VIR_DOMAIN_STATS_VCPU, false },
9119d9
     { NULL, 0, false }
9119d9
 };
9119d9
 
9119d9
-- 
9119d9
2.1.2
9119d9