X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fintel_pmu.c;h=23536841f81b8542e9366c0c9509ba37a03138d6;hp=e332c37b106bef33989c93653f969c9062829df4;hb=06a86a60a7dabc685bdbd81ce3d36ea5f7e2c2d4;hpb=7a8d53720c82e6391508bd1c4200339cc6a1d5d8 diff --git a/src/intel_pmu.c b/src/intel_pmu.c index e332c37b..23536841 100644 --- a/src/intel_pmu.c +++ b/src/intel_pmu.c @@ -64,9 +64,10 @@ struct event_info { typedef struct event_info event_info_t; struct intel_pmu_ctx_s { - _Bool hw_cache_events; - _Bool kernel_pmu_events; - _Bool sw_events; + bool hw_cache_events; + bool kernel_pmu_events; + bool sw_events; + char event_list_fn[PATH_MAX]; char **hw_events; size_t hw_events_count; struct eventlist *event_list; @@ -181,8 +182,6 @@ static void pmu_dump_events() { DEBUG(PMU_PLUGIN ": config : %#x", (unsigned)e->attr.config); DEBUG(PMU_PLUGIN ": size : %d", e->attr.size); } - - return; } static void pmu_dump_config(void) { @@ -193,10 +192,9 @@ static void pmu_dump_config(void) { DEBUG(PMU_PLUGIN ": software_events : %d", g_ctx.sw_events); for (size_t i = 0; i < g_ctx.hw_events_count; i++) { - DEBUG(PMU_PLUGIN ": hardware_events[%zu]: %s", i, g_ctx.hw_events[i]); + DEBUG(PMU_PLUGIN ": hardware_events[%" PRIsz "]: %s", i, + g_ctx.hw_events[i]); } - - return; } #endif /* COLLECT_DEBUG */ @@ -207,6 +205,11 @@ static int pmu_config_hw_events(oconfig_item_t *ci) { return -EINVAL; } + if (g_ctx.hw_events) { + ERROR(PMU_PLUGIN ": Duplicate config for HardwareEvents."); + return -EINVAL; + } + g_ctx.hw_events = calloc(ci->values_num, sizeof(char *)); if (g_ctx.hw_events == NULL) { ERROR(PMU_PLUGIN ": Failed to allocate hw events."); @@ -232,24 +235,27 @@ static int pmu_config_hw_events(oconfig_item_t *ci) { } static int pmu_config(oconfig_item_t *ci) { - int ret = 0; DEBUG(PMU_PLUGIN ": %s:%d", __FUNCTION__, __LINE__); for (int i = 0; i < ci->children_num; i++) { + int ret = 0; oconfig_item_t *child = ci->children + i; if (strcasecmp("ReportHardwareCacheEvents", child->key) == 0) { ret = cf_util_get_boolean(child, &g_ctx.hw_cache_events); } else if (strcasecmp("ReportKernelPMUEvents", child->key) == 0) { ret = cf_util_get_boolean(child, &g_ctx.kernel_pmu_events); + } else if (strcasecmp("EventList", child->key) == 0) { + ret = cf_util_get_string_buffer(child, g_ctx.event_list_fn, + sizeof(g_ctx.event_list_fn)); } else if (strcasecmp("HardwareEvents", child->key) == 0) { ret = pmu_config_hw_events(child); } else if (strcasecmp("ReportSoftwareEvents", child->key) == 0) { ret = cf_util_get_boolean(child, &g_ctx.sw_events); } else { ERROR(PMU_PLUGIN ": Unknown configuration parameter \"%s\".", child->key); - ret = (-1); + ret = -1; } if (ret != 0) { @@ -265,7 +271,8 @@ static int pmu_config(oconfig_item_t *ci) { return 0; } -static void pmu_submit_counter(int cpu, char *event, counter_t value) { +static void pmu_submit_counter(int cpu, char *event, counter_t value, + meta_data_t *meta) { value_list_t vl = VALUE_LIST_INIT; vl.values = &(value_t){.counter = value}; @@ -273,9 +280,10 @@ static void pmu_submit_counter(int cpu, char *event, counter_t value) { sstrncpy(vl.plugin, PMU_PLUGIN, sizeof(vl.plugin)); if (cpu == -1) { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "all"); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "all"); } else { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%d", cpu); + vl.meta = meta; + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%d", cpu); } sstrncpy(vl.type, "counter", sizeof(vl.type)); sstrncpy(vl.type_instance, event, sizeof(vl.type_instance)); @@ -283,7 +291,28 @@ static void pmu_submit_counter(int cpu, char *event, counter_t value) { plugin_dispatch_values(&vl); } -static int pmu_dispatch_data(void) { +meta_data_t *pmu_meta_data_create(const struct efd *efd) { + meta_data_t *meta = NULL; + + /* create meta data only if value was scaled */ + if (efd->val[1] == efd->val[2] || !efd->val[2]) { + return NULL; + } + + meta = meta_data_create(); + if (meta == NULL) { + ERROR(PMU_PLUGIN ": meta_data_create failed."); + return NULL; + } + + meta_data_add_unsigned_int(meta, "intel_pmu:raw_count", efd->val[0]); + meta_data_add_unsigned_int(meta, "intel_pmu:time_enabled", efd->val[1]); + meta_data_add_unsigned_int(meta, "intel_pmu:time_running", efd->val[2]); + + return meta; +} + +static void pmu_dispatch_data(void) { struct event *e; @@ -297,21 +326,29 @@ static int pmu_dispatch_data(void) { event_enabled++; + /* If there are more events than counters, the kernel uses time + * multiplexing. With multiplexing, at the end of the run, + * the counter is scaled basing on total time enabled vs time running. + * final_count = raw_count * time_enabled/time_running + */ uint64_t value = event_scaled_value(e, i); all_value += value; + /* get meta data with information about scaling */ + meta_data_t *meta = pmu_meta_data_create(&e->efd[i]); + /* dispatch per CPU value */ - pmu_submit_counter(i, e->event, value); + pmu_submit_counter(i, e->event, value, meta); + + meta_data_destroy(meta); } if (event_enabled > 0) { DEBUG(PMU_PLUGIN ": %-20s %'10lu", e->event, all_value); /* dispatch all CPU value */ - pmu_submit_counter(-1, e->event, all_value); + pmu_submit_counter(-1, e->event, all_value, NULL); } } - - return 0; } static int pmu_read(__attribute__((unused)) user_data_t *ud) { @@ -322,22 +359,18 @@ static int pmu_read(__attribute__((unused)) user_data_t *ud) { ret = read_all_events(g_ctx.event_list); if (ret != 0) { ERROR(PMU_PLUGIN ": Failed to read values of all events."); - return 0; + return ret; } - ret = pmu_dispatch_data(); - if (ret != 0) { - ERROR(PMU_PLUGIN ": Failed to dispatch event values."); - return 0; - } + pmu_dispatch_data(); return 0; } static int pmu_add_events(struct eventlist *el, uint32_t type, - event_info_t *events, int count) { + event_info_t *events, size_t count) { - for (int i = 0; i < count; i++) { + for (size_t i = 0; i < count; i++) { /* Allocate memory for event struct that contains array of efd structs for all cores */ struct event *e = @@ -350,7 +383,6 @@ static int pmu_add_events(struct eventlist *el, uint32_t type, e->attr.type = type; e->attr.config = events[i].config; e->attr.size = PERF_ATTR_SIZE_VER0; - e->next = NULL; if (!el->eventlist) el->eventlist = e; if (el->eventlist_last) @@ -375,12 +407,6 @@ static int pmu_add_hw_events(struct eventlist *el, char **e, size_t count) { char *s, *tmp; for (s = strtok_r(events, ",", &tmp); s; s = strtok_r(NULL, ",", &tmp)) { - /* Multiple events parsed in one entry */ - if (group_events_count == 1) { - /* Mark previously added event as group leader */ - el->eventlist_last->group_leader = 1; - } - /* Allocate memory for event struct that contains array of efd structs for all cores */ struct event *e = @@ -390,19 +416,26 @@ static int pmu_add_hw_events(struct eventlist *el, char **e, size_t count) { return -ENOMEM; } - if (resolve_event(s, &e->attr) == 0) { - e->next = NULL; - if (!el->eventlist) - el->eventlist = e; - if (el->eventlist_last) - el->eventlist_last->next = e; - el->eventlist_last = e; - e->event = strdup(s); - } else { - DEBUG(PMU_PLUGIN ": Cannot resolve %s", s); + if (resolve_event(s, &e->attr) != 0) { + WARNING(PMU_PLUGIN ": Cannot resolve %s", s); sfree(e); + continue; + } + + /* Multiple events parsed in one entry */ + if (group_events_count == 1) { + /* Mark previously added event as group leader */ + el->eventlist_last->group_leader = 1; } + e->next = NULL; + if (!el->eventlist) + el->eventlist = e; + if (el->eventlist_last) + el->eventlist_last->next = e; + el->eventlist_last = e; + e->event = strdup(s); + group_events_count++; } @@ -493,6 +526,14 @@ static int pmu_init(void) { /* parse events names if config option is present and is not empty */ if (g_ctx.hw_events_count) { + + ret = read_events(g_ctx.event_list_fn); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to read event list file '%s'.", + g_ctx.event_list_fn); + return ret; + } + ret = pmu_add_hw_events(g_ctx.event_list, g_ctx.hw_events, g_ctx.hw_events_count); if (ret != 0) { @@ -538,7 +579,6 @@ init_error: sfree(g_ctx.hw_events); g_ctx.hw_events_count = 0; - return ret; }