cpu-boosting: Split a cpu boosting info table into three tables 22/297122/4
authorUnsung Lee <unsung.lee@samsung.com>
Thu, 10 Aug 2023 07:44:13 +0000 (16:44 +0900)
committerUnsung Lee <unsung.lee@samsung.com>
Mon, 28 Aug 2023 01:49:13 +0000 (10:49 +0900)
Split a cpu boosting info table into three independent cpu boosting info tables
according to cpu boosting level.
Currently, resourced supports three cpu boosting level
(CPU_BOOSTING_LEVEL_STRONG, CPU_BOOSTING_LEVEL_MEDIUM, and CPU_BOOSTING_LEVEL_WEAK).

Separate cpu boosting info table according to cpu boosting level
to find and handle threads with same cpu boosting level easily.

Change-Id: I9eb8eac89df8112e91802154401fd59bd0626781
Signed-off-by: Unsung Lee <unsung.lee@samsung.com>
src/common/conf/cpu-common.h
src/resource-optimizer/cpu/cpu-boosting.c

index 34e5ff8..74e872f 100644 (file)
@@ -45,6 +45,7 @@ struct cpu_boosting_info {
        pid_t tid;
        int level;                     /* current boosting level */
        guint gsource_id;              /* timer id */
+       int ref_cnt;                   /* Ref count */
 };
 
 struct cpu_boosting_input {
index 0588cd2..2783ea0 100644 (file)
@@ -20,8 +20,8 @@
 #include "cpu-common.h"
 #include "fd-handler.h"
 #include "proc-common.h"
-
-static GHashTable *tid_table;  /* key = tid, value = cpu_boosting info per thread (tid, attr, gsource_id) hash table */
+/* key = tid, value = cpu_boosting info per thread */
+static GHashTable *g_cpu_boosting_info_table[CPU_BOOSTING_LEVEL_END] = { NULL, };
 static GHashTable *dest_table;  /* key = destiation process name, value = cpu_boosting_input */
 
 pthread_t cpu_boosting_thread;
@@ -41,6 +41,44 @@ GMainContext *cpu_boosting_context;
        (_input)->client_input.pid = _pid;                                          \
 }
 
