proc-stat : record app's starttime and use it for getting cpu usage 16/121216/6
authorKichan Kwon <k_c.kwon@samsung.com>
Mon, 27 Mar 2017 07:41:02 +0000 (16:41 +0900)
committerKichan Kwon <k_c.kwon@samsung.com>
Fri, 19 May 2017 01:37:58 +0000 (10:37 +0900)
- In previous approach, starttime is gotten from /proc/{pid}/stat
- But, this value can't guarantee time delta with current uptime
  - In case of multicore environment
- Therefore, we will use the uptime when app is launched

- To use uptime to starttime, we will store this time

Change-Id: I86dab9bc261012686a1e92ed7c2b2bd3fdf5be47
Signed-off-by: Kichan Kwon <k_c.kwon@samsung.com>
src/common/file-helper.c
src/common/file-helper.h
src/common/proc-common.h
src/proc-stat/proc-main.c
src/proc-stat/proc-monitor.c

index 8f1f599..0cb3bb0 100644 (file)
@@ -80,6 +80,18 @@ int fwrite_uint(const char *path, const u_int32_t number)
        return fwrite_str(path, digit_buf);
 }
 
+int fwrite_ulong(const char *path, const unsigned long number)
+{
+       _cleanup_free_ char *digit_buf = NULL;
+       int ret;
+
+       ret = asprintf(&digit_buf, "%lu", number);
+       ret_value_errno_msg_if(ret < 0, -ENOMEM,
+                              "sprintf failed\n");
+
+       return fwrite_str(path, digit_buf);
+}
+
 int fread_str(const char *path, char **str)
 {
        _cleanup_fclose_ FILE *f = NULL;
@@ -127,6 +139,22 @@ int fread_uint(const char *path, u_int32_t *number)
        return RESOURCED_ERROR_NONE;
 }
 
+int fread_ulong(const char *path, unsigned long *number)
+{
+       _cleanup_fclose_ FILE *f = NULL;
+       int ret;
+
+       f = fopen(path, "r");
+       ret_value_errno_msg_if(!f, -errno,
+                              "Fail to open %s file.", path);
+
+       ret = fscanf(f, "%lu", number);
+       ret_value_errno_msg_if(ret == EOF, -errno,
+                              "Fail to read file\n");
+
+       return RESOURCED_ERROR_NONE;
+}
+
 int fwrite_array(const char *path, const void *array,
                 const size_t size_of_elem,
                 const size_t numb_of_elem)
index 96da0bc..0b932e8 100644 (file)
@@ -39,12 +39,16 @@ int fwrite_int(const char *path, const int number);
 
 int fwrite_uint(const char *path, const u_int32_t number);
 
+int fwrite_ulong(const char *path, const unsigned long number);
+
 int fread_str(const char *path, char **str);
 
 int fread_int(const char *path, int32_t *number);
 
 int fread_uint(const char *path, u_int32_t *number);
 
+int fread_ulong(const char *path, unsigned long *number);
+
 int fwrite_array(const char *path, const void *array,
                 const size_t size_of_elem,
                 const size_t numb_of_elem);
index 461249b..49ba2ac 100644 (file)
@@ -175,7 +175,7 @@ struct proc_app_info {
        struct resourced_appinfo *ai;
        struct proc_program_info *program;
        struct proc_memory_state memory;
-
+       unsigned long starttime;
 };
 
 int proc_get_freezer_status(void);
index cd82668..0cec334 100644 (file)
@@ -206,6 +206,33 @@ static char *proc_get_runtime_app_info_path(const struct proc_app_info *pai)
                return fread_uint(app_info_node, data); \
        }
 
