Treewide: replace ssnprintf with snprintf
[collectd.git] / src / intel_rdt.c
index d8e775f..5eabdb3 100644 (file)
@@ -3,15 +3,15 @@
  *
  * Copyright(c) 2016 Intel Corporation. All rights reserved.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -25,8 +25,8 @@
  *   Serhiy Pshyk <serhiyx.pshyk@intel.com>
  **/
 
-#include "collectd.h"
 #include "common.h"
+#include "collectd.h"
 
 #include <pqos.h>
 
 #define RDT_MAX_SOCKET_CORES 64
 #define RDT_MAX_CORES (RDT_MAX_SOCKET_CORES * RDT_MAX_SOCKETS)
 
+typedef enum {
+  UNKNOWN = 0,
+  CONFIGURATION_ERROR,
+} rdt_config_status;
+
 struct rdt_core_group_s {
   char *desc;
   size_t num_cores;
@@ -56,6 +61,8 @@ typedef struct rdt_ctx_s rdt_ctx_t;
 
 static rdt_ctx_t *g_rdt = NULL;
 
+static rdt_config_status g_state = UNKNOWN;
+
 static int isdup(const uint64_t *nums, size_t size, uint64_t val) {
   for (size_t i = 0; i < size; i++)
     if (nums[i] == val)
@@ -73,10 +80,10 @@ static int strtouint64(const char *s, uint64_t *n) {
 
   if (!(*s != '\0' && *endptr == '\0')) {
     DEBUG(RDT_PLUGIN ": Error converting '%s' to unsigned number.", s);
-    return (-EINVAL);
+    return -EINVAL;
   }
 
-  return (0);
+  return 0;
 }
 
 /*
@@ -129,12 +136,12 @@ static size_t strlisttonums(char *s, uint64_t *nums, size_t max) {
       *p = '\0';
       ret = strtouint64(token, &start);
       if (ret < 0)
-        return (0);
+        return 0;
       ret = strtouint64(p + 1, &end);
       if (ret < 0)
-        return (0);
+        return 0;
       if (start > end) {
-        return (0);
+        return 0;
       }
       for (n = start; n <= end; n++) {
         if (!(isdup(nums, index, n))) {
@@ -149,7 +156,7 @@ static size_t strlisttonums(char *s, uint64_t *nums, size_t max) {
 
       ret = strtouint64(token, &val);
       if (ret < 0)
-        return (0);
+        return 0;
 
       if (!(isdup(nums, index, val))) {
         nums[index] = val;
@@ -216,14 +223,14 @@ static int cgroup_set(rdt_core_group_t *cg, char *desc, uint64_t *cores,
   cg->cores = calloc(num_cores, sizeof(unsigned));
   if (cg->cores == NULL) {
     ERROR(RDT_PLUGIN ": Error allocating core group table");
-    return (-ENOMEM);
+    return -ENOMEM;
   }
   cg->num_cores = num_cores;
   cg->desc = strdup(desc);
   if (cg->desc == NULL) {
     ERROR(RDT_PLUGIN ": Error allocating core group description");
     sfree(cg->cores);
-    return (-ENOMEM);
+    return -ENOMEM;
   }
 
   for (size_t i = 0; i < num_cores; i++)
@@ -245,14 +252,13 @@ static int cgroup_set(rdt_core_group_t *cg, char *desc, uint64_t *cores,
  *   `item'        Config option containing core groups.
  *   `groups'      Table of core groups to set values in.
  *   `max_groups'  Maximum number of core groups allowed.
- *   `max_core'    Maximum allowed core value.
  *
  * RETURN VALUE
  *   On success, the number of core groups set up. On error, appropriate
  *   negative error value.
  */
 static int oconfig_to_cgroups(oconfig_item_t *item, rdt_core_group_t *groups,
-                              size_t max_groups, uint64_t max_core) {
+                              size_t max_groups) {
   int index = 0;
 
   assert(groups != NULL);
@@ -265,7 +271,8 @@ static int oconfig_to_cgroups(oconfig_item_t *item, rdt_core_group_t *groups,
     uint64_t cores[RDT_MAX_CORES] = {0};
     char value[DATA_MAX_NAME_LEN];
 
-    if ((item->values[j].value.string == NULL) || (strlen(item->values[j].value.string) == 0))
+    if ((item->values[j].value.string == NULL) ||
+        (strlen(item->values[j].value.string) == 0))
       continue;
 
     sstrncpy(value, item->values[j].value.string, sizeof(value));
@@ -274,15 +281,7 @@ static int oconfig_to_cgroups(oconfig_item_t *item, rdt_core_group_t *groups,
     if (n == 0) {
       ERROR(RDT_PLUGIN ": Error parsing core group (%s)",
             item->values[j].value.string);
-      return (-EINVAL);
-    }
-
-    for (int i = 0; i < n; i++) {
-      if (cores[i] > max_core) {
-        ERROR(RDT_PLUGIN ": Core group (%s) contains invalid core id (%d)",
-              item->values[j].value.string, (int)cores[i]);
-        return (-EINVAL);
-      }
+      return -EINVAL;
     }
 
     /* set core group info */
@@ -376,7 +375,7 @@ static int rdt_default_cgroups(void) {
     char desc[DATA_MAX_NAME_LEN];
     uint64_t core = i;
 
-    ssnprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore);
+    snprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore);
 
     /* set core group info */
     ret = cgroup_set(&g_rdt->cgroups[i], desc, &core, 1);
@@ -387,31 +386,52 @@ static int rdt_default_cgroups(void) {
   return g_rdt->pqos_cpu->num_cores;
 }
 
+static int rdt_is_core_id_valid(int core_id) {
+
+  for (int i = 0; i < g_rdt->pqos_cpu->num_cores; i++)
+    if (core_id == g_rdt->pqos_cpu->cores[i].lcore)
+      return 1;
+
+  return 0;
+}
+
 static int rdt_config_cgroups(oconfig_item_t *item) {
   int n = 0;
   enum pqos_mon_event events = 0;
 
   if (item == NULL) {
     DEBUG(RDT_PLUGIN ": cgroups_config: Invalid argument.");
-    return (-EINVAL);
+    return -EINVAL;
   }
 
   DEBUG(RDT_PLUGIN ": Core groups [%d]:", item->values_num);
   for (int j = 0; j < item->values_num; j++) {
     if (item->values[j].type != OCONFIG_TYPE_STRING) {
-      ERROR(RDT_PLUGIN ": given core group value is not a string [idx=%d]",
-            j);
-      return (-EINVAL);
+      ERROR(RDT_PLUGIN ": given core group value is not a string [idx=%d]", j);
+      return -EINVAL;
     }
     DEBUG(RDT_PLUGIN ":  [%d]: %s", j, item->values[j].value.string);
   }
 
-  n = oconfig_to_cgroups(item, g_rdt->cgroups, RDT_MAX_CORES,
-                         g_rdt->pqos_cpu->num_cores-1);
+  n = oconfig_to_cgroups(item, g_rdt->cgroups, g_rdt->pqos_cpu->num_cores);
   if (n < 0) {
     rdt_free_cgroups();
     ERROR(RDT_PLUGIN ": Error parsing core groups configuration.");
-    return (-EINVAL);
+    return -EINVAL;
+  }
+
+  /* validate configured core id values */
+  for (int group_idx = 0; group_idx < n; group_idx++) {
+    for (int core_idx = 0; core_idx < g_rdt->cgroups[group_idx].num_cores;
+         core_idx++) {
+      if (!rdt_is_core_id_valid(g_rdt->cgroups[group_idx].cores[core_idx])) {
+        ERROR(RDT_PLUGIN ": Core group '%s' contains invalid core id '%d'",
+                g_rdt->cgroups[group_idx].desc,
+                (int)g_rdt->cgroups[group_idx].cores[core_idx]);
+        rdt_free_cgroups();
+        return -EINVAL;
+      }
+    }
   }
 
   if (n == 0) {
@@ -419,8 +439,7 @@ static int rdt_config_cgroups(oconfig_item_t *item) {
     n = rdt_default_cgroups();
     if (n < 0) {
       rdt_free_cgroups();
-      ERROR(RDT_PLUGIN
-            ": Error creating default core groups configuration.");
+      ERROR(RDT_PLUGIN ": Error creating default core groups configuration.");
       return n;
     }
     INFO(RDT_PLUGIN
@@ -445,7 +464,7 @@ static int rdt_config_cgroups(oconfig_item_t *item) {
       if (found != 0) {
         rdt_free_cgroups();
         ERROR(RDT_PLUGIN ": Cannot monitor same cores in different groups.");
-        return (-EINVAL);
+        return -EINVAL;
       }
     }
 
@@ -454,11 +473,15 @@ static int rdt_config_cgroups(oconfig_item_t *item) {
     if (g_rdt->pgroups[i] == NULL) {
       rdt_free_cgroups();
       ERROR(RDT_PLUGIN ": Failed to allocate memory for monitoring data.");
-      return (-ENOMEM);
+      return -ENOMEM;
     }
   }
 
-  return (0);
+  return 0;
+}
+
+static void rdt_pqos_log(void *context, const size_t size, const char *msg) {
+  DEBUG(RDT_PLUGIN ": %s", msg);
 }
 
 static int rdt_preinit(void) {
@@ -466,24 +489,21 @@ static int rdt_preinit(void) {
 
   if (g_rdt != NULL) {
     /* already initialized if config callback was called before init callback */
-    return (0);
+    return 0;
   }
 
   g_rdt = calloc(1, sizeof(*g_rdt));
   if (g_rdt == NULL) {
     ERROR(RDT_PLUGIN ": Failed to allocate memory for rdt context.");
-    return (-ENOMEM);
+    return -ENOMEM;
   }
 
-  /* In case previous instance of the application was not closed properly
-   * call fini and ignore return code. */
-  pqos_fini();
+  struct pqos_config pqos = {.fd_log = -1,
+                             .callback_log = rdt_pqos_log,
+                             .context_log = NULL,
+                             .verbose = 0};
 
-  /* TODO:
-   * stdout should not be used here. Will be reworked when support of log
-   * callback is added to PQoS library.
-  */
-  ret = pqos_init(&(struct pqos_config){.fd_log = STDOUT_FILENO});
+  ret = pqos_init(&pqos);
   if (ret != PQOS_RETVAL_OK) {
     ERROR(RDT_PLUGIN ": Error initializing PQoS library!");
     goto rdt_preinit_error1;
@@ -495,8 +515,7 @@ static int rdt_preinit(void) {
     goto rdt_preinit_error2;
   }
 
-  ret = pqos_cap_get_type(g_rdt->pqos_cap, PQOS_CAP_TYPE_MON,
-                          &g_rdt->cap_mon);
+  ret = pqos_cap_get_type(g_rdt->pqos_cap, PQOS_CAP_TYPE_MON, &g_rdt->cap_mon);
   if (ret == PQOS_RETVAL_PARAM) {
     ERROR(RDT_PLUGIN ": Error retrieving monitoring capabilities.");
     goto rdt_preinit_error2;
@@ -509,7 +528,10 @@ static int rdt_preinit(void) {
     goto rdt_preinit_error2;
   }
 
-  return (0);
+  /* Reset pqos monitoring groups registers */
+  pqos_mon_reset();
+
+  return 0;
 
 rdt_preinit_error2:
   pqos_fini();
@@ -518,43 +540,48 @@ rdt_preinit_error1:
 
   sfree(g_rdt);
 
-  return (-1);
+  return -1;
 }
 
 static int rdt_config(oconfig_item_t *ci) {
-  int ret = 0;
-
-  ret = rdt_preinit();
-  if (ret != 0)
-    return ret;
+  if (rdt_preinit() != 0) {
+    g_state = CONFIGURATION_ERROR;
+    /* if we return -1 at this point collectd
+      reports a failure in configuration and
+      aborts
+    */
+    return (0);
+  }
 
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Cores", child->key) == 0) {
-
-      ret = rdt_config_cgroups(child);
-      if (ret != 0)
-        return ret;
+      if (rdt_config_cgroups(child) != 0) {
+        g_state = CONFIGURATION_ERROR;
+        /* if we return -1 at this point collectd
+           reports a failure in configuration and
+           aborts
+         */
+        return (0);
+      }
 
 #if COLLECT_DEBUG
       rdt_dump_cgroups();
 #endif /* COLLECT_DEBUG */
-
     } else {
-      ERROR(RDT_PLUGIN ": Unknown configuration parameter \"%s\".",
-            child->key);
+      ERROR(RDT_PLUGIN ": Unknown configuration parameter \"%s\".", child->key);
     }
   }
 
-  return (0);
+  return 0;
 }
 
 static void rdt_submit_derive(char *cgroup, char *type, char *type_instance,
-                                derive_t value) {
+                              derive_t value) {
   value_list_t vl = VALUE_LIST_INIT;
 
-  vl.values = &(value_t) { .derive = value };
+  vl.values = &(value_t){.derive = value};
   vl.values_len = 1;
 
   sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
@@ -567,10 +594,10 @@ static void rdt_submit_derive(char *cgroup, char *type, char *type_instance,
 }
 
 static void rdt_submit_gauge(char *cgroup, char *type, char *type_instance,
-                                gauge_t value) {
+                             gauge_t value) {
   value_list_t vl = VALUE_LIST_INIT;
 
-  vl.values = &(value_t) { .gauge = value };
+  vl.values = &(value_t){.gauge = value};
   vl.values_len = 1;
 
   sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
@@ -587,13 +614,13 @@ static int rdt_read(__attribute__((unused)) user_data_t *ud) {
 
   if (g_rdt == NULL) {
     ERROR(RDT_PLUGIN ": rdt_read: plugin not initialized.");
-    return (-EINVAL);
+    return -EINVAL;
   }
 
   ret = pqos_mon_poll(&g_rdt->pgroups[0], (unsigned)g_rdt->num_groups);
   if (ret != PQOS_RETVAL_OK) {
     ERROR(RDT_PLUGIN ": Failed to poll monitoring data.");
-    return (-1);
+    return -1;
   }
 
 #if COLLECT_DEBUG
@@ -616,19 +643,22 @@ static int rdt_read(__attribute__((unused)) user_data_t *ud) {
       rdt_submit_gauge(g_rdt->cgroups[i].desc, "ipc", NULL, pv->ipc);
 
     if (g_rdt->cgroups[i].events & mbm_events) {
-      rdt_submit_derive(g_rdt->cgroups[i].desc, "memory_bandwidth",
-                           "local", pv->mbm_local_delta);
-      rdt_submit_derive(g_rdt->cgroups[i].desc, "memory_bandwidth",
-                           "remote", pv->mbm_remote_delta);
+      rdt_submit_derive(g_rdt->cgroups[i].desc, "memory_bandwidth", "local",
+                        pv->mbm_local_delta);
+      rdt_submit_derive(g_rdt->cgroups[i].desc, "memory_bandwidth", "remote",
+                        pv->mbm_remote_delta);
     }
   }
 
-  return (0);
+  return 0;
 }
 
 static int rdt_init(void) {
   int ret;
 
+  if(g_state == CONFIGURATION_ERROR)
+    return -1;
+
   ret = rdt_preinit();
   if (ret != 0)
     return ret;
@@ -645,7 +675,7 @@ static int rdt_init(void) {
             cg->desc, ret);
   }
 
-  return (0);
+  return 0;
 }
 
 static int rdt_shutdown(void) {
@@ -654,7 +684,7 @@ static int rdt_shutdown(void) {
   DEBUG(RDT_PLUGIN ": rdt_shutdown.");
 
   if (g_rdt == NULL)
-    return (0);
+    return 0;
 
   /* Stop monitoring */
   for (int i = 0; i < g_rdt->num_groups; i++) {
@@ -668,7 +698,7 @@ static int rdt_shutdown(void) {
   rdt_free_cgroups();
   sfree(g_rdt);
 
-  return (0);
+  return 0;
 }
 
 void module_register(void) {