From 759095f6367cf5ab3b66ab9916594d12cbc6e95e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 Mar 2012 08:20:20 -0700 Subject: [PATCH] cpustats: report user and sys times Thanks to cgroups, providing user vs. system time of the overall guest is easy to add to our existing API. * include/libvirt/libvirt.h.in (VIR_DOMAIN_CPU_STATS_USERTIME) (VIR_DOMAIN_CPU_STATS_SYSTEMTIME): New constants. * src/util/virtypedparam.h (virTypedParameterArrayValidate) (virTypedParameterAssign): Enforce checking the result. * src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Fix offender. (qemuDomainGetTotalcpuStats): Implement new parameters. * tools/virsh.c (cmdCPUStats): Tweak output accordingly. --- include/libvirt/libvirt.h.in | 12 ++++++++++ src/qemu/qemu_driver.c | 45 +++++++++++++++++++++++++++++------- src/util/virtypedparam.h | 5 ++-- tools/virsh.c | 12 ++++++---- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 66883fbb75..7d41642e2c 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1332,6 +1332,18 @@ int virDomainGetState (virDomainPtr domain, */ #define VIR_DOMAIN_CPU_STATS_CPUTIME "cpu_time" +/** + * VIR_DOMAIN_CPU_STATS_USERTIME: + * cpu time charged to user instructions in nanoseconds, as a ullong + */ +#define VIR_DOMAIN_CPU_STATS_USERTIME "user_time" + +/** + * VIR_DOMAIN_CPU_STATS_SYSTEMTIME: + * cpu time charged to system instructions in nanoseconds, as a ullong + */ +#define VIR_DOMAIN_CPU_STATS_SYSTEMTIME "system_time" + int virDomainGetCPUStats(virDomainPtr domain, virTypedParameterPtr params, unsigned int nparams, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index be678f3652..3147a9bf64 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -101,6 +101,9 @@ #define QEMU_NB_NUMA_PARAM 2 +#define QEMU_NB_TOTAL_CPU_STAT_PARAM 3 +#define QEMU_NB_PER_CPU_STAT_PARAM 1 + #if HAVE_LINUX_KVM_H # include #endif @@ -12145,11 +12148,10 @@ qemuDomainGetTotalcpuStats(virCgroupPtr group, int nparams) { unsigned long long cpu_time; - int param_idx = 0; int ret; if (nparams == 0) /* return supported number of params */ - return 1; + return QEMU_NB_TOTAL_CPU_STAT_PARAM; /* entry 0 is cputime */ ret = virCgroupGetCpuacctUsage(group, &cpu_time); if (ret < 0) { @@ -12157,9 +12159,35 @@ qemuDomainGetTotalcpuStats(virCgroupPtr group, return -1; } - virTypedParameterAssign(¶ms[param_idx], VIR_DOMAIN_CPU_STATS_CPUTIME, - VIR_TYPED_PARAM_ULLONG, cpu_time); - return 1; + if (virTypedParameterAssign(¶ms[0], VIR_DOMAIN_CPU_STATS_CPUTIME, + VIR_TYPED_PARAM_ULLONG, cpu_time) < 0) + return -1; + + if (nparams > 1) { + unsigned long long user; + unsigned long long sys; + + ret = virCgroupGetCpuacctStat(group, &user, &sys); + if (ret < 0) { + virReportSystemError(-ret, "%s", _("unable to get cpu account")); + return -1; + } + + if (virTypedParameterAssign(¶ms[1], + VIR_DOMAIN_CPU_STATS_USERTIME, + VIR_TYPED_PARAM_ULLONG, user) < 0) + return -1; + if (nparams > 2 && + virTypedParameterAssign(¶ms[2], + VIR_DOMAIN_CPU_STATS_SYSTEMTIME, + VIR_TYPED_PARAM_ULLONG, sys) < 0) + return -1; + + if (nparams > QEMU_NB_TOTAL_CPU_STAT_PARAM) + nparams = QEMU_NB_TOTAL_CPU_STAT_PARAM; + } + + return nparams; } static int @@ -12180,7 +12208,7 @@ qemuDomainGetPercpuStats(virDomainPtr domain, /* return the number of supported params */ if (nparams == 0 && ncpus != 0) - return 1; /* only cpu_time is supported */ + return QEMU_NB_PER_CPU_STAT_PARAM; /* only cpu_time is supported */ /* return percpu cputime in index 0 */ param_idx = 0; @@ -12223,8 +12251,9 @@ qemuDomainGetPercpuStats(virDomainPtr domain, if (i < start_cpu) continue; ent = ¶ms[ (i - start_cpu) * nparams + param_idx]; - virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME, - VIR_TYPED_PARAM_ULLONG, cpu_time); + if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME, + VIR_TYPED_PARAM_ULLONG, cpu_time) < 0) + goto cleanup; } rv = param_idx + 1; cleanup: diff --git a/src/util/virtypedparam.h b/src/util/virtypedparam.h index 52cbe78d1d..7c513ed1f8 100644 --- a/src/util/virtypedparam.h +++ b/src/util/virtypedparam.h @@ -29,9 +29,10 @@ void virTypedParameterArrayClear(virTypedParameterPtr params, int nparams); int virTypedParameterArrayValidate(virTypedParameterPtr params, int nparams, /* const char *name, int type ... */ ...) - ATTRIBUTE_SENTINEL; + ATTRIBUTE_SENTINEL ATTRIBUTE_RETURN_CHECK; int virTypedParameterAssign(virTypedParameterPtr param, const char *name, - int type, /* TYPE arg */ ...); + int type, /* TYPE arg */ ...) + ATTRIBUTE_RETURN_CHECK; #endif /* __VIR_TYPED_PARAM_H */ diff --git a/tools/virsh.c b/tools/virsh.c index 9a16ef85d4..630b77f104 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -5630,10 +5630,10 @@ cmdCPUStats(vshControl *ctl, const vshCmd *cmd) for (j = 0; j < nparams; j++) { pos = i * nparams + j; - vshPrint(ctl, "\t%-10s ", params[pos].field); + vshPrint(ctl, "\t%-12s ", params[pos].field); if (STREQ(params[pos].field, VIR_DOMAIN_CPU_STATS_CPUTIME) && params[j].type == VIR_TYPED_PARAM_ULLONG) { - vshPrint(ctl, "%lld.%09lld seconds\n", + vshPrint(ctl, "%9lld.%09lld seconds\n", params[pos].value.ul / 1000000000, params[pos].value.ul % 1000000000); } else { @@ -5671,10 +5671,12 @@ do_show_total: vshPrint(ctl, _("Total:\n")); for (i = 0; i < nparams; i++) { - vshPrint(ctl, "\t%-10s ", params[i].field); - if (STREQ(params[i].field, VIR_DOMAIN_CPU_STATS_CPUTIME) && + vshPrint(ctl, "\t%-12s ", params[i].field); + if ((STREQ(params[i].field, VIR_DOMAIN_CPU_STATS_CPUTIME) || + STREQ(params[i].field, VIR_DOMAIN_CPU_STATS_USERTIME) || + STREQ(params[i].field, VIR_DOMAIN_CPU_STATS_SYSTEMTIME)) && params[i].type == VIR_TYPED_PARAM_ULLONG) { - vshPrint(ctl, "%llu.%09llu seconds\n", + vshPrint(ctl, "%9lld.%09lld seconds\n", params[i].value.ul / 1000000000, params[i].value.ul % 1000000000); } else {