util: kernel: Make query_taskstats() common kernel utility function 54/273454/1
authorDongwoo Lee <dwoo08.lee@samsung.com>
Thu, 31 Mar 2022 03:14:56 +0000 (12:14 +0900)
committerDongwoo Lee <dwoo08.lee@samsung.com>
Wed, 6 Apr 2022 04:51:48 +0000 (13:51 +0900)
To use taskstats in other drivers as well as process driver,
query_taskstat() now become common kernel utility function and
name is changed as following kernel util naming rules.

Change-Id: I64eff1892d908d22a0f8f831949b2c072cc0e68b
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
include/util/kernel.h
src/resource/resource-process.c
src/util/kernel.c

index 9846466..5938d9f 100644 (file)
@@ -20,6 +20,7 @@
 #define __KERNEL_H__
 
 #include <glib.h>
+#include <linux/taskstats.h>
 #include "common.h"
 
 struct cpu_stat {
@@ -55,4 +56,6 @@ int kernel_get_memory_total(u_int64_t *val);
 
 int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len,
                                   char *stat_fields[PROCESS_STAT_FIELD_MAX]);
+int kernel_get_process_taskstats(struct taskstats *stats, int cmd_type, pid_t pid);
+int kernel_get_thread_group_taskstats(struct taskstats *stats, pid_t tgid, bool get_proc_info);
 #endif
index 5702c10..00fb14c 100644 (file)
@@ -18,9 +18,6 @@
 
 #include <unistd.h>
 #include <linux/taskstats.h>
-#include <netlink/netlink.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/ctrl.h>
 
 #include <util/log.h>
 #include <util/resource.h>
@@ -308,163 +305,6 @@ static u_int64_t get_total_cpu_time(void)
        return total_time;
 }
 
