Merge branch 'collectd-5.8'
[collectd.git] / src / intel_pmu.c
index e5f19ce..2353684 100644 (file)
@@ -64,10 +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;
-  char  event_list_fn[PATH_MAX];
+  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;
@@ -192,7 +192,8 @@ 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]);
   }
 }
 
@@ -204,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.");
@@ -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};
@@ -275,6 +282,7 @@ static void pmu_submit_counter(int cpu, char *event, counter_t value) {
   if (cpu == -1) {
     snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "all");
   } else {
+    vl.meta = meta;
     snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%d", cpu);
   }
   sstrncpy(vl.type, "counter", sizeof(vl.type));
@@ -283,6 +291,27 @@ static void pmu_submit_counter(int cpu, char *event, counter_t value) {
   plugin_dispatch_values(&vl);
 }
 
+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,17 +326,27 @@ static void 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);
     }
   }
 }
@@ -368,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 =
@@ -383,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++;
     }
 
@@ -539,7 +579,6 @@ init_error:
   sfree(g_ctx.hw_events);
   g_ctx.hw_events_count = 0;
 
-
   return ret;
 }