#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;
(_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;
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)
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)
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");
}
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);
}
}
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)
}
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;
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;
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;
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);
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);