From 757cc4ff8f5cc6fab1ca333b90b09db691665e73 Mon Sep 17 00:00:00 2001 From: Unsung Lee Date: Wed, 10 Aug 2022 18:01:03 +0900 Subject: [PATCH] cpu-boosting: add (un)register and get/set inherit Change-Id: I99fa6e6aba0ecd59b731b089245e63d4d3c156bd Signed-off-by: Unsung Lee --- src/common/cpu-common.h | 1 + src/resource-optimizer/cpu/cpu-boosting.c | 291 +++++++++++++++++++++++++----- 2 files changed, 247 insertions(+), 45 deletions(-) diff --git a/src/common/cpu-common.h b/src/common/cpu-common.h index 3325300..bd549b8 100644 --- a/src/common/cpu-common.h +++ b/src/common/cpu-common.h @@ -51,6 +51,7 @@ struct cpu_boosting_input { cpu_boosting_input_t client_input; int sock; guint *gsource_id; + bool remove_input; }; struct cpu_sched_info { diff --git a/src/resource-optimizer/cpu/cpu-boosting.c b/src/resource-optimizer/cpu/cpu-boosting.c index d0c2ca1..b4d4ae5 100644 --- a/src/resource-optimizer/cpu/cpu-boosting.c +++ b/src/resource-optimizer/cpu/cpu-boosting.c @@ -21,7 +21,9 @@ #include "fd-handler.h" #include "proc-common.h" -static GHashTable *tid_table; /* cpu_boosting info per thread (tid, attr, gsource_id) hash table */ +static GHashTable *tid_table; /* key = tid, value = cpu_boosting info per thread (tid, attr, gsource_id) hash table */ +static GHashTable *dest_table; /* key = destiation process name, value = cpu_boosting_input */ + pthread_t cpu_boosting_thread; static struct sched_attr cpu_boosting_attr[CPU_BOOSTING_LEVEL_END]; static bool cpu_boosting_success[CPU_BOOSTING_LEVEL_END] = {false, }; @@ -29,8 +31,6 @@ static bool cpu_boosting_success[CPU_BOOSTING_LEVEL_END] = {false, }; GMainLoop *cpu_boosting_loop; GMainContext *cpu_boosting_context; -static void cpu_boosting_destroy_request(struct cpu_boosting_input *input); - #define SOCK_PATH "/run/.resourced.socket" #define CPU_BOOSTING_SET_REQUEST(_input, _command, _level, _timeout_msec, _pid) \ @@ -69,6 +69,11 @@ static int cpu_boosting_get_tids(pid_t pid, resource_pid_t *resource_pid) struct dirent *dirent; _cleanup_free_ char *buf = NULL; + if (pid <= 0) { + _E("[CPU-BOOSTING] Wrong pid = %d", pid); + return RESOURCED_ERROR_FAIL; + } + ret = asprintf(&buf, "/proc/%d/task", pid); if (ret < 0) { _E("[CPU-BOOSTING] Failed to allocate buf (dir = %s)", buf); @@ -109,14 +114,19 @@ static int cpu_boosting_get_tids(pid_t pid, resource_pid_t *resource_pid) return RESOURCED_ERROR_NONE; } -static void cpu_boosting_destroy_request(struct cpu_boosting_input *input) +static void cpu_boosting_destroy_request(gpointer data) { + struct cpu_boosting_input *input = (struct cpu_boosting_input *)data; + if (input == NULL) return; if (input->client_input.pid.tid) free(input->client_input.pid.tid); + if (input->client_input.dest) + free((void *)input->client_input.dest); + if (input->gsource_id) g_free(input->gsource_id); @@ -230,11 +240,9 @@ static void cpu_boosting_send_reply(int sock, cpu_boosting_output_t output) { int byte; - if (sock == 0) - return; - else if (sock < 0) { + if (sock < 0) { _E("[CPU-BOOSTING] socket cannot be negative"); - return; + goto remove_output; } if (output.success) { @@ -243,7 +251,7 @@ static void cpu_boosting_send_reply(int sock, cpu_boosting_output_t output) if (byte != sizeof(output)) { _E("[CPU-BOOSTING] Server output size is %u, but sent size is %d", (unsigned int)sizeof(output), byte); - return; + goto remove_output; } /* Check body size */ @@ -252,9 +260,8 @@ static void cpu_boosting_send_reply(int sock, cpu_boosting_output_t output) if (byte != output.level.tid_count * sizeof(int)) { _E("[CPU-BOOSTING] Server output size is %u, but sent size is %d", output.level.tid_count * (unsigned int)sizeof(int), byte); - return; + goto remove_output; } - } else { /* Send a header */ @@ -262,10 +269,11 @@ static void cpu_boosting_send_reply(int sock, cpu_boosting_output_t output) if (byte != sizeof(output.success)) { _E("[CPU-BOOSTING] Server output size is %u, but sent size is %d", (unsigned int)sizeof(output.success), byte); - return; + goto remove_output; } } +remove_output: if (output.level.tid_level) free(output.level.tid_level); } @@ -294,10 +302,13 @@ static int cpu_boosting_enqueue_by_socket(int sock, struct cpu_boosting_input ** _E("[CPU-BOOSTING] client input size is %u, but received size is %d", (unsigned int)sizeof(input->client_input), byte); input->client_input.pid.tid = NULL; + input->client_input.dest = NULL; } goto destroy_input; } + input->client_input.pid.tid = NULL; + input->client_input.dest = NULL; if (input->client_input.command == CPU_BOOSTING_COMMAND_CLEAR || input->client_input.command == CPU_BOOSTING_COMMAND_SET) { @@ -318,11 +329,10 @@ static int cpu_boosting_enqueue_by_socket(int sock, struct cpu_boosting_input ** } /* Check body size */ - input->client_input.pid.tid = NULL; - if (input->client_input.body_size > 0 && + if (input->client_input.body_len > 0 && input->client_input.pid.tid_count > 0) { int *tid_list; - int body_size = input->client_input.body_size; + int body_len = input->client_input.body_len; int tid_count = input->client_input.pid.tid_count; tid_list = (int *)calloc(tid_count, sizeof(int)); @@ -335,40 +345,77 @@ static int cpu_boosting_enqueue_by_socket(int sock, struct cpu_boosting_input ** input->client_input.pid.tid = tid_list; /* Get a body from the client */ - byte = recv(sock, (void *)tid_list, body_size, 0); - if (byte != body_size) { + byte = recv(sock, (void *)tid_list, body_len, 0); + if (byte != body_len) { ret = RESOURCED_ERROR_FAIL; if (byte < 0) { _E("[CPU-BOOSTING] error is based on %m"); } else if (byte > 0) _E("[CPU-BOOSTING] client input size is %d, but received size is %d", - body_size, byte); + body_len, byte); goto destroy_input; } + } + else if (input->client_input.body_len == 0) { + switch (input->client_input.command) { + case CPU_BOOSTING_COMMAND_SET: + case CPU_BOOSTING_COMMAND_CLEAR: + case CPU_BOOSTING_COMMAND_GET: + case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION: + ret = cpu_boosting_get_tids(input->client_input.pid.pid, &input->client_input.pid); + if (ret != RESOURCED_ERROR_NONE) + goto destroy_input; - /* - * TODO: Checking whether Thread ID is valid or not - * - * for (int i = 0; i < tid_count; i++) { - * if (tid_list[i] <= 0) - * goto destroy_input; - }*/ - } - else if (input->client_input.body_size == 0 && - input->client_input.pid.pid > 0) { - ret = cpu_boosting_get_tids(input->client_input.pid.pid, &input->client_input.pid); - if (ret != RESOURCED_ERROR_NONE) - goto destroy_input; + break; + default: + //do nothing + break; + } } else { _E("[CPU-BOOSTING] Unknown header format"); + ret = RESOURCED_ERROR_FAIL; goto destroy_input; } if (input->client_input.command == CPU_BOOSTING_COMMAND_GET) input->sock = sock; /* For a reply */ + else if (input->client_input.command == CPU_BOOSTING_COMMAND_REGISTER_DESTINATION || + input->client_input.command == CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION || + input->client_input.command == CPU_BOOSTING_COMMAND_SET_INHERITANCE || + input->client_input.command == CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE) { + char *dest; + + if (input->client_input.dest_len <= 0) { + _E("[CPU-BOOSTING] Wrong destination name"); + ret = RESOURCED_ERROR_FAIL; + goto destroy_input; + } + + dest = (char *)calloc(input->client_input.dest_len, sizeof(char)); + if (dest == NULL) { + _E("[CPU-BOOSTING] Failed to allocate memory"); + ret = RESOURCED_ERROR_OUT_OF_MEMORY; + goto destroy_input; + } + else + input->client_input.dest = dest; + + byte = recv(sock, (void *)dest, input->client_input.dest_len, 0); + if (byte != input->client_input.dest_len) { + ret = RESOURCED_ERROR_FAIL; + if (byte < 0) { + _E("[CPU-BOOSTING] error is based on %m"); + } + else if (byte > 0) + _E("[CPU-BOOSTING] client input size is %d, but received size is %d", + input->client_input.dest_len, byte); + + goto destroy_input; + } + } return RESOURCED_ERROR_NONE; @@ -449,13 +496,14 @@ static gboolean cpu_boosting_timeout(gpointer data) _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]); } - cpu_boosting_destroy_request(input); + if (input->remove_input) + cpu_boosting_destroy_request(input); timer_out: return G_SOURCE_REMOVE; } -static void cpu_boosting_find_and_insert_attr(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 level, guint id) { struct cpu_boosting_info *info = g_hash_table_lookup(tid_table, &tid); if (info == NULL) { @@ -475,6 +523,7 @@ static void cpu_boosting_find_and_insert_attr(pid_t tid, cpu_boosting_level_e le static void cpu_boosting_set(struct cpu_boosting_input *input) { + guint id = 0; int fail_cnt = 0; int success_cnt = 0; struct sched_attr attr; @@ -507,7 +556,6 @@ static void cpu_boosting_set(struct cpu_boosting_input *input) _E("[CPU-BOOSTING] Boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt); if (success_cnt > 0) { - guint id; /* * If timeout value is larger than 0 and at least one boosting succeed, * then set the timer to restore @@ -523,14 +571,15 @@ static void cpu_boosting_set(struct cpu_boosting_input *input) id = *(input->gsource_id); } - else - id = 0; /* No timer source */ for (int i = 0; i < tid_count; i++) { if (tid_list[i] > 0) - cpu_boosting_find_and_insert_attr(tid_list[i], cpu_boosting_level, id); + cpu_boosting_find_and_insert_info(tid_list[i], cpu_boosting_level, id); } } + + if (id == 0 && input->remove_input) + cpu_boosting_destroy_request(input); } static void cpu_boosting_clear(struct cpu_boosting_input *input) @@ -562,7 +611,8 @@ static void cpu_boosting_clear(struct cpu_boosting_input *input) if (fail_cnt > 0) _E("[CPU-BOOSTING] Boosting success ratio = %d/%d", success_cnt, fail_cnt + success_cnt); - cpu_boosting_destroy_request(input); + if (input->remove_input) + cpu_boosting_destroy_request(input); } static void cpu_boosting_get(struct cpu_boosting_input *input) @@ -615,6 +665,145 @@ output_update: cpu_boosting_destroy_request(input); } +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_input *input_dest; + + source_tid = input->client_input.pid.pid; + if (source_tid <= 0) { + _E("[CPU-BOOSTING] source tid should be larger than 0"); + goto destroy_input; + } + + input_dest = g_hash_table_lookup(dest_table, input->client_input.dest); + if (input_dest == NULL) { + _E("[CPU-BOOSTING] %s is not registered before", input->client_input.dest); + goto destroy_input; + } + + info = g_hash_table_lookup(tid_table, &source_tid); + if (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; + +#ifdef CONFIG_DEBUG_CPU_BOOSTING + int tid_count = input_dest->client_input.pid.tid_count; + int *tid_list = input_dest->client_input.pid.tid; + + for (int i = 0; i < tid_count; i++) { + if (tid_list[i] > 0) + _D("[CPU-BOOSTING] tid = %d", tid_list[i]); + else + _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]); + } + _D("[CPU-BOOSTING] %s is boost set", input_dest->client_input.dest); +#endif + + input_dest->client_input.timeout_msec = input->client_input.timeout_msec; + input_dest->client_input.level = boosting_level; + cpu_boosting_set(input_dest); + +destroy_input: + cpu_boosting_destroy_request(input); +} + +static void cpu_boosting_clear_inheritance(struct cpu_boosting_input *input) +{ + struct cpu_boosting_input *input_dest = g_hash_table_lookup(dest_table, input->client_input.dest); + if (input_dest == NULL) { + _E("[CPU-BOOSTING] %s is not registered before", input->client_input.dest); + goto destroy_input; + } + +#ifdef CONFIG_DEBUG_CPU_BOOSTING + int tid_count = input_dest->client_input.pid.tid_count; + int *tid_list = input_dest->client_input.pid.tid; + + for (int i = 0; i < tid_count; i++) { + if (tid_list[i] > 0) + _D("[CPU-BOOSTING] tid = %d", tid_list[i]); + else + _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]); + } + _D("[CPU-BOOSTING] %s is boost cleared", input_dest->client_input.dest); +#endif + + cpu_boosting_clear(input_dest); + +destroy_input: + cpu_boosting_destroy_request(input); +} + +static void cpu_boosting_register_destination(struct cpu_boosting_input *input) +{ + if (input->client_input.dest == NULL) { + _E("[CPU-BOOSTING] Boosting target name cannot be NULL"); + return; + } + +#ifdef CONFIG_DEBUG_CPU_BOOSTING + int tid_count = input->client_input.pid.tid_count; + int *tid_list = input->client_input.pid.tid; + + for (int i = 0; i < tid_count; i++) { + if (tid_list[i] > 0) + _D("[CPU-BOOSTING] tid = %d", tid_list[i]); + else + _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]); + } + _D("[CPU-BOOSTING] %s is inserted", input->client_input.dest); +#endif + + input->remove_input = false; + g_hash_table_insert(dest_table, (gpointer)input->client_input.dest, input); +} + +static void cpu_boosting_unregister_destination(struct cpu_boosting_input *input) +{ + if (input->client_input.dest == NULL) { + _E("[CPU-BOOSTING] Boosting target name cannot be NULL"); + return; + } + +#ifdef CONFIG_DEBUG_CPU_BOOSTING + struct cpu_boosting_input *input_dest = g_hash_table_lookup(dest_table, input->client_input.dest); + if (input_dest == NULL) { + _E("[CPU-BOOSTING] %s does not registered before", input->client_input.dest); + return; + } + + int tid_count = input_dest->client_input.pid.tid_count; + int *tid_list = input_dest->client_input.pid.tid; + + for (int i = 0; i < tid_count; i++) { + if (tid_list[i] > 0) + _D("[CPU-BOOSTING] tid = %d", tid_list[i]); + else + _E("[CPU-BOOSTING] Thread (id = %d) should be larger than 0", tid_list[i]); + } +#endif + +#ifdef CONFIG_DEBUG_CPU_BOOSTING + gboolean ret = g_hash_table_remove(dest_table, input->client_input.dest); + _D("[CPU-BOOSTING] %s is %sremoved", input->client_input.dest, + ret ? "" : "already "); +#else + g_hash_table_remove(dest_table, input->client_input.dest); +#endif + cpu_boosting_destroy_request(input); +} + static int cpu_boosting_init_socket(void) { /* Create a server socket */ @@ -678,15 +867,28 @@ static void cpu_boosting_handle_command(struct cpu_boosting_input *input) */ switch (input->client_input.command) { case CPU_BOOSTING_COMMAND_SET: + input->remove_input = true; cpu_boosting_set(input); break; case CPU_BOOSTING_COMMAND_CLEAR: + input->remove_input = true; cpu_boosting_clear(input); break; case CPU_BOOSTING_COMMAND_GET: - cpu_boosting_get(input); break; + case CPU_BOOSTING_COMMAND_SET_INHERITANCE: + cpu_boosting_set_inheritance(input); + break; + case CPU_BOOSTING_COMMAND_CLEAR_INHERITANCE: + cpu_boosting_clear_inheritance(input); + break; + case CPU_BOOSTING_COMMAND_REGISTER_DESTINATION: + cpu_boosting_register_destination(input); + break; + case CPU_BOOSTING_COMMAND_UNREGISTER_DESTINATION: + cpu_boosting_unregister_destination(input); + break; case CPU_BOOSTING_COMMAND_NONE: default: _E("[CPU-BOOSTING] Unknown cpu boosting (command = %d)", input->client_input.command); @@ -730,12 +932,6 @@ static bool cpu_boosting_recv_from_client(int fd, void *data) goto remove_handler; } - if (input->client_input.pid.tid_count == 0) { - _E("[CPU-BOOSTING] The number of tids should be larger than 0"); - cpu_boosting_destroy_request(input); - goto remove_handler; - } - cpu_boosting_handle_command(input); return G_SOURCE_CONTINUE; @@ -862,6 +1058,10 @@ static int cpu_boosting_init(void *data) tid_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free); g_assert(tid_table); + dest_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + cpu_boosting_destroy_request); + g_assert(dest_table); + /* For the conf-based client */ register_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf); @@ -873,6 +1073,7 @@ static int cpu_boosting_finalize(void *data) { cpu_boosting_thread_deactivate(); g_hash_table_destroy(tid_table); + g_hash_table_destroy(dest_table); unregister_notifier(RESOURCED_NOTIFIER_BOOSTING_RESOURCE, cpu_boosting_recv_from_conf); return RESOURCED_ERROR_NONE; -- 2.7.4