[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 = &params[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