[PATCH] qemu: add delay time cpu stats

Aleksei Zakharov zaharov at selectel.ru
Fri Jan 29 14:34:02 UTC 2021


This commit adds delay time (steal time inside guest) to libvirt
domain CPU stats. It's more convenient to work with this statistic
in a context of libvirt domain. Any monitoring software may use
this information.

As an example: the next step is to add support to
libvirt-go and expose metrics with libvirt-exporter.

Signed-off-by: Aleksei Zakharov <zaharov at selectel.ru>
---
 include/libvirt/libvirt-domain.h |  6 ++++
 src/qemu/qemu_driver.c           | 56 ++++++++++++++++++++++++++++++++
 tools/virsh-domain.c             |  3 +-
 3 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index de2456812c..b3f9f375a5 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -1350,6 +1350,12 @@ int                     virDomainGetState       (virDomainPtr domain,
  */
 # define VIR_DOMAIN_CPU_STATS_SYSTEMTIME "system_time"
 
+/**
+ * VIR_DOMAIN_CPU_STATS_DELAYTIME:
+ * cpu time waiting on runqueue in nanoseconds, as a ullong
+ */
+# define VIR_DOMAIN_CPU_STATS_DELAYTIME "delay_time"
+
 /**
  * VIR_DOMAIN_CPU_STATS_VCPUTIME:
  * vcpu usage in nanoseconds (cpu_time excluding hypervisor time),
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6193376544..41839a0239 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16674,6 +16674,36 @@ qemuDomainGetMetadata(virDomainPtr dom,
     return ret;
 }
 
+static int
+virSchedstatGetDelay(virDomainObjPtr dom, unsigned long long *delay)
+{
+    char *proc = NULL;
+    FILE* schedstat;
+    unsigned long long curr_delay, oncpu = 0;
+    pid_t pid = dom->pid;
+    for (size_t i = 0; i < virDomainDefGetVcpusMax(dom->def); i++) {
+        pid_t vcpupid = qemuDomainGetVcpuPid(dom, i);
+        if (vcpupid) {
+            if (asprintf(&proc, "/proc/%d/task/%d/schedstat",
+                                    pid, vcpupid) < 0)
+                return -1;
+        } else {
+            if (asprintf(&proc, "/proc/%d/schedstat", pid) < 0)
+                return -1;
+        }
+        schedstat = fopen(proc, "r");
+        VIR_FREE(proc);
+        if (!schedstat ||
+            fscanf(schedstat, "%llu %llu",
+                &oncpu, &curr_delay) < 2) {
+                return -1;
+        }
+
+        *delay += curr_delay;
+    }
+    return 0;
+}
+
 
 static int
 qemuDomainGetCPUStats(virDomainPtr domain,
@@ -16687,6 +16717,7 @@ qemuDomainGetCPUStats(virDomainPtr domain,
     int ret = -1;
     qemuDomainObjPrivatePtr priv;
     virBitmapPtr guestvcpus = NULL;
+    unsigned long long delay = 0;
 
     virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
 
@@ -16712,8 +16743,19 @@ qemuDomainGetCPUStats(virDomainPtr domain,
         goto cleanup;
 
     if (start_cpu == -1)
+    {
         ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
                                               params, nparams);
+        if (nparams > 3) {
+            if (virSchedstatGetDelay(vm,&delay) < 0)
+                return -1;
+            if (virTypedParameterAssign(&params[3],
+                            VIR_DOMAIN_CPU_STATS_DELAYTIME,
+                            VIR_TYPED_PARAM_ULLONG, delay) < 0)
+		return -1;
+        }
+        ret++;
+    }
     else
         ret = virCgroupGetPercpuStats(priv->cgroup, params, nparams,
                                       start_cpu, ncpus, guestvcpus);
@@ -17845,6 +17887,17 @@ qemuDomainGetStatsMemoryBandwidth(virQEMUDriverPtr driver,
     return ret;
 }
 
+static int
+qemuDomainGetStatsCpuDelay(virDomainObjPtr dom,
+                           virTypedParamListPtr params)
+{
+    unsigned long long delay_time = 0;
+    int err = 0;
+    err = virSchedstatGetDelay(dom, &delay_time);
+    if (!err && virTypedParamListAddULLong(params, delay_time, "cpu.delay") < 0)
+        return -1;
+    return 0;
+}
 
 static int
 qemuDomainGetStatsCpuCache(virQEMUDriverPtr driver,
@@ -17950,6 +18003,9 @@ qemuDomainGetStatsCpu(virQEMUDriverPtr driver,
     if (qemuDomainGetStatsCpuCache(driver, dom, params) < 0)
         return -1;
 
+    if (qemuDomainGetStatsCpuDelay(dom, params) < 0)
+        return -1;
+
     return 0;
 }
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 2bb136333f..a1780da1a5 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -8085,7 +8085,8 @@ vshCPUStatsPrintField(vshControl *ctl,
     if ((STREQ(param->field, VIR_DOMAIN_CPU_STATS_CPUTIME) ||
          STREQ(param->field, VIR_DOMAIN_CPU_STATS_VCPUTIME) ||
          STREQ(param->field, VIR_DOMAIN_CPU_STATS_USERTIME) ||
-         STREQ(param->field, VIR_DOMAIN_CPU_STATS_SYSTEMTIME)) &&
+         STREQ(param->field, VIR_DOMAIN_CPU_STATS_SYSTEMTIME) ||
+         STREQ(param->field, VIR_DOMAIN_CPU_STATS_DELAYTIME)) &&
         param->type == VIR_TYPED_PARAM_ULLONG) {
         vshPrint(ctl, "%9lld.%09lld seconds\n",
                  param->value.ul / 1000000000,
-- 
2.17.1




More information about the libvir-list mailing list