[PATCH v3 1/1] qemu: add per-vcpu delay stats

Aleksei Zakharov zaharov at selectel.ru
Mon Feb 15 11:21:45 UTC 2021


This patch adds delay time (steal time inside guest) to libvirt
domain per-vcpu stats. Delay time is a consequence of the overloaded
CPU. Knowledge of the delay time of a virtual machine helps to react
exactly when needed and rebalance the load between hosts.
This is used by cloud providers to provide quality of service,
especially when the CPU is oversubscripted.

It's more convenient to work with this metric in a context of a
libvirt domain. Any monitoring software may use this information.

Signed-off-by: Aleksei Zakharov <zaharov at selectel.ru>
---
 src/qemu/qemu_driver.c | 40 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 3d54653217..319bc60632 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1332,6 +1332,29 @@ static char *qemuConnectGetCapabilities(virConnectPtr conn) {
     return virCapabilitiesFormatXML(caps);
 }
 
+static int
+qemuGetSchedstatDelay(unsigned long long *cpudelay,
+                 pid_t pid, pid_t tid)
+{
+    g_autofree char *proc = NULL;
+    unsigned long long oncpu = 0;
+    g_autofree FILE *schedstat = NULL;
+
+    if (tid)
+        proc = g_strdup_printf("/proc/%d/task/%d/schedstat", (int)pid, (int)tid);
+    else
+        proc = g_strdup_printf("/proc/%d/schedstat", (int)pid);
+    if (!proc)
+        return -1;
+
+    schedstat = fopen(proc, "r");
+    if (!schedstat || fscanf(schedstat, "%llu %llu", &oncpu, cpudelay) < 2) {
+            return -1;
+    }
+
+    VIR_FORCE_FCLOSE(schedstat);
+    return 0;
+}
 
 static int
 qemuGetSchedInfo(unsigned long long *cpuWait,
@@ -1470,6 +1493,7 @@ static int
 qemuDomainHelperGetVcpus(virDomainObjPtr vm,
                          virVcpuInfoPtr info,
                          unsigned long long *cpuwait,
+                         unsigned long long *cpudelay,
                          int maxinfo,
                          unsigned char *cpumaps,
                          int maplen)
@@ -1529,6 +1553,11 @@ qemuDomainHelperGetVcpus(virDomainObjPtr vm,
                 return -1;
         }
 
+        if (cpudelay) {
+            if (qemuGetSchedstatDelay(&(cpudelay[ncpuinfo]), vm->pid, vcpupid) < 0)
+                return -1;
+        }
+
         ncpuinfo++;
     }
 
@@ -4873,7 +4902,7 @@ qemuDomainGetVcpus(virDomainPtr dom,
         goto cleanup;
     }
 
-    ret = qemuDomainHelperGetVcpus(vm, info, NULL, maxinfo, cpumaps, maplen);
+    ret = qemuDomainHelperGetVcpus(vm, info, NULL, NULL, maxinfo, cpumaps, maplen);
 
  cleanup:
     virDomainObjEndAPI(&vm);
@@ -17870,7 +17899,6 @@ qemuDomainGetStatsMemoryBandwidth(virQEMUDriverPtr driver,
     return ret;
 }
 
-
 static int
 qemuDomainGetStatsCpuCache(virQEMUDriverPtr driver,
                            virDomainObjPtr dom,
@@ -18060,6 +18088,7 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver,
     int ret = -1;
     virVcpuInfoPtr cpuinfo = NULL;
     g_autofree unsigned long long *cpuwait = NULL;
+    g_autofree unsigned long long *cpudelay = NULL;
 
     if (virTypedParamListAddUInt(params, virDomainDefGetVcpus(dom->def),
                                  "vcpu.current") < 0)
@@ -18071,6 +18100,7 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver,
 
     cpuinfo = g_new0(virVcpuInfo, virDomainDefGetVcpus(dom->def));
     cpuwait = g_new0(unsigned long long, virDomainDefGetVcpus(dom->def));
+    cpudelay = g_new0(unsigned long long, virDomainDefGetVcpus(dom->def));
 
     if (HAVE_JOB(privflags) && virDomainObjIsActive(dom) &&
         qemuDomainRefreshVcpuHalted(driver, dom, QEMU_ASYNC_JOB_NONE) < 0) {
@@ -18079,7 +18109,7 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver,
             virResetLastError();
     }
 
-    if (qemuDomainHelperGetVcpus(dom, cpuinfo, cpuwait,
+    if (qemuDomainHelperGetVcpus(dom, cpuinfo, cpuwait, cpudelay,
                                  virDomainDefGetVcpus(dom->def),
                                  NULL, 0) < 0) {
         virResetLastError();
@@ -18104,6 +18134,10 @@ qemuDomainGetStatsVcpu(virQEMUDriverPtr driver,
                                        "vcpu.%u.wait", cpuinfo[i].number) < 0)
             goto cleanup;
 
+        if (virTypedParamListAddULLong(params, cpudelay[i],
+                                        "vcpu.%u.delay", cpuinfo[i].number) < 0)
+            goto cleanup;
+
         /* state below is extracted from the individual vcpu structs */
         if (!(vcpu = virDomainDefGetVcpu(dom->def, cpuinfo[i].number)))
             continue;
-- 
2.17.1




More information about the libvir-list mailing list