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(a)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(¶ms[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