+#define DEFINE_PROC_RUNTIME_APP_INFO_WRITE_ULONG(node)                 \
+       int proc_runtime_app_info_write_##node(const char *path,        \
+                                              unsigned long data)              \
+       {                                                               \
+               char app_info_node[PATH_MAX] = "";                      \
+                                                                       \
+               assert(path);                                           \
+                                                                       \
+               snprintf(app_info_node, PATH_MAX, "%s/"#node"", path);  \
+                                                                       \
+               return fwrite_ulong(app_info_node, data);               \
+       }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_READ_ULONG(node)                  \
+       int proc_runtime_app_info_read_##node(const char *path,         \
+                                             unsigned long *data)              \
+       {                                                               \
+               char app_info_node[PATH_MAX] = "";                      \
+                                                                       \
+               assert(path);                                           \
+               assert(data);                                           \
+                                                                       \
+               snprintf(app_info_node, PATH_MAX, "%s/"#node"", path);  \
+                                                                       \
+               return fread_ulong(app_info_node, data);        \
+       }
+
 #define DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(node)                      \
        int proc_runtime_app_info_remove_##node(const char *path)       \
        {                                                               \
@@ -241,6 +268,8 @@ DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(type);
 DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(type);
 DEFINE_PROC_RUNTIME_APP_INFO_WRITE_STR(pkgname);
 DEFINE_PROC_RUNTIME_APP_INFO_READ_STR(pkgname);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_ULONG(starttime);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_ULONG(starttime);
 
 DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(appid);
 DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(procs);
@@ -252,6 +281,8 @@ DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(categories);
 DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(state);
 DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(type);
 DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(pkgname);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(starttime);
+
 
 static int proc_runtime_app_info_write_procs(const char *path, pid_list child_list)
 {
@@ -573,6 +604,10 @@ static int proc_runtime_write_app_info(const struct proc_app_info *pai)
        if (ret < 0)
                return ret;
 
+       ret = proc_runtime_app_info_write_starttime(runtime_app_info_path, pai->starttime);
+       if (ret < 0)
+               return ret;
+
        if (!pai->program)
                return 0;
 
@@ -637,6 +672,10 @@ static int proc_runtime_remove_app_info(const struct proc_app_info *pai)
        if (ret < 0 && ret != -ENOENT)
                goto finish;
 
+       ret = proc_runtime_app_info_remove_starttime(runtime_app_info_path);
+       if (ret < 0 && ret != -ENOENT)
+               goto finish;
+
 finish:
        if (rmdir(runtime_app_info_path) < 0)
                return -errno;
@@ -686,6 +725,8 @@ static struct proc_app_info *proc_create_app_info(const char *appid,
                                           enum proc_state state)
 {
        struct proc_app_info *pai;
+       unsigned long uptime = 0;
+       int ret;
 
        if (!appid || !pkgid) {
                _E("Each app should have appid and pkgid");
@@ -757,8 +798,16 @@ static struct proc_app_info *proc_create_app_info(const char *appid,
        if (categories)
                pai->categories = categories;
 
-       pai->program = proc_add_program_list(type, pai, pkgid, false);
-
+       if (pid > 0) {
+               pai->program = proc_add_program_list(type, pai, pkgid, false);
+               if (!pai->starttime) {
+                       ret = proc_get_uptime(&uptime);
+                       if (ret)
+                               _E("Failed to get uptime");
+                       else
+                               pai->starttime = uptime;
+               }
+       }
        return pai;
 }
 struct proc_app_info *proc_add_app_info(const char *appid,
@@ -1219,6 +1268,10 @@ static int proc_restore_runtime_app_info(const char *path)
        if (ret < 0)
                return ret;
 
+       ret = proc_runtime_app_info_read_starttime(path, &pai->starttime);
+       if (ret < 0)
+               return ret;
+
        ret = proc_runtime_app_info_read_procs(path, &pai->childs);
        if (ret < 0 && ret != -ENOENT)
                return ret;
index 308efbf..4e7aa30 100755 (executable)
@@ -269,7 +269,7 @@ static void dbus_get_cpu_list(GDBusMethodInvocation *invocation, GVariant *param
        GSList *giter;
        char *appid;
        struct proc_app_info *pai;
-       unsigned long uptime, utime, stime, starttime;
+       unsigned long uptime, utime, stime, deltatime, starttime;
        int ret;
        GVariantBuilder builder, *sub_builder;
 
@@ -292,7 +292,12 @@ static void dbus_get_cpu_list(GDBusMethodInvocation *invocation, GVariant *param
                if (proc_get_cpu_time(pai->main_pid, &utime, &stime, &starttime) != RESOURCED_ERROR_NONE)
                        continue;
                appid = pai->appid;
-               percent = 100 * (((utime + stime) * 1000 / HZ) / (uptime - (starttime / HZ)));
+
+               deltatime = uptime - pai->starttime;
+               if (deltatime == 0)
+                       percent = 0;
+               else
+                       percent = (utime + stime) / deltatime;
 
                g_variant_builder_add(sub_builder, "(su)", appid, percent);
        }
@@ -349,7 +354,7 @@ static void dbus_get_cpu_lists(GDBusMethodInvocation *invocation, GVariant *para
        int ret, type;
        char *appid;
        struct proc_app_info *pai;
-       unsigned long uptime, utime, stime, starttime;
+       unsigned long uptime, utime, stime, deltatime, starttime;
        GVariantBuilder builder, *sub_builder;
 
        g_variant_get(params, "(i)", &type);
@@ -380,7 +385,21 @@ static void dbus_get_cpu_lists(GDBusMethodInvocation *invocation, GVariant *para
                if (proc_get_cpu_time(pai->main_pid, &utime, &stime, &starttime) != RESOURCED_ERROR_NONE)
                        continue;
                appid = pai->appid;
-               percent = (((utime + stime)*100 /HZ) / (uptime - (starttime/HZ)));
+
+               /*
+                * cpu usage can be calculated using total usage of stime and utime out of delta time.
+                * cpu usage = (utime + stime ticks) / (current uptime - process start time) * 100 percentage
+                *           = (utime + stime seconds) / (current uptime - process start time)
+                *
+                * Meanwhile, delta time between uptime and starttime should be checked
+                * whether it is zero or not.
+                * If delta time is zero, it can cause "divided by zero" fatal error.
+                */
+               deltatime = uptime - pai->starttime;
+               if (deltatime == 0)
+                       percent = 0;
+               else
+                       percent = (utime + stime) / deltatime;
 
                g_variant_builder_add(sub_builder, "(su)", appid, percent);
        }