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@xxxxxxxxxxx> --- 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