+static void free_cpu_boosting_info(gpointer data)
+{
+       struct cpu_boosting_info *cpu_boosting_info =
+               (struct cpu_boosting_info *)data;
+
+       assert(cpu_boosting_info);
+
+       cpu_boosting_info->ref_cnt--;
+       if (cpu_boosting_info->ref_cnt == 0)
+               free(cpu_boosting_info);
+}
+
+static void remove_cpu_boosting_info_in_tables(int *tid)
+{
+       gboolean ret_removed;
+       for (cpu_boosting_level_e cpu_boosting_level = CPU_BOOSTING_LEVEL_STRONG;
+                       cpu_boosting_level < CPU_BOOSTING_LEVEL_END; cpu_boosting_level++) {
+               ret_removed = g_hash_table_remove(
+                               g_cpu_boosting_info_table[cpu_boosting_level], tid);
+               if (ret_removed)
+                       return;
+       }
+}
+
+static void find_cpu_boosting_info_in_tables(
+               struct cpu_boosting_info **cpu_boosting_info, int *tid)
+{
+       assert(cpu_boosting_info);
+
+       for (cpu_boosting_level_e cpu_boosting_level = CPU_BOOSTING_LEVEL_STRONG;
+                       cpu_boosting_level < CPU_BOOSTING_LEVEL_END; cpu_boosting_level++) {
+               *cpu_boosting_info = g_hash_table_lookup(
+                               g_cpu_boosting_info_table[cpu_boosting_level], tid);
+               if (*cpu_boosting_info)
+                       return;
+       }
+}
+
 static cpu_boosting_level_e cpu_boosting_level_search(struct sched_attr attr)
 {
        attr.sched_policy = attr.sched_policy & ~SCHED_RESET_ON_FORK;
@@ -480,22 +518,41 @@ static gboolean cpu_boosting_timeout(gpointer data)
        int *tid_list = input->client_input.pid.tid;
 
        for (int i = 0; i < tid_count; i++) {
-               if (tid_list[i] > 0) {
-                       struct cpu_boosting_info *info = g_hash_table_lookup(tid_table, &tid_list[i]);
-                       /*
-                        * info is NULL when clearing boosting before timeout
-                        * info->gsource_id != *(input->gsource_id) when setting boosting again before timeout
-                        */
-                       if (info == NULL || info->gsource_id != *(input->gsource_id))
-                               continue;
+               struct cpu_boosting_info *cpu_boosting_info = NULL;
 
-                       g_hash_table_remove(tid_table, &tid_list[i]);
-                       ret = sched_setattr(tid_list[i], &cpu_boosting_attr[CPU_BOOSTING_LEVEL_NONE], 0);
-                       if (ret != RESOURCED_ERROR_NONE)
-                               _E("[CPU-BOOSTING] Failed to clear boost cpu of (tid = %d)", tid_list[i]);
+               if (tid_list[i] <= 0) {
+                       _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+                       continue;
                }
-               else
-                       _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+
+               find_cpu_boosting_info_in_tables(&cpu_boosting_info, &tid_list[i]);
+
+               /**
+                * cpu_boosting_info is NULL when clearing boosting before timeout.
+                * cpu_boosting_info->gsource_id != *(input->gsource_id)
+                * when setting cpu boosting again before timeout.
+                */
+               if (cpu_boosting_info == NULL
+                               || cpu_boosting_info->gsource_id != *(input->gsource_id))
+                       continue;
+
+               switch (cpu_boosting_info->level) {
+               case CPU_BOOSTING_LEVEL_STRONG:
+               case CPU_BOOSTING_LEVEL_MEDIUM:
+               case CPU_BOOSTING_LEVEL_WEAK:
+                       g_hash_table_remove(
+                                       g_cpu_boosting_info_table[cpu_boosting_info->level],
+                                       &tid_list[i]);
+                       break;
+               case CPU_BOOSTING_LEVEL_NONE:
+               default:
+                       _E("[CPU-BOOSTING] Unknown cpu boosting level (SIGABT)");
+                       assert(0);
+               }
+
+               ret = sched_setattr(tid_list[i], &cpu_boosting_attr[CPU_BOOSTING_LEVEL_NONE], 0);
+               if (ret != RESOURCED_ERROR_NONE)
+                       _E("[CPU-BOOSTING] Failed to clear boost cpu of (tid = %d)", tid_list[i]);
        }
 
        if (input->remove_input)
@@ -505,22 +562,54 @@ timer_out:
        return G_SOURCE_REMOVE;
 }
 
-static void cpu_boosting_find_and_insert_info(pid_t tid, cpu_boosting_level_e level, guint id)
+static void cpu_boosting_find_and_insert_info(pid_t tid,
+               cpu_boosting_level_e cpu_boosting_level, guint id)
 {
-       struct cpu_boosting_info *info = g_hash_table_lookup(tid_table, &tid);
-       if (info == NULL) {
-               info = (struct cpu_boosting_info *)calloc(1, sizeof (struct cpu_boosting_info));
-               if (info == NULL) {
+       struct cpu_boosting_info *cpu_boosting_info = NULL;
+
+       switch (cpu_boosting_level) {
+       case CPU_BOOSTING_LEVEL_STRONG:
+       case CPU_BOOSTING_LEVEL_MEDIUM:
+       case CPU_BOOSTING_LEVEL_WEAK:
+               break;
+       case CPU_BOOSTING_LEVEL_NONE:
+       default:
+               _E("[CPU-BOOSTING] Cannot boosting unknown or none level");
+               return;
+       }
+
+       find_cpu_boosting_info_in_tables(&cpu_boosting_info, &tid);
+       if (cpu_boosting_info == NULL) {
+               cpu_boosting_info = (struct cpu_boosting_info *)
+                       calloc(1, sizeof (struct cpu_boosting_info));
+               if (cpu_boosting_info == NULL) {
                        _E("[CPU-BOOSTING] Failed to allocate memory");
                        return;
                }
 
-               info->tid = tid;
-               g_hash_table_insert(tid_table, &info->tid, info);
+               cpu_boosting_info->tid = tid;
+               cpu_boosting_info->ref_cnt = 1;
+
+               g_hash_table_insert(g_cpu_boosting_info_table[cpu_boosting_level],
+                               &cpu_boosting_info->tid, cpu_boosting_info);
+       } else if (cpu_boosting_info->level != cpu_boosting_level) {
+               /**
+                * Do not free cpu_boosting_info in
+                * g_cpu_boosting_info_table[cpu_boosting_info->level].
+                * This is because the corresponding cpu_boosting_info
+                * will be reused as a value in another table
+                * (g_cpu_boosting_info_table[cpu_boosting_level]
+                */
+               cpu_boosting_info->ref_cnt++;
+               g_hash_table_remove(
+                               g_cpu_boosting_info_table[cpu_boosting_info->level],
+                               &cpu_boosting_info->tid);
+               g_hash_table_insert(g_cpu_boosting_info_table[cpu_boosting_level],
+                               &cpu_boosting_info->tid, cpu_boosting_info);
        }
 
-       info->level = level;
-       info->gsource_id = id;
+       cpu_boosting_info->level = cpu_boosting_level;
+       cpu_boosting_info->gsource_id = id;
 }
 
 static void cpu_boosting_set(struct cpu_boosting_input *input)
@@ -534,6 +623,18 @@ static void cpu_boosting_set(struct cpu_boosting_input *input)
        int timeout_msec = input->client_input.timeout_msec;
        cpu_boosting_level_e cpu_boosting_level = input->client_input.level;
 
+       switch (cpu_boosting_level) {
+       case CPU_BOOSTING_LEVEL_STRONG:
+       case CPU_BOOSTING_LEVEL_MEDIUM:
+       case CPU_BOOSTING_LEVEL_WEAK:
+               break;
+       case CPU_BOOSTING_LEVEL_NONE:
+               return;
+       default:
+               _E("[CPU-BOOSTING] Unknown boosting level");
+               return;
+       }
+
        attr = cpu_boosting_attr[cpu_boosting_level];
        if (input->client_input.flags & CPU_BOOSTING_RESET_ON_FORK) {
                _I("[CPU-BOOSTING] Turn on SCHED_RESET_ON_FORK flag");
@@ -575,8 +676,10 @@ static void cpu_boosting_set(struct cpu_boosting_input *input)
                }
 
                for (int i = 0; i < tid_count; i++) {
-                       if (tid_list[i] > 0)
-                               cpu_boosting_find_and_insert_info(tid_list[i], cpu_boosting_level, id);
+                       if (tid_list[i] <= 0)
+                               continue;
+
+                       cpu_boosting_find_and_insert_info(tid_list[i], cpu_boosting_level, id);
                }
        }
 
@@ -593,21 +696,22 @@ static void cpu_boosting_clear(struct cpu_boosting_input *input)
        int *tid_list = input->client_input.pid.tid;
 
        for (int i = 0; i < tid_count; i++) {
-               if (tid_list[i] > 0) {
-                       g_hash_table_remove(tid_table, &tid_list[i]);
+               if (tid_list[i] <= 0) {
+                       _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0",
+                                       tid_list[i]);
+                       continue;
+               }
 
-                       ret = sched_setattr(tid_list[i],
-                                       &cpu_boosting_attr[CPU_BOOSTING_LEVEL_NONE], 0);
-                       if (ret != RESOURCED_ERROR_NONE) {
-                               _E("[CPU-BOOSTING] Failed to clear boost cpu of (tid = %d)", tid_list[i]);
-                               fail_cnt++;
-                               continue;
-                       }
+               remove_cpu_boosting_info_in_tables(&tid_list[i]);
 
-                       success_cnt++;
+               ret = sched_setattr(tid_list[i],
+                               &cpu_boosting_attr[CPU_BOOSTING_LEVEL_NONE], 0);
+               if (ret != RESOURCED_ERROR_NONE) {
+                       _E("[CPU-BOOSTING] Failed to clear boost cpu of (tid = %d)", tid_list[i]);
+                       fail_cnt++;
+                       continue;
                }
-               else
-                       _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+               success_cnt++;
        }
 
        if (fail_cnt > 0)
@@ -635,22 +739,26 @@ static void cpu_boosting_get(struct cpu_boosting_input *input)
        }
 
        for (int i = 0; i < tid_count; i++) {
-               if (tid_list[i] > 0) {
-                       struct cpu_boosting_info *info = g_hash_table_lookup(tid_table, &tid_list[i]);
-                       if (info == NULL) {
-                               if (sched_getattr(tid_list[i], &attr, 0) < 0) {
-                                       _E("[CPU-BOOSTING] Failed to get boost cpu of (tid = %d)", tid_list[i]);
-                                       fail_cnt++;
-                                       continue;
-                               }
-                               output.level.tid_level[success_cnt++] = cpu_boosting_level_search(attr);
-                       }
-                       else
-                               output.level.tid_level[success_cnt++] = info->level;
-               }
-               else {
+               struct cpu_boosting_info *cpu_boosting_info = NULL;
+
+               if (tid_list[i] <= 0) {
                        fail_cnt++;
-                       _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+                       _W("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]);
+                       continue;
+               }
+
+               find_cpu_boosting_info_in_tables(&cpu_boosting_info, &tid_list[i]);
+               if (cpu_boosting_info == NULL) {
+                       if (sched_getattr(tid_list[i], &attr, 0) < 0) {
+                               fail_cnt++;
+                               continue;
+                       }
+
+                       output.level.tid_level[success_cnt] = cpu_boosting_level_search(attr);
+                       success_cnt++;
+               } else {
+                       output.level.tid_level[success_cnt] = cpu_boosting_info->level;
+                       success_cnt++;
                }
        }
        output.level.tid_count = success_cnt;
@@ -672,7 +780,7 @@ static void cpu_boosting_set_inheritance(struct cpu_boosting_input *input)
        pid_t source_tid;
        struct sched_attr attr;
        cpu_boosting_level_e boosting_level;
-       struct cpu_boosting_info *info;
+       struct cpu_boosting_info *cpu_boosting_info = NULL;
        struct cpu_boosting_input *input_dest;
 
        source_tid = input->client_input.pid.pid;
@@ -687,17 +795,21 @@ static void cpu_boosting_set_inheritance(struct cpu_boosting_input *input)
                goto destroy_input;
        }
 
-       info = g_hash_table_lookup(tid_table, &source_tid);
-       if (info == NULL) {
+       find_cpu_boosting_info_in_tables(&cpu_boosting_info, &source_tid);
+
+       /**
+        * This source thread is not boosted by resourced.
+        * Therefore, resourced needs to figure out cpu priority or nice value through the kernel.
+        */
+       if (cpu_boosting_info == NULL) {
                if (sched_getattr(source_tid, &attr, 0) < 0) {
                        _E("[CPU-BOOSTING] Failed to get boost cpu of (tid = %d)", source_tid);
                        goto destroy_input;
                }
-               else
-                       boosting_level = cpu_boosting_level_search(attr);
-       }
-       else
-               boosting_level = info->level;
+
+               boosting_level = cpu_boosting_level_search(attr);
+       } else
+               boosting_level = cpu_boosting_info->level;
 
 #ifdef CONFIG_DEBUG_CPU_BOOSTING
        int tid_count = input_dest->client_input.pid.tid_count;
@@ -1059,8 +1171,11 @@ static int cpu_boosting_init(void *data)
        if (ret != RESOURCED_ERROR_NONE)
                return ret;
 
-       tid_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free);
-       g_assert(tid_table);
+       for (int level = CPU_BOOSTING_LEVEL_STRONG; level < CPU_BOOSTING_LEVEL_END; level++) {
+               g_cpu_boosting_info_table[level] = g_hash_table_new_full(
+                               g_int_hash, g_int_equal, NULL, free_cpu_boosting_info);
+               g_assert(g_cpu_boosting_info_table[level]);
+       }
 
        dest_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                        cpu_boosting_destroy_request);
@@ -1076,7 +1191,8 @@ static int cpu_boosting_init(void *data)
 static int cpu_boosting_finalize(void *data)
 {
        cpu_boosting_thread_deactivate();
-       g_hash_table_destroy(tid_table);
+       for (int level = CPU_BOOSTING_LEVEL_STRONG; level < CPU_BOOSTING_LEVEL_END; level++)
+               g_hash_table_destroy(g_cpu_boosting_info_table[level]);
        g_hash_table_destroy(dest_table);
 
        unregister_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf);