summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 9a34b41)
raw | patch | inline | side by side (parent: 9a34b41)
author | Francesco Romani <fromani@redhat.com> | |
Mon, 9 Jan 2017 11:31:17 +0000 (12:31 +0100) | ||
committer | Francesco Romani <fromani@redhat.com> | |
Tue, 14 Feb 2017 14:30:19 +0000 (15:30 +0100) |
Add a metric to report physical cpu consumed by the hypervisor,
split per user/system time. This is provided by libvirt since version
0.9.11, and used by oVirt.
We also extend the newly-added 'ExtraStats' option to allow
users to toggle on/off the new metric. Default is off.
Signed-off-by: Francesco Romani <fromani@redhat.com>
split per user/system time. This is provided by libvirt since version
0.9.11, and used by oVirt.
We also extend the newly-added 'ExtraStats' option to allow
users to toggle on/off the new metric. Default is off.
Signed-off-by: Francesco Romani <fromani@redhat.com>
src/collectd.conf.in | patch | blob | history | |
src/collectd.conf.pod | patch | blob | history | |
src/virt.c | patch | blob | history |
diff --git a/src/collectd.conf.in b/src/collectd.conf.in
index 982cba9f32eaac594252c52aab7c314d9930c277..e4ab11170ea4be6fb187a689edc779b6330d48c4 100644 (file)
--- a/src/collectd.conf.in
+++ b/src/collectd.conf.in
# InterfaceFormat name
# PluginInstanceFormat name
# Instances 1
-# ExtraStats "disk"
+# ExtraStats "disk pcpu"
#</Plugin>
#<Plugin vmem>
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 9b32a7811ebfa2a9c7a90ea95a625df370798cb8..e1c75675de6abd5312bdf89b0cf61ddb18984948 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
Currently supported selectors are:
B<disk> report extra statistics like number of flush operations and total
service time for read, write and flush operations.
+B<pcpu> report the physical user/system cpu time consumed by the hypervisor, per-vm.
=back
diff --git a/src/virt.c b/src/virt.c
index 5a4604c86d53e4a539578331cc8a9c8b32f8e671..f2dccec45c3f34352f7debd1c1df470aa205e97c 100644 (file)
--- a/src/virt.c
+++ b/src/virt.c
#define PLUGIN_NAME "virt"
#ifdef LIBVIR_CHECK_VERSION
+
#if LIBVIR_CHECK_VERSION(0, 9, 5)
#define HAVE_BLOCK_STATS_FLAGS 1
#endif
+
+#if LIBVIR_CHECK_VERSION(0, 9, 11)
+#define HAVE_CPU_STATS 1
#endif
+#endif /* LIBVIR_CHECK_VERSION */
+
static const char *config_keys[] = {"Connection",
"RefreshInterval",
/* ExtraStats */
#define EX_STATS_MAX_FIELDS 8
-#define EX_STATS_DISK "disk"
-enum ex_stats { ex_stats_none = 0, ex_stats_disk = 1 };
-static enum ex_stats extra_stats = ex_stats_none;
+enum ex_stats { ex_stats_none = 0, ex_stats_disk = 1, ex_stats_pcpu = 2 };
+static unsigned int extra_stats = ex_stats_none;
+
+struct ex_stats_item {
+ const char *name;
+ enum ex_stats flag;
+};
+static const struct ex_stats_item ex_stats_table[] = {
+ {"disk", ex_stats_disk}, {"pcpu", ex_stats_pcpu}, {NULL, ex_stats_none},
+};
/* BlockDeviceFormatBasename */
_Bool blockdevice_format_basename = 0;
static int refresh_lists(struct lv_read_instance *inst);
+struct lv_info {
+ virDomainInfo di;
+ unsigned long long total_user_cpu_time;
+ unsigned long long total_syst_cpu_time;
+};
+
struct lv_block_info {
virDomainBlockStatsStruct bi;
ERROR("%s: %s", (s), err->message); \
} while (0)
+static void init_lv_info(struct lv_info *info) {
+ if (info != NULL)
+ memset(info, 0, sizeof(*info));
+}
+
+static int lv_domain_info(virDomainPtr dom, struct lv_info *info) {
+#ifdef HAVE_CPU_STATS
+ virTypedParameterPtr param = NULL;
+ int nparams = 0;
+#endif /* HAVE_CPU_STATS */
+ int ret = virDomainGetInfo(dom, &(info->di));
+ if (ret != 0) {
+ return ret;
+ }
+
+#ifdef HAVE_CPU_STATS
+ nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
+ if (nparams < 0) {
+ VIRT_ERROR(conn, "getting the CPU params count");
+ return -1;
+ }
+
+ param = calloc(nparams, sizeof(virTypedParameter));
+ if (param == NULL) {
+ ERROR("virt plugin: alloc(%i) for cpu parameters failed.", nparams);
+ return -1;
+ }
+
+ ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats.
+ if (ret < 0) {
+ virTypedParamsFree(param, nparams);
+ VIRT_ERROR(conn, "getting the disk params values");
+ return -1;
+ }
+
+ for (int i = 0; i < nparams; ++i) {
+ if (!strcmp(param[i].field, "user_time"))
+ info->total_user_cpu_time = param[i].value.ul;
+ else if (!strcmp(param[i].field, "system_time"))
+ info->total_syst_cpu_time = param[i].value.ul;
+ }
+
+ virTypedParamsFree(param, nparams);
+#endif /* HAVE_CPU_STATS */
+
+ return 0;
+}
+
static void init_value_list(value_list_t *vl, virDomainPtr dom) {
int n;
const char *name;
submit(dom, "memory", tags[tag_index], &(value_t){.gauge = value}, 1);
}
+static void submit_derive2(const char *type, derive_t v0, derive_t v1,
+ virDomainPtr dom, const char *devname) {
+ value_t values[] = {
+ {.derive = v0}, {.derive = v1},
+ };
+
+ submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values));
+} /* void submit_derive2 */
+
+static void pcpu_submit(virDomainPtr dom, struct lv_info *info) {
+#ifdef HAVE_CPU_STATS
+ if (extra_stats & ex_stats_pcpu)
+ submit_derive2("ps_cputime", info->total_user_cpu_time,
+ info->total_syst_cpu_time, dom, NULL);
+#endif /* HAVE_CPU_STATS */
+}
+
static void cpu_submit(unsigned long long value, virDomainPtr dom,
const char *type) {
submit(dom, type, NULL, &(value_t){.derive = (derive_t)value}, 1);
submit(dom, type, type_instance, &(value_t){.derive = value}, 1);
}
-static void submit_derive2(const char *type, derive_t v0, derive_t v1,
- virDomainPtr dom, const char *devname) {
- value_t values[] = {
- {.derive = v0}, {.derive = v1},
- };
-
- submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values));
-} /* void submit_derive2 */
-
static void disk_submit(struct lv_block_info *binfo, virDomainPtr dom,
const char *type_instance) {
char flush_type_instance[DATA_MAX_NAME_LEN];
}
}
+static unsigned int parse_ex_stats_flags(const char *exstats, int numexstats) {
+ int extra_stats = ex_stats_none;
+ for (int i = 0; i < numexstats; i++) {
+ for (int j = 0; ex_stats_table[j].name != NULL; j++) {
+ if (strcasecmp(exstats[i], ex_stats_table[j].name) == 0) {
+ DEBUG(PLUGIN_NAME " plugin: enabling extra stats for '%s'",
+ ex_stats_table[j].name);
+ extra_stats |= ex_stats_table[j].flag;
+ break;
+ }
+ }
+ }
+ return extra_stats;
+}
+
static int lv_config(const char *key, const char *value) {
if (virInitialize() != 0)
return 1;
}
if (strcasecmp(key, "ExtraStats") == 0) {
- char *localvalue = sstrdup(value);
+ char *localvalue = strdup(value);
if (localvalue != NULL) {
char *exstats[EX_STATS_MAX_FIELDS];
int numexstats =
strsplit(localvalue, exstats, STATIC_ARRAY_SIZE(exstats));
- for (int i = 0; i < numexstats; i++) {
- if (strcasecmp(exstats[i], EX_STATS_DISK) == 0) {
- DEBUG(PLUGIN_NAME " plugin: enabling extra stats for '%s'",
- EX_STATS_DISK);
- extra_stats |= ex_stats_disk;
- }
- }
+ extra_stats = parse_ex_stats_flags(exstats, numexstats);
sfree(localvalue);
}
}
/* Get CPU usage, memory, VCPU usage for each domain. */
for (int i = 0; i < state->nr_domains; ++i) {
- virDomainInfo info;
+ struct lv_info info;
virVcpuInfoPtr vinfo = NULL;
virDomainMemoryStatPtr minfo = NULL;
int status;
- status = virDomainGetInfo(state->domains[i], &info);
+ init_lv_info(&info);
+ status = lv_domain_info(state->domains[i], &info);
if (status != 0) {
ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
status);
continue;
}
- if (info.state != VIR_DOMAIN_RUNNING) {
+ if (info.di.state != VIR_DOMAIN_RUNNING) {
/* only gather stats for running domains */
continue;
}
- cpu_submit(info.cpuTime, state->domains[i], "virt_cpu_total");
- memory_submit((gauge_t)info.memory * 1024, state->domains[i]);
+ pcpu_submit(state->domains[i], &info);
+ cpu_submit(info.di.cpuTime, state->domains[i], "virt_cpu_total");
+ memory_submit((gauge_t)info.di.memory * 1024, state->domains[i]);
- vinfo = malloc(info.nrVirtCpu * sizeof(vinfo[0]));
+ vinfo = malloc(info.di.nrVirtCpu * sizeof(vinfo[0]));
if (vinfo == NULL) {
ERROR(PLUGIN_NAME " plugin: malloc failed.");
continue;
}
- status = virDomainGetVcpus(state->domains[i], vinfo, info.nrVirtCpu,
+ status = virDomainGetVcpus(state->domains[i], vinfo, info.di.nrVirtCpu,
/* cpu map = */ NULL, /* cpu map length = */ 0);
if (status < 0) {
ERROR(PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
continue;
}
- for (int j = 0; j < info.nrVirtCpu; ++j)
+ for (int j = 0; j < info.di.nrVirtCpu; ++j)
vcpu_submit(vinfo[j].cpuTime, state->domains[i], vinfo[j].number,
"virt_vcpu");