cpu-boosting: add (un)register and get/set inherit 00/279500/6 submit/tizen/20220816.062425
authorUnsung Lee <unsung.lee@samsung.com>
Wed, 10 Aug 2022 09:01:03 +0000 (18:01 +0900)
committerUnsung Lee <unsung.lee@samsung.com>
Tue, 16 Aug 2022 04:23:01 +0000 (13:23 +0900)
Change-Id: I99fa6e6aba0ecd59b731b089245e63d4d3c156bd
Signed-off-by: Unsung Lee <unsung.lee@samsung.com>
src/common/cpu-common.h
src/resource-optimizer/cpu/cpu-boosting.c

index 3325300..bd549b8 100644 (file)
@@ -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 {
index d0c2ca1..b4d4ae5 100644 (file)
@@ -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;