cpu-sched: add apps' static cpusets 64/237364/6
authorMaciej Słodczyk <m.slodczyk2@partner.samsung.com>
Mon, 29 Jun 2020 13:28:10 +0000 (15:28 +0200)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Tue, 21 Jul 2020 11:56:43 +0000 (11:56 +0000)
Change-Id: I1ce586e2923ea39c280c4e7bb53a04335554f5c1
Signed-off-by: Maciej Słodczyk <m.slodczyk2@partner.samsung.com>
src/cpu/cpu-sched.c

index 728396b..992a051 100644 (file)
@@ -8,6 +8,8 @@
 #include "notifier.h"
 #include "cpu-hotplug.h"
 #include "proc-common.h"
+#include "file-helper.h"
+#include "util.h"
 
 #define CPU_SCHED_CONF_FILE     RD_CONFIG_FILE(cpu-sched)
 #define CPU_SCHED_FG_NAME      "foreground"
@@ -27,11 +29,25 @@ struct coreset {
 
 struct cpu_sched {
        struct coreset fg;
+       GSList *apps;
        bool is_initalized;
 };
 
 static struct cpu_sched cs;
 
+struct coreset *cpu_sched_find_coreset(const char *name)
+{
+       GSList *i;
+       struct coreset *c;
+
+       gslist_for_each_item(i, cs.apps) {
+               c = (struct coreset *)i->data;
+               if (!strcmp(name, c->name))
+                       return c;
+       }
+       return NULL;
+}
+
 /* check if cpuset subsystem is mounted at the right location */
 static bool cpu_sched_is_cpuset_mounted()
 {
@@ -97,6 +113,8 @@ static int cpu_sched_init_cgroup_set(const struct coreset *set)
 static int cpu_sched_init_cgroup(struct cpu_sched *cs)
 {
        int r;
+       GSList *i;
+       struct coreset *c;
 
        _D("cpu-sched: init cgroup subsystem");
        if (false == cpu_sched_is_cpuset_mounted()) {
@@ -113,6 +131,14 @@ static int cpu_sched_init_cgroup(struct cpu_sched *cs)
                }
        }
 
+       gslist_for_each_item(i, cs->apps) {
+               c = (struct coreset *)i->data;
+               r = cpu_sched_init_cgroup_set(c);
+               if (r < 0) {
+                       _E("cpu-set: error setting up cpuset (%s)", c->name);
+                       return r;
+               }
+       }
        return cpu_sched_init_cgroup_set(&cs->fg);
 }
 
@@ -148,6 +174,17 @@ static void cpu_sched_free_cpuset(struct coreset *set)
        set->name = NULL;
 }
 
+/* free memory allocated in coreset structure and the structure */
+static void cpu_sched_free_cpuset_full(void *data)
+{
+       struct coreset *set = (struct coreset *)data;
+
+       assert(set);
+
+       cpu_sched_free_cpuset(set);
+       free(set);
+}
+
 /* parse config for specific coreset line */
 static int cpu_sched_parse_cpuset(struct coreset *set, char *value)
 {
@@ -200,17 +237,27 @@ static int load_config(struct parse_result *result, void *user_data)
 
        assert(data);
 
-       if (strcmp(result->name, CPU_SCHED_FG_NAME))
-               return RESOURCED_ERROR_NONE;
+       if (strcmp(result->name, CPU_SCHED_FG_NAME)) { /* not a 'foreground' group */
+               struct coreset *c = (struct coreset *)calloc(1, sizeof *c);
+               if (NULL == c)
+                       return RESOURCED_ERROR_OUT_OF_MEMORY;
+
+               c->name = strdup(result->name);
 
-       r = cpu_sched_parse_cpuset(&data->fg, result->value);
+               r = cpu_sched_parse_cpuset(c, result->value);
+
+               if (RESOURCED_ERROR_NONE == r)
+                       data->apps = g_slist_append(data->apps, c);
+       } else {
+               data->fg.name = strdup(CPU_SCHED_FG_NAME);
+               r = cpu_sched_parse_cpuset(&data->fg, result->value);
+       }
 
        if (r < 0) {
                _E("cpu-sched parse fg coreset: could not parse");
                return RESOURCED_ERROR_FAIL;
        }
 
-       data->fg.name = strdup(CPU_SCHED_FG_NAME);
        return RESOURCED_ERROR_NONE;
 }
 