-static int parse_aggregate_task_stats(struct nlattr *attr, int attr_size,
-                                       struct taskstats *stats)
-{
-       nla_for_each_attr(attr, attr, attr_size, attr_size) {
-               switch (attr->nla_type) {
-               case TASKSTATS_TYPE_PID:
-               case TASKSTATS_TYPE_TGID:
-                       break;
-               case TASKSTATS_TYPE_STATS:
-                       nla_memcpy(stats, attr, sizeof(struct taskstats));
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-static int parse_task_stats(struct nl_msg *msg, void *arg)
-{
-       struct genlmsghdr *hdr = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
-       struct nlattr *attr = genlmsg_attrdata(hdr, 0);
-       int remaining = genlmsg_attrlen(hdr, 0);
-       int ret;
-
-       nla_for_each_attr(attr, attr, remaining, remaining) {
-               switch (attr->nla_type) {
-               case TASKSTATS_TYPE_AGGR_PID:
-               case TASKSTATS_TYPE_AGGR_TGID:
-                       ret = parse_aggregate_task_stats(nla_data(attr),
-                                                  nla_len(attr), arg);
-                       if (ret < 0) {
-                               _E("failed to parse netlink message\n");
-                               return NL_STOP;
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-       return NL_STOP;
-}
-
-static int print_receive_error(struct sockaddr_nl *address,
-                               struct nlmsgerr *error, void *arg)
-{
-       return NL_STOP;
-}
-
-static int query_taskstats(struct taskstats *stats, int cmd_type, pid_t pid)
-{
-       struct nl_sock *sock;
-       struct nl_msg *msg;
-       struct nl_cb *cb;
-       int ret;
-
-       sock = nl_socket_alloc();
-       if (!sock)
-               return -ENOMEM;
-
-       ret = genl_connect(sock);
-       if (ret < 0)
-               goto err_free_sock;
-
-       ret = genl_ctrl_resolve(sock, TASKSTATS_GENL_NAME);
-       if (ret < 0)
-               goto err_genl_close;
-
-       msg = nlmsg_alloc();
-       if (!msg) {
-               ret = -ENOMEM;
-               goto err_genl_close;
-       }
-
-       genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ret, 0, 0, TASKSTATS_CMD_GET, TASKSTATS_VERSION);
-
-       ret = nla_put_u32(msg, cmd_type, pid);
-       if (ret < 0)
-               goto err_msg_free;
-
-       ret = nl_send_auto_complete(sock, msg);
-       nlmsg_free(msg);
-       if (ret < 0)
-               goto err_genl_close;
-
-       cb = nl_cb_get(nl_cb_alloc(NL_CB_CUSTOM));
-       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, &parse_task_stats, stats);
-       nl_cb_err(cb, NL_CB_CUSTOM, &print_receive_error, NULL);
-
-       ret = nl_recvmsgs(sock, cb);
-       nl_cb_put(cb);
-       if (ret < 0)
-               goto err_genl_close;
-
-       nl_close(sock);
-       nl_socket_free(sock);
-
-       return 0;
-
-err_msg_free:
-       nlmsg_free(msg);
-err_genl_close:
-       nl_close(sock);
-err_free_sock:
-       nl_socket_free(sock);
-
-       return ret;
-}
-
-static int update_taskstats(struct process_context *ctx)
-{
-       struct taskstats stats, *curr = &ctx->curr;
-       struct dirent *task_entry;
-       DIR *task_dir;
-       char task_dir_path[BUFF_MAX];
-       pid_t pid;
-       int ret;
-
-       memset(curr, 0, sizeof(struct taskstats));
-
-       sprintf(task_dir_path, "/proc/%d/task/", ctx->tgid);
-
-       task_dir = opendir(task_dir_path);
-       if (!task_dir)
-               return -ESRCH;
-
-       while ((task_entry = readdir(task_dir)) != NULL) {
-               const char *name = task_entry->d_name;
-
-               if (task_entry->d_type != DT_DIR && task_entry->d_type != DT_UNKNOWN)
-                       continue;
-
-               if (name[0] < '0' || name[0] > '9')
-                       continue;
-
-               pid = strtoul(name, NULL, 10);
-
-               ret = query_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, pid);
-               if (ret < 0)
-                       /* threads can be removed before get taskstats */
-                       continue;
-
-               curr->ac_utime += stats.ac_utime;
-               curr->ac_stime += stats.ac_stime;
-               curr->ac_etime += stats.ac_etime;
-               curr->virtmem += stats.virtmem;
-               curr->coremem += stats.coremem;
-               curr->read_bytes += stats.read_bytes;
-               curr->write_bytes += stats.write_bytes;
-       }
-
-       closedir(task_dir);
-
-       return 0;
-}
-
 static int process_setup_tgid(const struct resource *res,
                                const struct resource_control *ctrl,
                                const void *data)
@@ -488,7 +328,7 @@ static int process_setup_tgid(const struct resource *res,
        ctx->prev_total_time = get_total_cpu_time();
 
        /* update initial status */
-       ret = update_taskstats(ctx);
+       ret = kernel_get_process_taskstats(&ctx->curr, ctx->tgid, false);
        if (ret < 0)
                return ret;
 
@@ -524,7 +364,7 @@ static int process_prepare_update(struct resource *res)
 
        memcpy(&ctx->prev, &ctx->curr, sizeof(struct taskstats));
 
-       ret = update_taskstats(ctx);
+       ret = kernel_get_thread_group_taskstats(&ctx->curr, ctx->tgid, false);
        if (ret < 0)
                return ret;
 
index 3a9c2d6..653b297 100644 (file)
@@ -19,6 +19,9 @@
 #include <glib.h>
 #include <stdio.h>
 #include <string.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
 
 #include <util/common.h>
 #include <util/log.h>
@@ -243,3 +246,164 @@ int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len,
 
        return 0;
 }
+
+static int parse_aggregate_task_stats(struct nlattr *attr, int attr_size,
+                                       struct taskstats *stats)
+{
+       nla_for_each_attr(attr, attr, attr_size, attr_size) {
+               switch (attr->nla_type) {
+               case TASKSTATS_TYPE_PID:
+               case TASKSTATS_TYPE_TGID:
+                       break;
+               case TASKSTATS_TYPE_STATS:
+                       nla_memcpy(stats, attr, sizeof(struct taskstats));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int parse_task_stats(struct nl_msg *msg, void *arg)
+{
+       struct genlmsghdr *hdr = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg));
+       struct nlattr *attr = genlmsg_attrdata(hdr, 0);
+       int remaining = genlmsg_attrlen(hdr, 0);
+       int ret;
+
+       nla_for_each_attr(attr, attr, remaining, remaining) {
+               switch (attr->nla_type) {
+               case TASKSTATS_TYPE_AGGR_PID:
+               case TASKSTATS_TYPE_AGGR_TGID:
+                       ret = parse_aggregate_task_stats(nla_data(attr),
+                                                  nla_len(attr), arg);
+                       if (ret < 0) {
+                               _E("failed to parse netlink message\n");
+                               return NL_STOP;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       return NL_STOP;
+}
+
+static int print_receive_error(struct sockaddr_nl *address,
+                               struct nlmsgerr *error, void *arg)
+{
+       return NL_STOP;
+}
+
+int kernel_get_process_taskstats(struct taskstats *stats, int cmd_type, pid_t pid)
+{
+       struct nl_sock *sock;
+       struct nl_msg *msg;
+       struct nl_cb *cb;
+       int ret;
+
+       sock = nl_socket_alloc();
+       if (!sock)
+               return -ENOMEM;
+
+       ret = genl_connect(sock);
+       if (ret < 0)
+               goto err_free_sock;
+
+       ret = genl_ctrl_resolve(sock, TASKSTATS_GENL_NAME);
+       if (ret < 0)
+               goto err_genl_close;
+
+       msg = nlmsg_alloc();
+       if (!msg) {
+               ret = -ENOMEM;
+               goto err_genl_close;
+       }
+
+       genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ret, 0, 0, TASKSTATS_CMD_GET, TASKSTATS_VERSION);
+
+       ret = nla_put_u32(msg, cmd_type, pid);
+       if (ret < 0)
+               goto err_msg_free;
+
+       ret = nl_send_auto_complete(sock, msg);
+       nlmsg_free(msg);
+       if (ret < 0)
+               goto err_genl_close;
+
+       cb = nl_cb_get(nl_cb_alloc(NL_CB_CUSTOM));
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, &parse_task_stats, stats);
+       nl_cb_err(cb, NL_CB_CUSTOM, &print_receive_error, NULL);
+
+       ret = nl_recvmsgs(sock, cb);
+       nl_cb_put(cb);
+       if (ret < 0)
+               goto err_genl_close;
+
+       nl_close(sock);
+       nl_socket_free(sock);
+
+       return 0;
+
+err_msg_free:
+       nlmsg_free(msg);
+err_genl_close:
+       nl_close(sock);
+err_free_sock:
+       nl_socket_free(sock);
+
+       return ret;
+}
+
+int kernel_get_thread_group_taskstats(struct taskstats *stats, pid_t tgid, bool get_proc_info)
+{
+       struct taskstats pid_stats;
+       struct dirent *task_entry;
+       DIR *task_dir;
+       char task_dir_path[BUFF_MAX];
+       pid_t pid;
+       int ret;
+
+       ret = kernel_get_process_taskstats(stats, TASKSTATS_CMD_ATTR_TGID, tgid);
+       if (ret < 0)
+               return -EINVAL;
+
+       sprintf(task_dir_path, "/proc/%d/task/", tgid);
+
+       task_dir = opendir(task_dir_path);
+       if (!task_dir)
+               return -ESRCH;
+
+       while ((task_entry = readdir(task_dir)) != NULL) {
+               const char *name = task_entry->d_name;
+
+               if (task_entry->d_type != DT_DIR && task_entry->d_type != DT_UNKNOWN)
+                       continue;
+
+               if (name[0] < '0' || name[0] > '9')
+                       continue;
+
+               pid = strtoul(name, NULL, 10);
+
+               ret = kernel_get_process_taskstats(&pid_stats, TASKSTATS_CMD_ATTR_PID, pid);
+               if (ret < 0)
+                       /* threads can be removed before get taskstats */
+                       continue;
+
+               if (get_proc_info && tgid == pid_stats.ac_pid) {
+                       stats->ac_ppid = pid_stats.ac_ppid;
+                       memcpy(stats->ac_comm, pid_stats.ac_comm, strlen(pid_stats.ac_comm) + 1);
+               }
+
+               stats->virtmem += pid_stats.virtmem;
+               stats->coremem += pid_stats.coremem;
+               stats->read_bytes += pid_stats.read_bytes;
+               stats->write_bytes += pid_stats.write_bytes;
+       }
+
+       closedir(task_dir);
+
+       return 0;
+}