From a00958770bd6bc5a0647e8dda7e7511012d03d39 Mon Sep 17 00:00:00 2001 From: Unsung Lee Date: Thu, 10 Aug 2023 16:44:13 +0900 Subject: [PATCH] cpu-boosting: Split a cpu boosting info table into three tables 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 --- src/common/conf/cpu-common.h | 1 + src/resource-optimizer/cpu/cpu-boosting.c | 246 ++++++++++++++++++++++-------- 2 files changed, 182 insertions(+), 65 deletions(-) diff --git a/src/common/conf/cpu-common.h b/src/common/conf/cpu-common.h index 34e5ff8..74e872f 100644 --- a/src/common/conf/cpu-common.h +++ b/src/common/conf/cpu-common.h @@ -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 { diff --git a/src/resource-optimizer/cpu/cpu-boosting.c b/src/resource-optimizer/cpu/cpu-boosting.c index 0588cd2..2783ea0 100644 --- a/src/resource-optimizer/cpu/cpu-boosting.c +++ b/src/resource-optimizer/cpu/cpu-boosting.c @@ -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); -- 2.7.4