[libvirt] [PATCH v2] BSD: implement nodeGetCPUStats
Daniel P. Berrange
berrange at redhat.com
Fri Jan 17 11:39:17 UTC 2014
On Wed, Jan 15, 2014 at 10:42:41PM +0400, Roman Bogorodskiy wrote:
> Implementation obtains CPU usage information using
> kern.cp_time and kern.cp_times sysctl(8)s and reports
> CPU utilization.
> ---
> include/libvirt/libvirt.h.in | 8 ++++
> src/nodeinfo.c | 104 +++++++++++++++++++++++++++++++++++++++++++
> tools/virsh-host.c | 11 ++++-
> 3 files changed, 121 insertions(+), 2 deletions(-)
>
> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> index 018a5ce..88afe20 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -692,6 +692,14 @@ typedef enum {
> #define VIR_NODE_CPU_STATS_IOWAIT "iowait"
>
> /**
> + * VIR_NODE_CPU_STATS_INTR:
> + *
> + * The cumulative interrupt CPU time,
> + * since the node booting up (in nanoseconds).
> + */
> +#define VIR_NODE_CPU_STATS_INTR "intr"
> +
> +/**
> * VIR_NODE_CPU_STATS_UTILIZATION:
> *
> * The CPU utilization of a node.
> diff --git a/src/nodeinfo.c b/src/nodeinfo.c
> index 05bc038..fd2f8c8 100644
> --- a/src/nodeinfo.c
> +++ b/src/nodeinfo.c
> @@ -34,8 +34,10 @@
> #include "conf/domain_conf.h"
>
> #if defined(__FreeBSD__) || defined(__APPLE__)
> +# include <sys/time.h>
> # include <sys/types.h>
> # include <sys/sysctl.h>
> +# include <sys/resource.h>
> #endif
>
> #include "c-ctype.h"
> @@ -99,8 +101,108 @@ appleFreebsdNodeGetMemorySize(unsigned long *memory)
> #endif /* defined(__FreeBSD__) || defined(__APPLE__) */
>
> #ifdef __FreeBSD__
> +# define BSD_CPU_STATS_ALL 4
> # define BSD_MEMORY_STATS_ALL 4
>
> +# define TICK_TO_NSEC (1000ull * 1000ull * 1000ull / (stathz ? stathz : hz))
> +
> +static int
> +freebsdNodeGetCPUStats(int cpuNum,
> + virNodeCPUStatsPtr params,
> + int *nparams)
> +{
> + const char *sysctl_name;
> + long *cpu_times;
> + struct clockinfo clkinfo;
> + size_t i, j, cpu_times_size, clkinfo_size;
> + int cpu_times_num, offset, hz, stathz, ret = -1;
> + struct field_cpu_map {
> + const char *field;
> + int idx[CPUSTATES];
> + } cpu_map[] = {
> + {VIR_NODE_CPU_STATS_KERNEL, {CP_SYS}},
> + {VIR_NODE_CPU_STATS_USER, {CP_USER, CP_NICE}},
> + {VIR_NODE_CPU_STATS_IDLE, {CP_IDLE}},
> + {VIR_NODE_CPU_STATS_INTR, {CP_INTR}},
> + {NULL, {0}}
> + };
> +
> + if ((*nparams) == 0) {
> + *nparams = BSD_CPU_STATS_ALL;
> + return 0;
> + }
> +
> + if ((*nparams) != BSD_CPU_STATS_ALL) {
> + virReportInvalidArg(*nparams,
> + _("nparams in %s must be equal to %d"),
> + __FUNCTION__, BSD_CPU_STATS_ALL);
> + return -1;
> + }
> +
> + clkinfo_size = sizeof(clkinfo);
> + if (sysctlbyname("kern.clockrate", &clkinfo, &clkinfo_size, NULL, 0) < 0) {
> + virReportSystemError(errno,
> + _("sysctl failed for '%s'"),
> + "kern.clockrate");
> + return -1;
> + }
> +
> + stathz = clkinfo.stathz;
> + hz = clkinfo.hz;
> +
> + if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS) {
> + sysctl_name = "kern.cp_time";
> + cpu_times_num = 1;
> + offset = 0;
> + } else {
> + sysctl_name = "kern.cp_times";
> + cpu_times_num = appleFreebsdNodeGetCPUCount();
> +
> + if (cpuNum >= cpu_times_num) {
> + virReportInvalidArg(cpuNum,
> + _("Invalid cpuNum in %s"),
> + __FUNCTION__);
> + return -1;
> + }
> +
> + offset = cpu_times_num * CPUSTATES;
> + }
> +
> + cpu_times_size = sizeof(long) * cpu_times_num * CPUSTATES;
> +
> + if (VIR_ALLOC_N(cpu_times, cpu_times_num * CPUSTATES) < 0)
> + goto cleanup;
> +
> + if (sysctlbyname(sysctl_name, cpu_times, &cpu_times_size, NULL, 0) < 0) {
> + virReportSystemError(errno,
> + _("sysctl failed for '%s'"),
> + sysctl_name);
> + goto cleanup;
> + }
> +
> + for (i = 0; cpu_map[i].field != NULL; i++) {
> + virNodeCPUStatsPtr param = ¶ms[i];
> +
> + if (virStrcpyStatic(param->field, cpu_map[i].field) == NULL) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Field '%s' too long for destination"),
> + cpu_map[i].field);
> + goto cleanup;
> + }
> +
> + param->value = 0;
> + for (j = 0; j < ARRAY_CARDINALITY(cpu_map[i].idx); j++)
> + param->value += cpu_times[offset + cpu_map[i].idx[j]] * TICK_TO_NSEC;
> + }
> +
> + ret = 0;
> +
> +cleanup:
> + VIR_FREE(cpu_times);
> +
> + return ret;
> +}
> +
> static int
> freebsdNodeGetMemoryStats(virNodeMemoryStatsPtr params,
> int *nparams)
> @@ -1066,6 +1168,8 @@ int nodeGetCPUStats(int cpuNum ATTRIBUTE_UNUSED,
>
> return ret;
> }
> +#elif defined(__FreeBSD__)
> + return freebsdNodeGetCPUStats(cpuNum, params, nparams);
> #else
> virReportError(VIR_ERR_NO_SUPPORT, "%s",
> _("node CPU stats not implemented on this platform"));
> diff --git a/tools/virsh-host.c b/tools/virsh-host.c
> index 1d1bb97..ac41177 100644
> --- a/tools/virsh-host.c
> +++ b/tools/virsh-host.c
> @@ -347,9 +347,10 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
> unsigned long long sys;
> unsigned long long idle;
> unsigned long long iowait;
> + unsigned long long intr;
> unsigned long long util;
> } cpu_stats[2];
> - double user_time, sys_time, idle_time, iowait_time, total_time;
> + double user_time, sys_time, idle_time, iowait_time, intr_time, total_time;
> double usage;
>
> if (vshCommandOptInt(cmd, "cpu", &cpuNum) < 0) {
> @@ -390,6 +391,8 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
> cpu_stats[i].idle = value;
> } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) {
> cpu_stats[i].iowait = value;
> + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_INTR)) {
> + cpu_stats[i].intr = value;
> } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) {
> cpu_stats[i].util = value;
> flag_utilization = true;
> @@ -406,6 +409,7 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
> vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys);
> vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle);
> vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait);
> + vshPrint(ctl, "%-15s %20llu\n", _("intr:"), cpu_stats[0].intr);
> }
> } else {
> if (flag_utilization) {
> @@ -418,7 +422,8 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
> sys_time = cpu_stats[1].sys - cpu_stats[0].sys;
> idle_time = cpu_stats[1].idle - cpu_stats[0].idle;
> iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait;
> - total_time = user_time + sys_time + idle_time + iowait_time;
> + intr_time = cpu_stats[1].intr - cpu_stats[0].intr;
> + total_time = user_time + sys_time + idle_time + iowait_time + intr_time;
>
> usage = (user_time + sys_time) / total_time * 100;
>
> @@ -432,6 +437,8 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd)
> _("idle:"), idle_time / total_time * 100);
> vshPrint(ctl, "%-15s %5.1lf%%\n",
> _("iowait:"), iowait_time / total_time * 100);
> + vshPrint(ctl, "%-15s %5.1lf%%\n",
> + _("intr:"), intr_time / total_time * 100);
> }
> }
ACK looks reasonable to me.
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
More information about the libvir-list
mailing list