intel_rdt: refactored proc utils to increase efficiency
[collectd.git] / src / utils_proc_pids.c
index 1a05fe4..0fbea53 100644 (file)
@@ -1,3 +1,32 @@
+/**
+ * collectd - src/utils_config_pids.c
+ *
+ * Copyright(c) 2018-2019 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:
+ *
+ * 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,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Starzyk, Mateusz <mateuszx.starzyk@intel.com>
+ *   Wojciech Andralojc <wojciechx.andralojc@intel.com>
+ *   Michał Aleksiński <michalx.aleksinski@intel.com>
+ **/
+
 #include "collectd.h"
 #include "utils/common/common.h"
 #include "utils_proc_pids.h"
@@ -7,12 +36,8 @@
 void pids_list_free(pids_list_t *list) {
   assert(list);
 
-  pids_list_t *current = list;
-  while (current != NULL) {
-    pids_list_t *previous = current;
-    current = current->next;
-    sfree(previous);
-  }
+  sfree(list->pids);
+  sfree(list);
 }
 
 int is_proc_name_valid(const char *name) {
@@ -31,62 +56,75 @@ int is_proc_name_valid(const char *name) {
   return 0;
 }
 
-int pids_list_add_pid(pids_list_t **list, const pid_t pid) {
+int pids_list_add_pid(pids_list_t *list, const pid_t pid) {
   assert(list);
 
-  pids_list_t *new_element = calloc(1, sizeof(*new_element));
+  if (list->allocated == list->size) {
+    size_t new_allocated = list->allocated + 1 + list->allocated / 10;
+    pid_t *new_pids = realloc(list->pids, sizeof(pid_t) * new_allocated);
 
-  if (new_element == NULL) {
-    ERROR(UTIL_NAME ": Alloc error\n");
-    return -1;
-  }
-  new_element->pid = pid;
-  new_element->next = NULL;
+    if (NULL == new_pids) {
+      ERROR(UTIL_NAME ": Alloc error\n");
+      return -1;
+    }
 
-  pids_list_t **current = list;
-  while (*current != NULL) {
-    current = &((*current)->next);
+    list->pids = new_pids;
+    list->allocated = new_allocated;
   }
-  *current = new_element;
-  return 0;
-}
 
-int pids_list_contains_pid(pids_list_t *list, const pid_t pid) {
-  assert(list);
+  list->pids[list->size] = pid;
+  list->size++;
 
-  pids_list_t *current = list;
-  while (current != NULL) {
-    if (current->pid == pid)
-      return 1;
-    current = current->next;
-  }
   return 0;
 }
 
-int pids_list_add_pids_list(pids_list_t **dst, pids_list_t *src,
-                            size_t *dst_num) {
+int pids_list_add_list(pids_list_t *dst, pids_list_t *src) {
   assert(dst);
   assert(src);
-  assert(dst_num);
 
-  pids_list_t *current = src;
-  int ret;
+  if (dst->allocated < dst->size + src->size) {
+    pid_t *new_pids =
+        realloc(dst->pids, sizeof(pid_t) * (dst->size + src->size));
 
-  while (current != NULL) {
-    ret = pids_list_add_pid(dst, current->pid);
-    if (0 != ret)
-      return ret;
+    if (NULL == new_pids) {
+      ERROR(UTIL_NAME ": Alloc error\n");
+      return -1;
+    }
 
-    ++(*dst_num);
-    current = current->next;
+    dst->allocated = dst->size + src->size;
+    dst->pids = new_pids;
   }
 
+  memcpy(dst->pids + dst->size, src->pids, src->size * sizeof(*(src->pids)));
+  dst->size += src->size;
+
+  return 0;
+}
+
+int pids_list_clear(pids_list_t *list) {
+  assert(list);
+
+  if (list->pids != NULL)
+    sfree(list->pids);
+
+  list->size = 0;
+  list->allocated = 0;
+
+  return 0;
+}
+
+int pids_list_contains_pid(pids_list_t *list, const pid_t pid) {
+  assert(list);
+
+  for (int i = 0; i < list->size; i++)
+    if (list->pids[i] == pid)
+      return 1;
+
   return 0;
 }
 
 int read_proc_name(const char *procfs_path, const struct dirent *pid_entry,
                    char *name, const size_t out_size) {
-  assert(procfs_path);
   assert(pid_entry);
   assert(name);
   assert(out_size);
@@ -135,52 +173,56 @@ int get_pid_number(struct dirent *entry, pid_t *pid) {
   return 0;
 }
 
-void pids_list_to_array(pid_t *array, pids_list_t *list,
-                        const size_t array_length) {
-
-  assert(list);
-  assert(array);
-  assert(array_length > 0);
-
-  size_t current = 0;
-
-  while (list != NULL && current < array_length) {
-    array[current] = list->pid;
-    list = list->next;
-    ++current;
-  }
-}
-
 int initialize_proc_pids(const char **procs_names_array,
                          const size_t procs_names_array_size,
-                         proc_pids_t **proc_pids_array) {
+                         proc_pids_t **proc_pids[]) {
 
-  assert(proc_pids_array);
-  assert(NULL == *proc_pids_array);
+  proc_pids_t **proc_pids_array;
+  assert(proc_pids);
+  assert(NULL == *proc_pids);
 
   /* Copy procs names to output array. Initialize pids list with NULL value. */
-  (*proc_pids_array) =
-      calloc(procs_names_array_size, sizeof(**proc_pids_array));
+  proc_pids_array = calloc(procs_names_array_size, sizeof(*proc_pids_array));
 
-  if (NULL == (*proc_pids_array))
+  if (NULL == proc_pids_array)
     return -1;
 
   for (size_t i = 0; i < procs_names_array_size; ++i) {
-    sstrncpy((*proc_pids_array)[i].proccess_name, procs_names_array[i],
-             STATIC_ARRAY_SIZE((*proc_pids_array)[i].proccess_name));
-    (*proc_pids_array)[i].pids = NULL;
+    proc_pids_array[i] = calloc(1, sizeof(**proc_pids_array));
+    if (NULL == proc_pids_array[i])
+      goto initialize_proc_pids_error;
+
+    sstrncpy(proc_pids_array[i]->process_name, procs_names_array[i],
+             STATIC_ARRAY_SIZE(proc_pids_array[i]->process_name));
+    proc_pids_array[i]->prev = NULL;
+    proc_pids_array[i]->curr = NULL;
   }
 
+  *proc_pids = proc_pids_array;
+
   return 0;
+initialize_proc_pids_error:
+  if (NULL != proc_pids_array) {
+    for (size_t i = 0; i < procs_names_array_size; ++i) {
+      free(proc_pids_array[i]);
+    }
+    free(proc_pids_array);
+  }
+  return -1;
 }
 
-int fetch_pids_for_procs(const char *procfs_path,
-                         const char **procs_names_array,
-                         const size_t procs_names_array_size,
-                         proc_pids_t **proc_pids_array) {
+static void swap_proc_pids(proc_pids_t **proc_pids, size_t proc_pids_num) {
+  for (size_t i = 0; i < proc_pids_num; i++) {
+    pids_list_t *swap = proc_pids[i]->prev;
+    proc_pids[i]->prev = proc_pids[i]->curr;
+    proc_pids[i]->curr = swap;
+  }
+}
+
+int update_proc_pids(const char *procfs_path, proc_pids_t **proc_pids,
+                     size_t proc_pids_num) {
   assert(procfs_path);
-  assert(procs_names_array);
-  assert(procs_names_array_size);
+  assert(proc_pids);
 
   DIR *proc_dir = opendir(procfs_path);
   if (proc_dir == NULL) {
@@ -189,17 +231,23 @@ int fetch_pids_for_procs(const char *procfs_path,
     return -1;
   }
 
-  int init_result = initialize_proc_pids(
-      procs_names_array, procs_names_array_size, proc_pids_array);
-  if (0 != init_result) {
-    closedir(proc_dir);
-    return -1;
+  swap_proc_pids(proc_pids, proc_pids_num);
+
+  for (size_t i = 0; i < proc_pids_num; i++) {
+    if (NULL == proc_pids[i]->curr)
+      proc_pids[i]->curr = calloc(1, sizeof(*(proc_pids[i]->curr)));
+
+    if (NULL == proc_pids[i]->curr) {
+      ERROR(UTIL_NAME ": Alloc error\n");
+      goto update_error;
+    }
+
+    proc_pids[i]->curr->size = 0;
   }
 
   /* Go through procfs and find PIDS and their comms */
   struct dirent *entry;
   while ((entry = readdir(proc_dir)) != NULL) {
-
     pid_t pid;
     int pid_conversion = get_pid_number(entry, &pid);
     if (pid_conversion < 0)
@@ -208,65 +256,72 @@ int fetch_pids_for_procs(const char *procfs_path,
     proc_comm_t comm;
     int read_result =
         read_proc_name(procfs_path, entry, comm, sizeof(proc_comm_t));
-    if (read_result <= 0) {
-      ERROR(UTIL_NAME ": Comm file skipped. Read result: %d", read_result);
+    if (read_result <= 0)
       continue;
-    }
 
-    /* Try to find comm in input procs array (proc_pids_array has same names) */
-    for (size_t i = 0; i < procs_names_array_size; ++i) {
-      if (0 == strncmp(comm, (*proc_pids_array)[i].proccess_name,
-                       STATIC_ARRAY_SIZE(comm)))
-        pids_list_add_pid(&((*proc_pids_array)[i].pids), pid);
+    /* Try to find comm in input procs array */
+    for (size_t i = 0; i < proc_pids_num; ++i) {
+      if (0 ==
+          strncmp(comm, proc_pids[i]->process_name, STATIC_ARRAY_SIZE(comm)))
+        pids_list_add_pid(proc_pids[i]->curr, pid);
     }
   }
 
   int close_result = closedir(proc_dir);
   if (0 != close_result) {
-    ERROR(UTIL_NAME ": failed to close %s directory, error: %d", procfs_path,
-          errno);
-    sfree((*proc_pids_array));
-    return -1;
+    ERROR(UTIL_NAME ": failed to close /proc directory, error: %d", errno);
+    goto update_error;
   }
   return 0;
+
+update_error:
+  swap_proc_pids(proc_pids, proc_pids_num);
+  return -1;
 }
 
-int pids_list_diff(pids_list_t *prev, pids_list_t *curr, pids_list_t **added,
-                   size_t *added_num, pids_list_t **removed,
-                   size_t *removed_num) {
-  assert(prev || curr);
+int pids_list_diff(proc_pids_t *proc, pids_list_t *added,
+                   pids_list_t *removed) {
+  assert(proc);
   assert(added);
   assert(removed);
 
-  if (NULL == prev) {
+  added->size = 0;
+  removed->size = 0;
+
+  if (NULL == proc->prev || 0 == proc->prev->size) {
     /* append all PIDs from curr to added*/
-    return pids_list_add_pids_list(added, curr, added_num);
-  } else if (NULL == curr) {
+    return pids_list_add_list(added, proc->curr);
+  } else if (NULL == proc->curr || 0 == proc->curr->size) {
     /* append all PIDs from prev to removed*/
-    return pids_list_add_pids_list(removed, prev, removed_num);
+    return pids_list_add_list(removed, proc->prev);
   }
 
-  pids_list_t *item = prev;
-  while (item != NULL) {
-    if (0 == pids_list_contains_pid(curr, item->pid)) {
-      int add_result = pids_list_add_pid(removed, item->pid);
+  for (int i = 0; i < proc->prev->size; i++)
+    if (0 == pids_list_contains_pid(proc->curr, proc->prev->pids[i])) {
+      int add_result = pids_list_add_pid(removed, proc->prev->pids[i]);
       if (add_result < 0)
         return add_result;
-      ++(*removed_num);
     }
-    item = item->next;
-  }
 
-  item = curr;
-  while (item != NULL) {
-    if (0 == pids_list_contains_pid(prev, item->pid)) {
-      int add_result = pids_list_add_pid(added, item->pid);
+  for (int i = 0; i < proc->curr->size; i++)
+    if (0 == pids_list_contains_pid(proc->prev, proc->curr->pids[i])) {
+      int add_result = pids_list_add_pid(added, proc->curr->pids[i]);
       if (add_result < 0)
         return add_result;
-      ++(*added_num);
     }
-    item = item->next;
+
+  return 0;
+}
+
+int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num) {
+  for (size_t i = 0; i < proc_pids_num; i++) {
+    if (NULL != proc_pids[i]->curr)
+      pids_list_free(proc_pids[i]->curr);
+    if (NULL != proc_pids[i]->prev)
+      pids_list_free(proc_pids[i]->prev);
+    sfree(proc_pids[i]);
   }
+  sfree(proc_pids);
 
   return 0;
 }