Support CPU throttling 50/275150/2
authorUnsung Lee <unsung.lee@samsung.com>
Mon, 16 May 2022 09:16:53 +0000 (18:16 +0900)
committerUnsung Lee <unsung.lee@samsung.com>
Tue, 17 May 2022 08:13:49 +0000 (17:13 +0900)
Change-Id: Icfa85a3228e9eaf0f94605561ac15f870d829641
Signed-off-by: Unsung Lee <unsung.lee@samsung.com>
conf/limiter.conf
src/common/cgroup/cpu-cgroup.h
src/common/config-parser.c
src/common/config-parser.h
src/common/dedup-common.c
src/common/notifier.h
src/common/proc-common.h
src/resource-limiter/cpu/cpu.c
src/resourced/init.c

index 8cff59f..b6ec42e 100644 (file)
@@ -18,3 +18,10 @@ OomPopup=            no
 
 [MemoryAppStatusLimit]
 #BackgroundPerAppLimitAction=768MB,kill
+
+[CpuThrottling]
+CpuSched=idle
+#CpuNice=19
+CpuShare=64
+CpuCFSRuntime=50ms
+CpuCFSPeriod=1s
index dc9af02..e01a3f9 100644 (file)
 #ifndef __CPU_CGROUP_H__
 #define __CPU_CGROUP_H__
 
+#include "cgroup.h"
 #include "proc-common.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-#define CPUCG_NAME                                             "cpu"
+#define CPUCG_THROTTLING_NAME           "Throttling"
+
+#define CPUCG_NAME                      "cpu"
 #define CPUCG_PATH                      CGROUP_PATH "/" CPUCG_NAME
+#define CPUCG_THROTTLING_PATH           CPUCG_PATH "/" CPUCG_THROTTLING_NAME
 
 #define CPUCG_CONTROL_BANDWIDTH         "cpu.cfs_quota_us"
 #define CPUCG_CONTROL_FULL_BANDWIDTH    "cpu.cfs_period_us"
@@ -40,12 +44,7 @@ extern "C" {
 #define CPUCG_RT_CONTROL_FULL_BANDWIDTH "cpu.rt_period_us"
 #define CPUCG_SHARE                     "cpu.shares"
 
-#define CPUCG_THROTTLING_NAME           "Throttling"
 
-struct cpucg_conf {
-       char name[64];
-       char value[64];
-};
 
 int cpu_move_cgroup_foreach(pid_t pid, struct proc_app_info *pai, char *path);
 int cpucg_make_full_subdir(const char* parentdir);
index e52da01..405e160 100644 (file)
@@ -681,6 +681,17 @@ static int vendor_config(struct parse_result *result, void *user_data)
                error = set_mem_action_conf(&pci->mem_action, result->value);
                return error;
        }