@@ -315,12 +362,16 @@ static int cpu_sched_cpu_off_for_coreset(struct coreset *set, int core_id)
 static int cpu_sched_cpu_on(void *data)
 {
        int id;
+       GSList *i;
 
        assert(data);
 
        id = *(int*)(data);
 
        _D("cpu-sched: core %d plugged in", id);
+       gslist_for_each_item(i, cs.apps) {
+               cpu_sched_cpu_on_for_coreset((struct coreset *)i->data, id);
+       }
        cpu_sched_cpu_on_for_coreset(&cs.fg, id);
 
        return RESOURCED_ERROR_NONE;
@@ -329,21 +380,27 @@ static int cpu_sched_cpu_on(void *data)
 static int cpu_sched_cpu_off(void *data)
 {
        int id;
+       GSList *i;
 
        assert(data);
 
        id = *(int*)(data);
 
        _D("cpu-sched: core %d plugged out", id);
+       gslist_for_each_item(i, cs.apps) {
+               cpu_sched_cpu_off_for_coreset((struct coreset *)i->data, id);
+       }
+
        cpu_sched_cpu_off_for_coreset(&cs.fg, id);
 
        return RESOURCED_ERROR_NONE;
 }
 
-static int cpu_sched_add_pid_to_cpuset(struct coreset *set, pid_t pid)
+static int cpu_sched_add_pid_to_cpuset(struct coreset *set, pid_t pid, bool move_pid)
 {
        pid_t old_pid;
-       char path[128];
+       char path[PATH_MAX];
+       _cleanup_free_ char *buf = NULL;
        int r;
 
        assert(set);
@@ -355,20 +412,56 @@ static int cpu_sched_add_pid_to_cpuset(struct coreset *set, pid_t pid)
                return r;
        }
 
-       /* read pid of previous foreground app */
-       if (RESOURCED_ERROR_NONE != cgroup_read_node_int32(path, "tasks", &old_pid)) {
-               _E("cpu-sched: could not read old value of fg app's pid");
-               return RESOURCED_ERROR_FAIL;
-       }
+       buf = (char *)calloc(1, PATH_MAX);
+       if (NULL == buf)
+               return RESOURCED_ERROR_OUT_OF_MEMORY;
 
-       /* and write it to default cpuset */
-       r = cgroup_write_node_int32(CPUSET_CGROUP, "tasks", (u_int32_t)old_pid);
-       ret_value_msg_if(r < 0, RESOURCED_ERROR_FAIL,
-               "Failed to attach pid %d to cgroup %s : %m",
-                        old_pid, CPUSET_CGROUP);
+
+       if (true == move_pid) { /* in case of foreground app previous pid needs to be moved to main cpuset first */
+               /* read pid of previous foreground app, there can be only one */
+               if (RESOURCED_ERROR_NONE == cgroup_read_node_int32(path, "tasks", &old_pid)) {
+                       /* and write it to default cpuset */
+                       r = cgroup_write_node_int32(CPUSET_CGROUP, "tasks", (u_int32_t)old_pid);
+                       ret_value_msg_if(r < 0, RESOURCED_ERROR_FAIL,
+                               "Failed to attach pid %d to cgroup %s : %m",
+                                        old_pid, CPUSET_CGROUP);
+               }
+
+               r = snprintf(buf, PATH_MAX, "%d", pid);
+               if (r < 0) {
+                       _E("cpu-sched: failed to create pid list for cpuset (%s)", set->name);
+                       return r;
+               }
+
+       } else { /* in case of static apps new pid needs to be appended to existing pids */
+               char path_full[PATH_MAX];
+
+               r = snprintf(path_full, sizeof path_full, "%s/tasks", path);
+               if (r < 0) {
+                       _E("cpu-sched: failed to setup path for cpuset (%s)", set->name);
+                       return r;
+               }
+
+               r = 0;
+               /* read pid of previous apps in this cpuset, there can be more than one */
+               if (RESOURCED_ERROR_NONE != fread_str(path_full, &buf)) {
+                       _I("cpu-sched: could not read old value of app's pids, adding first one");
+                       r = snprintf(buf, PATH_MAX, "%d", pid);
+               } else {
+                       /* append new pid at the end */
+                       r = snprintf(buf + strlen(buf), PATH_MAX - strlen(buf), ",%d", pid);
+               }
+
+               if (r < 0) {
+                       _E("cpu-sched: failed to create pid list for cpuset (%s)", set->name);
+                       return r;
+               }
+               _D("cpu-sched: add new pids to cpuset %s: %s (%d)", set->name, buf, r);
+
+       }
 
        /* write current foreground app to proper cpuset */
-       r = cgroup_write_node_int32(path, "tasks", (u_int32_t)pid);
+       r = cgroup_write_node_str(path, "tasks", buf);
        ret_value_msg_if(r < 0, RESOURCED_ERROR_FAIL,
                "Failed to attach pid %d to cgroup %s : %m",
                         pid, path);
@@ -386,9 +479,31 @@ static int cpu_sched_app_foreground(void *data)
        if (false == cs.is_initalized)
                return RESOURCED_ERROR_NONE;
 
+       /* if this app is subject to static coreset config don't change that */
+       if (NULL != cpu_sched_find_coreset(ps->pai->appid))
+               return 0;
+
        _D("cpu-sched: app %s moved to foreground; pid=%d", ps->pai->appid, ps->pid);
 
-       return cpu_sched_add_pid_to_cpuset(&cs.fg, ps->pid);
+       return cpu_sched_add_pid_to_cpuset(&cs.fg, ps->pid, true);
+}
+
+
+static int cpu_sched_app_launch(void *data)
+{
+       struct proc_status *ps = (struct proc_status *)data;
+       struct coreset *c;
+
+       assert(ps);
+       assert(ps->pai);
+
+       _D("cpu-sched: app launch: %s", ps->pai->appid);
+
+       c = cpu_sched_find_coreset(ps->pai->appid);
+       if (NULL == c)
+               return 0;
+
+       return cpu_sched_add_pid_to_cpuset(c, ps->pid, false);
 }
 
 static void register_notifiers()
