resource: process-group: Use taskstats instead of reading procfs 56/273456/2
authorDongwoo Lee <dwoo08.lee@samsung.com>
Thu, 31 Mar 2022 04:32:25 +0000 (13:32 +0900)
committerDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 6 Apr 2022 09:22:19 +0000 (18:22 +0900)
To lower the overhead of getting information about process, use
taskstats instead of reading procfs while building group list.
Moreover, two advantages can be gained as using taskstats directly:
 1. Lower number of copy
 2. Using taskstats accounting information without process driver

Change-Id: I5242d25ab864b05674d9af01838d3401a356a1df
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
src/resource/resource-process-group.c

index a56636d..31bb359 100644 (file)
 
 #define PROC_DIR_PATH  "/proc/"
 
-struct process_info {
-       pid_t pid;
-       pid_t ppid;
-       char comm[TS_COMM_LEN];
-};
-
 struct process_info_node {
-       struct process_info pi;
+       struct taskstats *stats;
        struct process_info_node *parent;
 };
 
 struct process_group_context {
-       struct process_info root_pi;
+       struct taskstats root_stats;
        GPtrArray *pi_list;
 };
 
@@ -47,7 +41,7 @@ static int process_group_get_pid_list(const struct resource *res,
 {
        struct process_group_context *ctx;
        struct array_value *list = data;
-       struct process_info *pi;
+       struct process_info_node *node;
        int *data_array;
        int i;
 
@@ -70,8 +64,8 @@ static int process_group_get_pid_list(const struct resource *res,
        list->length = ctx->pi_list->len;
 
        for (i = 0; i < list->length; i++) {
-               pi = g_ptr_array_index(ctx->pi_list, i);
-               data_array[i] = pi->pid;
+               node = g_ptr_array_index(ctx->pi_list, i);
+               data_array[i] = node->stats->ac_pid;
        }
 
        return 0;
@@ -83,7 +77,7 @@ static int process_group_get_comm_list(const struct resource *res,
 {
        struct process_group_context *ctx;
        struct array_value *list = data;
-       struct process_info *pi;
+       struct process_info_node *node;
        char **data_array;
        int i;
 
@@ -111,8 +105,8 @@ static int process_group_get_comm_list(const struct resource *res,
        list->length = ctx->pi_list->len;
 
        for (i = 0; i < list->length; i++) {
-               pi = g_ptr_array_index(ctx->pi_list, i);
-               data_array[i] = strdup(pi->comm);
+               node = g_ptr_array_index(ctx->pi_list, i);
+               data_array[i] = strdup(node->stats->ac_comm);
                if (!data_array[i]) {
                        while (i > 0)
                                free(data_array[--i]);
@@ -151,9 +145,6 @@ static int process_group_setup_root_pid(const struct resource *res,
                                const void *data)
 {
        struct process_group_context *ctx;
-       struct process_info *target;
-       char *statfields[PROCESS_STAT_FIELD_MAX];
-       char buf[BUFF_MAX];
        int target_pid;
        int ret;
 
@@ -162,25 +153,20 @@ static int process_group_setup_root_pid(const struct resource *res,
 
        ctx = res->priv;
 
-       target = &ctx->root_pi;
-
        target_pid = (int)(intptr_t)data;
 
        if (target_pid < 0) {
-               target->pid = target->ppid = -1;
+               ctx->root_stats.ac_pid = ctx->root_stats.ac_ppid = -1;
                return 0;
        }
 
-       ret = kernel_get_process_stat_fields(target_pid, buf, BUFF_MAX, statfields);
+       ret = kernel_get_process_taskstats(&ctx->root_stats, TASKSTATS_CMD_ATTR_PID, target_pid);
        if (ret < 0) {
                _E("target process pid is not valid");
-               target->pid = target->ppid = -1;
+               ctx->root_stats.ac_pid = ctx->root_stats.ac_ppid = -1;
                return ret;
        }
 
-       target->pid = atoi(statfields[PROCESS_STAT_FIELD_PID]);
-       target->ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]);
-
        return 0;
 }
 
@@ -194,21 +180,29 @@ static const struct resource_control process_group_ctrls[] = {
        },
 };
 
+static void free_node(void *_node)
+{
+       struct process_info_node *node = _node;
+
+       if (node->stats)
+               free(node->stats);
+
+       free(node);
+}
+
 static int process_group_prepare_update(struct resource *res)
 {
        struct process_group_context *ctx;
        struct process_info_node *pnode, *parent_pnode;
-       struct process_info *pi, *root_pi;
        struct dirent *task_entry;
-       char *statfields[PROCESS_STAT_FIELD_MAX];
-       char buf[BUFF_MAX];
+       struct taskstats *stats;
        GPtrArray *pi_list;
        GHashTableIter iter;
        gpointer key, value;
        GHashTable *process_hash;
        DIR *task_dir;
-       int len, ret = 0;
-       pid_t pid, ppid, pgrp;
+       int ret = 0;
+       pid_t pid;
 
        if (!res || !res->priv)
                return -EINVAL;
@@ -219,7 +213,7 @@ static int process_group_prepare_update(struct resource *res)
        if (!task_dir)
                return -ESRCH;
 
-       process_hash = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free);
+       process_hash = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free_node);
        if (!process_hash) {
                ret = -ENOMEM;
                goto out_close;
@@ -237,94 +231,79 @@ static int process_group_prepare_update(struct resource *res)
 
                pid = atoi(name);
 
-               ret = kernel_get_process_stat_fields(pid, buf, BUFF_MAX, statfields);
-               if (ret < 0)
-                       continue; /* process might be terminated */
+               if (pid == 2)
+                       continue;
+
+               stats = malloc(sizeof(struct taskstats));
+               if (!stats) {
+                       ret = -ENOMEM;
+                       goto out_free_hash;
+               }
 
-               ppid = atoi(statfields[PROCESS_STAT_FIELD_PPID]);
-               pgrp = atoi(statfields[PROCESS_STAT_FIELD_PGID]);
+               ret = kernel_get_process_taskstats(stats, TASKSTATS_CMD_ATTR_PID, pid);
+               if (ret < 0) {
+                       free(stats);
+                       continue; /* process might be terminated */
+               }
 
                /* except kthreads */
-               if (pid == 2 || ppid == 2 || pgrp == 2)
+               if (stats->ac_ppid == 2 || strstr(stats->ac_comm, "irq/")) {
+                       free(stats);
                        continue;
+               }
 
                pnode = calloc(1, sizeof(struct process_info_node));
                if (!pnode) {
+                       free(stats);
                        ret = -ENOMEM;
                        goto out_free_hash;
                }
 
-               pnode->pi.pid = pid;
-               pnode->pi.ppid = ppid;
+               pnode->stats = stats;
 
-               len = strlen(statfields[PROCESS_STAT_FIELD_COMM]) - 2/* '(', ')' */;
-               len = (len < TS_COMM_LEN - 1) ? len : TS_COMM_LEN - 1;
-               strncpy(pnode->pi.comm, statfields[PROCESS_STAT_FIELD_COMM] + 1, len);
-
-               if (g_hash_table_contains(process_hash, (gpointer)&pnode->pi.ppid)) {
-                       parent_pnode = g_hash_table_lookup(process_hash, (gpointer)&pnode->pi.ppid);
+               if (g_hash_table_contains(process_hash, (gpointer)&pnode->stats->ac_ppid)) {
+                       parent_pnode = g_hash_table_lookup(process_hash,
+                                                       (gpointer)&pnode->stats->ac_ppid);
 
                        pnode->parent = parent_pnode;
                }
 
-               g_hash_table_insert(process_hash, (gpointer)&pnode->pi.pid, (gpointer)pnode);
+               g_hash_table_insert(process_hash, (gpointer)&pnode->stats->ac_pid, (gpointer)pnode);
        }
 
-       pi_list = g_ptr_array_new_full(100, free);
+       pi_list = g_ptr_array_new_full(100, free_node);
        if (!pi_list) {
                ret = -ENOMEM;
                goto out_free_hash;
        }
 
-       root_pi = &ctx->root_pi;
-
-       if (root_pi->pid < 0) {
+       if (ctx->root_stats.ac_pid < 0) {
                /* just add all processes into array if parent pid is negative */
                g_hash_table_iter_init(&iter, process_hash);
                while (g_hash_table_iter_next(&iter, &key, &value)) {
                        pnode = (struct process_info_node *)value;
 
-                       pi = malloc(sizeof(struct process_info));
-                       if (!pi) {
-                               g_ptr_array_free(pi_list, true);
-                               ctx->pi_list = NULL;
-                               goto out_free_hash;
-                       }
-
-                       memcpy(pi, &pnode->pi, sizeof(struct process_info));
-                       g_ptr_array_add(pi_list, pi);
+                       g_ptr_array_add(pi_list, pnode);
+                       g_hash_table_iter_steal(&iter);
                }
        } else {
                g_hash_table_iter_init(&iter, process_hash);
                while (g_hash_table_iter_next(&iter, &key, &value)) {
                        pnode = (struct process_info_node *)value;
 
-                       if (root_pi->pid == pnode->pi.pid || root_pi->pid == pnode->pi.ppid) {
+                       if (ctx->root_stats.ac_pid == pnode->stats->ac_pid
+                                       || ctx->root_stats.ac_pid == pnode->stats->ac_ppid) {
 
-                               pi = malloc(sizeof(struct process_info));
-                               if (!pi) {
-                                       g_ptr_array_free(pi_list, true);
-                                       ctx->pi_list = NULL;
-                                       goto out_free_hash;
-                               }
-
-                               memcpy(pi, &pnode->pi, sizeof(struct process_info));
-                               g_ptr_array_add(pi_list, pi);
+                               g_ptr_array_add(pi_list, pnode);
+                               g_hash_table_iter_steal(&iter);
                                continue;
                        }
 
                        parent_pnode = pnode->parent;
                        while (parent_pnode != NULL) {
-                               if (parent_pnode->pi.ppid == root_pi->pid) {
-                                       pi = malloc(sizeof(struct process_info));
-                                       if (!pi) {
-                                               g_ptr_array_free(pi_list, true);
-                                               ctx->pi_list = NULL;
-                                               goto out_free_hash;
-                                       }
-
-                                       memcpy(pi, &pnode->pi, sizeof(struct process_info));
-                                       g_ptr_array_add(pi_list, pi);
+                               if (parent_pnode->stats->ac_ppid == ctx->root_stats.ac_pid) {
+                                       g_ptr_array_add(pi_list, pnode);
+                                       g_hash_table_iter_steal(&iter);
                                        break;
                                }
                                parent_pnode = parent_pnode->parent;
@@ -357,7 +336,7 @@ static int process_group_init(struct resource *res)
        if (!ctx)
                return -ENOMEM;
 
-       ctx->root_pi.pid = ctx->root_pi.ppid = -1;
+       ctx->root_stats.ac_pid = ctx->root_stats.ac_ppid = -1;
        ctx->pi_list = NULL;
 
        res->priv = ctx;
@@ -367,8 +346,19 @@ static int process_group_init(struct resource *res)
 
 static void process_group_exit(struct resource *res)
 {
-       if (res && res->priv)
+       struct process_group_context *ctx;
+
+       if (res && res->priv) {
+               ctx = res->priv;
+
+               if (ctx->pi_list) {
+                       /* remove previous list */
+                       g_ptr_array_free(ctx->pi_list, true);
+                       ctx->pi_list = NULL;
+               }
+
                free(res->priv);
+       }
 }
 
 static const struct resource_driver process_group_driver = {