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 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list