@@ -399,6 +514,8 @@ static void register_notifiers()
 
        register_notifier(RESOURCED_NOTIFIER_CPU_ON, cpu_sched_cpu_on);
        register_notifier(RESOURCED_NOTIFIER_CPU_OFF, cpu_sched_cpu_off);
+
+       register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, cpu_sched_app_launch);
 }
 
 static void unregister_notifiers()
@@ -409,6 +526,14 @@ static void unregister_notifiers()
 
        unregister_notifier(RESOURCED_NOTIFIER_CPU_ON, cpu_sched_cpu_on);
        unregister_notifier(RESOURCED_NOTIFIER_CPU_OFF, cpu_sched_cpu_off);
+
+       unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, cpu_sched_app_launch);
+}
+
+static void cpu_sched_free_cpusets()
+{
+       g_slist_free_full(g_steal_pointer(&cs.apps), cpu_sched_free_cpuset_full);
+       cpu_sched_free_cpuset(&cs.fg);
 }
 
 static int cpu_sched_init(void *data)
@@ -437,7 +562,7 @@ static int cpu_sched_init(void *data)
 init_failed:
        unregister_notifiers();
        cpu_hotplug_finalize();
-       cpu_sched_free_cpuset(&cs.fg);
+       cpu_sched_free_cpusets();
        cs.is_initalized = false;
        return RESOURCED_ERROR_FAIL;
 }
@@ -447,7 +572,7 @@ static int cpu_sched_finalize(void *data)
        _D("cpu-sched: deinit module");
        unregister_notifiers();
        cpu_hotplug_finalize();
-       cpu_sched_free_cpuset(&cs.fg);
+       cpu_sched_free_cpusets();
        cs.is_initalized = false;
        return RESOURCED_ERROR_NONE;
 }