+       else if (!strncmp(result->name, CPU_THROTTLING_NAME_CONF,
+               strlen(CPU_THROTTLING_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) {
+
+               if (!pci) {
+                       _E("process configuration information pointer should not be NULL");
+                       return RESOURCED_ERROR_FAIL;
+               }
+
+               /* Enable throttling of an app (or a service) */
+               pci->cpu_throttling_enable = config_parse_bool(result->value);
+       }
        /* optimizer.conf.d */
        else if (!strncmp(result->name, CPU_SCHED_NAME_CONF, strlen(CPU_SCHED_NAME_CONF)+1) &&
                        *config_type == OPTIMIZER_CONFIG) {
index 5b3b121..fd8b638 100644 (file)
@@ -28,7 +28,7 @@ extern "C" {
 #endif /* __cplusplus */
 
 
-#define CONF_FILE_SUFFIX                       ".conf"
+#define CONF_FILE_SUFFIX                    ".conf"
 
 #define LIMITER_CONF_FILE                   RD_CONFIG_FILE(limiter)
 #define OPTIMIZER_CONF_FILE                 RD_CONFIG_FILE(optimizer)
@@ -62,7 +62,6 @@ extern "C" {
 /* limiter.conf */
 #define SERVICE_NAME_CONF                            "Service"
 #define APP_NAME_CONF                                "App"
-//#define CPU_CGROUP_NAME_CONF                 "CpuGroup"
 #define MEM_CGROUP_NAME_CONF                         "MemGroup"
 #define MEM_LIMIT_ACTION_NAME_CONF                   "MemLimitAction"
 #define ACTION_ON_FAILURE_NAME_CONF                  "ActionOnFailure"
index dbaa927..c45be8c 100644 (file)
@@ -32,11 +32,11 @@ struct dedup_conf *get_dedup_conf(void)
                        _E("Failed to alloc memory for cpu configuration");
                        return NULL;
                }
-       }
-       else {
-               dedup_conf->enable = false;
-               dedup_conf->boot_dedup_enable = false;
-               dedup_conf->scan_on_lowmem = false;
+               else {
+                       dedup_conf->enable = false;
+                       dedup_conf->boot_dedup_enable = false;
+                       dedup_conf->scan_on_lowmem = false;
+               }
        }
 
        return dedup_conf;
index b52f1f5..9258ee8 100644 (file)
@@ -93,11 +93,12 @@ enum notifier_type {
         */
        RESOURCED_NOTIFIER_SYSTEM_SERVICE,
        RESOURCED_NOTIFIER_LIMIT_SYSTEM_SERVICE,
+       RESOURCED_NOTIFIER_THROTTLING_SYSTEM_SERVICE,
 
        /*
         * real time scheduler
         */
-       RESOURCED_NOTIFIER_RT_SCHEDULER,
+//     RESOURCED_NOTIFIER_RT_SCHEDULER,
 
        /*
         * receive external event
index eb15854..9255d30 100644 (file)
@@ -68,6 +68,7 @@ struct proc_conf_info {
        enum proc_action fail_action;           /* release action */
        struct mem_action mem_action;
        struct cpu_sched_info cpu_sched_info;
+       bool cpu_throttling_enable;
        pid_t pid;
 };
 
index f58b97d..af95d41 100644 (file)
@@ -41,6 +41,7 @@
 #include "resourced.h"
 #include "trace.h"
 #include "vconf.h"
+#include "util.h"
 #include "cgroup.h"
 #include "config-parser.h"
 #include "const.h"
 #define CPU_BACKGROUND_PRI    1
 #define CPU_CONTROL_PRI       10
 
-static void cpu_priority_update(int which, pid_t pid, int priority, struct proc_app_info *pai)
+bool throttling_success = false;
+bool skip_bandwidth = false;
+bool skip_share = false;
+struct sched_attr throttling_attr;
+struct sched_attr normal_attr;
+
+static int move_process_to_throttling_group(pid_t pid, struct proc_app_info *pai)
 {
-       if (pai && pai->app_cpu_nice_update_exclude)
-               return;
+       GSList *iter = NULL;
+       pid_t child_pid;
+
+       if (!throttling_success)
+               return RESOURCED_ERROR_NONE;
+
+       if (pai) {
+               if (pai->app_cpu_nice_update_exclude)
+                       goto cpu_cgroup_move;
+
+               sched_setattr_of_all_tasks(pai->main_pid, &throttling_attr, 0);
+               if (pai->childs) {
+                       gslist_for_each_item(iter, pai->childs) {
+                               child_pid = GPOINTER_TO_PID(iter->data);
+                               sched_setattr_of_all_tasks(child_pid, &throttling_attr, 0);
+                       }
+               }
+       }
+       else {
+               sched_setattr_of_all_tasks(pid, &throttling_attr, 0);
+       }
+
+cpu_cgroup_move:
+       if (!skip_share || !skip_bandwidth)
+               return cpu_move_cgroup_foreach(pid, pai, CPUCG_THROTTLING_PATH);
+       else
+               return RESOURCED_ERROR_NONE;
+}
+
+static int move_out_process_from_throttling_group(pid_t pid, struct proc_app_info *pai)
+{
+       GSList *iter = NULL;
+       pid_t child_pid;
+
+       if (!throttling_success)
+               return RESOURCED_ERROR_NONE;
+
+       if (pai) {
+               if (pai->app_cpu_nice_update_exclude)
+                       goto cpu_cgroup_move;
+
+               sched_setattr_of_all_tasks(pai->main_pid, &normal_attr, 0);
+               if (pai->childs) {
+                       gslist_for_each_item(iter, pai->childs) {
+                               child_pid = GPOINTER_TO_PID(iter->data);
+                               sched_setattr_of_all_tasks(child_pid, &normal_attr, 0);
+                       }
+               }
+       }
+       else {
+               sched_setattr_of_all_tasks(pid, &normal_attr, 0);
+       }
 
-       setpriority(which, pid, priority);
+cpu_cgroup_move:
+       if (!skip_share || !skip_bandwidth)
+               return cpu_move_cgroup_foreach(pid, pai, CPUCG_PATH);
+       else
+               return RESOURCED_ERROR_NONE;
 }
 
 static int cpu_foreground_state(void *data)
 {
+       int ret;
        struct proc_status *ps = (struct proc_status *)data;
-       int pri;
 
        assert(ps);
        _D("app foreground: pid = %d", ps->pid);
-       pri = getpriority(PRIO_PROCESS, ps->pid);
-       if (pri == -1 || pri > CPU_DEFAULT_PRI)
-               cpu_priority_update(PRIO_PGRP, ps->pid, CPU_DEFAULT_PRI, ps->pai);
+       ret = move_out_process_from_throttling_group(ps->pid, ps->pai);
+       if (ret < 0)
+               _E("Failed to throttle cpu resource of %s%s process (%d)",
+               ps->pai ? "App " : "System service",
+               ps->pai ? ps->pai->appid : "", ps->pid);
        return RESOURCED_ERROR_NONE;
 }
 
 static int cpu_background_state(void *data)
 {
+       int ret;
        struct proc_status *ps = (struct proc_status *)data;
        assert(ps);
 
        _D("app background: pid = %d", ps->pid);
-       cpu_priority_update(PRIO_PGRP, ps->pid, CPU_BACKGROUND_PRI, ps->pai);
+       ret = move_process_to_throttling_group(ps->pid, ps->pai);
+       if (ret < 0)
+               _E("Failed to throttle cpu resource of %s%s process (%d)",
+               ps->pai ? "App " : "System service",
+               ps->pai ? ps->pai->appid : "", ps->pid);
        return RESOURCED_ERROR_NONE;
 }
 
-static int resourced_cpu_init(void *data)
+static void load_cpu_throttling_config(void)
 {
-       int ret_code;
+       int ret;
+       int cpu_nice;
+       long long cpu_runtime_us;
+       unsigned long long cpu_period_us;
+       unsigned long long cpu_share;
+       enum cpu_sched_type cpu_sched_type;
+
+       struct cpu_throttling_conf *cpu_throttling_conf = get_cpu_throttling_conf();
+       if (cpu_throttling_conf == NULL) {
+               _E("[CPU-THROTTLING] cpu sched configuration structure should not be NULL");
+               return;
+       }
+
+       if (!cpu_throttling_conf->enable) {
+               _D("[CPU-THROTTLING] cpu throttling is disabled");
+               goto free_cpu_throttling_conf;
+       }
 
+       cpu_nice = cpu_throttling_conf->cpu_sched_info.cpu_nice;
+       cpu_sched_type = cpu_throttling_conf->cpu_sched_info.cpu_sched_type;
+       cpu_share = cpu_throttling_conf->cpu_cgroup_info.cpu_share;
+       cpu_period_us = cpu_throttling_conf->cpu_cgroup_info.cfs_period_us;
+       cpu_runtime_us = cpu_throttling_conf->cpu_cgroup_info.cfs_runtime_us;
+
+       if (cpu_share == 0) {
+               _E("[CPU-THROTTLING] cpu share cannot be 0");
+               cpu_share = CPU_THROTTLING_SHARE;
+               skip_share = true;
+       }
+
+       if (cpu_period_us == 0 || cpu_runtime_us == 0 ||
+                       cpu_period_us < cpu_runtime_us) {
+               _E("[CPU-THROTTLING] cpu period (%llu) and runtime (%lld) is out of scope",
+                               cpu_period_us, cpu_runtime_us);
+               skip_bandwidth = true;
+       }
+
+       if (cpu_sched_type < CPU_SCHED_IDLE || cpu_sched_type > CPU_SCHED_OTHER) {
+               _E("[CPU-THROTTLING] cpu scheduler type is unknown or realtime");
+               cpu_sched_type = CPU_SCHED_IDLE;
+       }
+
+       if (cpu_sched_type != CPU_SCHED_IDLE &&
+                       (cpu_nice < CPU_MIN_NICE || cpu_nice > CPU_MAX_NICE)) {
+               _W("[CPU-THROTTLING] cpu nice is out of scope");
+               cpu_nice = CPU_MAX_NICE;        /* the worst nice value */
+       }
+
+       /* Make a cpu throttling directory at the cpu cgroup */
+       if (!skip_share || !skip_bandwidth) {
+               ret = cpucg_make_full_subdir(CPUCG_PATH);
+               if (ret < 0) {
+                       _E("Failed to initialize cpu cgroup for throttling\n");
+                       goto free_cpu_throttling_conf;
+               }
+
+               /* Initialize cpu throttling cgroup */
+               cgroup_write_node_ulonglong(CPUCG_THROTTLING_PATH, CPUCG_SHARE, cpu_share);
+               cgroup_write_node_longlong(CPUCG_THROTTLING_PATH, CPUCG_CONTROL_BANDWIDTH,
+                               cpu_runtime_us);
+               cgroup_write_node_ulonglong(CPUCG_THROTTLING_PATH, CPUCG_CONTROL_FULL_BANDWIDTH,
+                               cpu_period_us);
+       }
+
+       /* Initialize type and nice of cpu throttling scheduler */
+       memset(&normal_attr, 0, sizeof(struct sched_attr));
+       normal_attr.size = sizeof(struct sched_attr);
+       normal_attr.sched_nice = CPU_DEFAULT_PRI;
+       normal_attr.sched_policy = SCHED_OTHER;
+
+       memset(&throttling_attr, 0, sizeof(struct sched_attr));
+       throttling_attr.size = sizeof(struct sched_attr);
+       throttling_attr.sched_nice = cpu_nice;
+       switch (cpu_sched_type) {
+               case CPU_SCHED_OTHER:
+                       throttling_attr.sched_policy = SCHED_OTHER;
+                       break;
+               case CPU_SCHED_IDLE:
+                       throttling_attr.sched_policy = SCHED_IDLE;
+                       break;
+               case CPU_SCHED_BATCH:
+                       throttling_attr.sched_policy = SCHED_BATCH;
+                       break;
+               default:
+                       if (!skip_share || !skip_bandwidth)
+                               rmdir(CPUCG_THROTTLING_PATH);
+                       goto free_cpu_throttling_conf;
+       }
+
+       throttling_success = true;
+
+       _I("[CPU-THROTTLING] throttling policy = %s",
+               throttling_attr.sched_policy == SCHED_IDLE ? "SCHED_IDLE" :
+                       throttling_attr.sched_policy == SCHED_BATCH ? "SCHED_BATCH" :
+                       throttling_attr.sched_policy == SCHED_OTHER ? "SCHED_OTHER" : "wrong scheduler type");
+       _I("[CPU-THROTTLING] throttling nice = %d", throttling_attr.sched_nice);
+
+free_cpu_throttling_conf:
+       free_cpu_throttling_conf();
+}
+
+static int resourced_cpu_init(void *data)
+{
        _D("resourced cpu init start");
-       ret_code = cpucg_make_full_subdir(CPUCG_PATH);
-       ret_value_msg_if(ret_code < 0, ret_code, "cpu cgroup init failed\n");
+       load_cpu_throttling_config();
+
        register_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_foreground_state);
        register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
        register_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_foreground_state);
        register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
+       register_notifier(RESOURCED_NOTIFIER_THROTTLING_SYSTEM_SERVICE, cpu_background_state);
 
        return RESOURCED_ERROR_NONE;
 }
@@ -111,6 +281,7 @@ static int resourced_cpu_finalize(void *data)
        unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
        unregister_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, cpu_foreground_state);
        unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
+       unregister_notifier(RESOURCED_NOTIFIER_THROTTLING_SYSTEM_SERVICE, cpu_background_state);
 
        return RESOURCED_ERROR_NONE;
 }
index d3248db..d9eb9b2 100644 (file)
@@ -365,12 +365,12 @@ skip_scheduler_update:
                }
 
                /* Put a system service into throttling group */
-/*             if (pci->cpu_throttling_enable) {
+               if (pci->cpu_throttling_enable) {
                        struct proc_status ps = {0, };
                        ps.pid = pid;
                        ps.pai = NULL;
                        resourced_notify(RESOURCED_NOTIFIER_THROTTLING_SYSTEM_SERVICE, &ps);
-               }*/
+               }
 /*             if (pci->cpu_sched_info.cpu_sched_type == CPU_SCHED_FIFO ||
                    pci->cpu_sched_info.cpu_sched_type == CPU_SCHED_RR ||
                        pci->cpu_sched_info.cpu_sched_type == CPU_SCHED_DEADLINE) {