From e5b2952d3db58e339221f0e3161a2c1c34e45167 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Sun, 3 Apr 2022 23:14:22 +0900 Subject: [PATCH 01/16] resource: process-group: Add aggregated attributes for accounting stats To provide aggregated accounting information about the process group which includes target process and its child at a driver level, the structure managing the current process group is changed from list to hash, and it is preserved until root target is changed or a prcess in a group is terminated to maintain previous stats. Thus, the clients can retrieved aggregated accounting stats without create the individual process driver. Newly added attributes are as follows: - PROCESS_GROUP_ATTR_CPU_UTIL - PROCESS_GROUP_ATTR_DISK_READ_BPS - PROCESS_GROUP_ATTR_DISK_WRITE_BPS - PROCESS_GROUP_ATTR_MEM_VIRT - PROCESS_GROUP_ATTR_MEM_RSS Change-Id: I967da6110fb8568383c2ba096d599f51ce8e54e2 Signed-off-by: Dongwoo Lee --- lib/resource-monitor/resource-monitor.h | 5 + src/resource/resource-process-group.c | 381 ++++++++++++++++++++++++++------ 2 files changed, 322 insertions(+), 64 deletions(-) diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h index 3b1b6cb..515ec10 100644 --- a/lib/resource-monitor/resource-monitor.h +++ b/lib/resource-monitor/resource-monitor.h @@ -127,6 +127,11 @@ extern "C" { /* Process List Resource */ #define PROCESS_GROUP_ATTR_PID_LIST BIT(0) /* DATA_TYPE_ARRAY(INT) */ #define PROCESS_GROUP_ATTR_COMM_LIST BIT(1) /* DATA_TYPE_ARRAY(STRING) */ +#define PROCESS_GROUP_ATTR_CPU_UTIL BIT(2) /* DATA_TYPE_DOUBLE */ +#define PROCESS_GROUP_ATTR_DISK_READ_BPS BIT(3) /* DATA_TYPE_UINT */ +#define PROCESS_GROUP_ATTR_DISK_WRITE_BPS BIT(4) /* DATA_TYPE_UINT */ +#define PROCESS_GROUP_ATTR_MEM_VIRT BIT(5) /* DATA_TYPE_UINT64 */ +#define PROCESS_GROUP_ATTR_MEM_RSS BIT(6) /* DATA_TYPE_UINT64 */ #define PROCESS_GROUP_CTRL_ROOT_PID BIT(0) diff --git a/src/resource/resource-process-group.c b/src/resource/resource-process-group.c index 31bb359..959ef43 100644 --- a/src/resource/resource-process-group.c +++ b/src/resource/resource-process-group.c @@ -26,15 +26,28 @@ #define PROC_DIR_PATH "/proc/" struct process_info_node { + pid_t tgid; + struct taskstats *prev; struct taskstats *stats; struct process_info_node *parent; }; struct process_group_context { - struct taskstats root_stats; - GPtrArray *pi_list; + pid_t pid; + GHashTable *pi_map; + struct { + double cpu_util; + u_int64_t mem_rss; + u_int64_t mem_virt; + u_int32_t disk_rbps; + u_int32_t disk_wbps; + } info; + u_int64_t prev_total_time; }; +static u_int64_t total_memory; +static long jiffy; + static int process_group_get_pid_list(const struct resource *res, const struct resource_attribute *attr, void *data) @@ -42,30 +55,32 @@ static int process_group_get_pid_list(const struct resource *res, struct process_group_context *ctx; struct array_value *list = data; struct process_info_node *node; + GHashTableIter iter; + gpointer key, value; int *data_array; - int i; + int i = 0; if (!res || !res->priv || !attr || !data) return -EINVAL; ctx = res->priv; - if (!ctx->pi_list) + if (!ctx->pi_map) return -EINVAL; if (list->data) free(list->data); - data_array = list->data = malloc(sizeof(int) * ctx->pi_list->len); + list->type = DATA_TYPE_INT; + list->length = g_hash_table_size(ctx->pi_map); + data_array = list->data = malloc(sizeof(int) * list->length); if (!data_array) return -ENOMEM; - list->type = DATA_TYPE_INT; - list->length = ctx->pi_list->len; - - for (i = 0; i < list->length; i++) { - node = g_ptr_array_index(ctx->pi_list, i); - data_array[i] = node->stats->ac_pid; + g_hash_table_iter_init(&iter, ctx->pi_map); + while (g_hash_table_iter_next(&iter, &key, &value)) { + node = (struct process_info_node *)value; + data_array[i++] = node->tgid; } return 0; @@ -78,15 +93,17 @@ static int process_group_get_comm_list(const struct resource *res, struct process_group_context *ctx; struct array_value *list = data; struct process_info_node *node; + GHashTableIter iter; + gpointer key, value; char **data_array; - int i; + int i = 0; if (!res || !res->priv || !attr || !data) return -EINVAL; ctx = res->priv; - if (!ctx->pi_list) + if (!ctx->pi_map) return -EINVAL; if (list->data) { @@ -96,16 +113,17 @@ static int process_group_get_comm_list(const struct resource *res, free(data_array); } + list->type = DATA_TYPE_STRING; + list->length = g_hash_table_size(ctx->pi_map); + /* last item will be null for boundary check */ - data_array = list->data = calloc(ctx->pi_list->len + 1, sizeof(char *)); + data_array = list->data = calloc(list->length + 1, sizeof(char *)); if (!data_array) return -ENOMEM; - list->type = DATA_TYPE_STRING; - list->length = ctx->pi_list->len; - - for (i = 0; i < list->length; i++) { - node = g_ptr_array_index(ctx->pi_list, i); + g_hash_table_iter_init(&iter, ctx->pi_map); + for (i = 0; g_hash_table_iter_next(&iter, &key, &value); i++) { + node = (struct process_info_node *)value; data_array[i] = strdup(node->stats->ac_comm); if (!data_array[i]) { while (i > 0) @@ -119,6 +137,87 @@ static int process_group_get_comm_list(const struct resource *res, return 0; } +static int process_group_get_cpu_util(const struct resource *res, + const struct resource_attribute *attr, + void *data) +{ + struct process_group_context *ctx; + double *util = (double *)data; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->pi_map || ctx->pid < 0) + return -EINVAL; + + *util = ctx->info.cpu_util; + + return 0; +} + +static int process_group_get_mem(const struct resource *res, + const struct resource_attribute *attr, + void *data) +{ + struct process_group_context *ctx; + u_int64_t *mem = (u_int64_t *)data; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->pi_map || ctx->pid < 0) + return -EINVAL; + + switch (attr->id) { + case PROCESS_GROUP_ATTR_MEM_RSS: + { + *mem = ctx->info.mem_rss; + break; + } + case PROCESS_GROUP_ATTR_MEM_VIRT: + { + *mem = ctx->info.mem_virt; + break; + } + default: + return -EINVAL; + } + + return 0; +} + +static int process_group_get_disk_bps(const struct resource *res, + const struct resource_attribute *attr, + void *data) +{ + struct process_group_context *ctx; + u_int32_t *bps = (u_int32_t *)data; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->pi_map || ctx->pid < 0) + return -EINVAL; + + switch (attr->id) { + case PROCESS_GROUP_ATTR_DISK_READ_BPS: + *bps = ctx->info.disk_rbps; + break; + case PROCESS_GROUP_ATTR_DISK_WRITE_BPS: + *bps = ctx->info.disk_wbps; + break; + default: + return -EINVAL; + } + return 0; +} + static const struct resource_attribute process_group_attrs[] = { { .name = "PROCESS_GROUP_ATTR_PID_LIST", @@ -138,12 +237,54 @@ static const struct resource_attribute process_group_attrs[] = { .is_supported = resource_attr_supported_always, }, }, + { + .name = "PROCESS_GROUP_ATTR_CPU_UTIL", + .id = PROCESS_GROUP_ATTR_CPU_UTIL, + .type = DATA_TYPE_DOUBLE, + .ops = { + .get = process_group_get_cpu_util, + .is_supported = resource_attr_supported_always, + }, + }, { + .name = "PROCESS_GROUP_ATTR_DISK_READ_BPS", + .id = PROCESS_GROUP_ATTR_DISK_READ_BPS, + .type = DATA_TYPE_UINT, + .ops = { + .get = process_group_get_disk_bps, + .is_supported = resource_attr_supported_always, + }, + }, { + .name = "PROCESS_GROUP_ATTR_DISK_WRITE_BPS", + .id = PROCESS_GROUP_ATTR_DISK_WRITE_BPS, + .type = DATA_TYPE_UINT, + .ops = { + .get = process_group_get_disk_bps, + .is_supported = resource_attr_supported_always, + }, + }, { + .name = "PROCESS_GROUP_ATTR_MEM_VIRT", + .id = PROCESS_GROUP_ATTR_MEM_VIRT, + .type = DATA_TYPE_UINT64, + .ops = { + .get = process_group_get_mem, + .is_supported = resource_attr_supported_always, + }, + }, { + .name = "PROCESS_GROUP_ATTR_MEM_RSS", + .id = PROCESS_GROUP_ATTR_MEM_RSS, + .type = DATA_TYPE_UINT64, + .ops = { + .get = process_group_get_mem, + .is_supported = resource_attr_supported_always, + }, + }, }; static int process_group_setup_root_pid(const struct resource *res, const struct resource_control *ctrl, const void *data) { + struct taskstats stats; struct process_group_context *ctx; int target_pid; int ret; @@ -156,17 +297,19 @@ static int process_group_setup_root_pid(const struct resource *res, target_pid = (int)(intptr_t)data; if (target_pid < 0) { - ctx->root_stats.ac_pid = ctx->root_stats.ac_ppid = -1; + ctx->pid = -1; return 0; } - ret = kernel_get_process_taskstats(&ctx->root_stats, TASKSTATS_CMD_ATTR_PID, target_pid); + ret = kernel_get_process_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, target_pid); if (ret < 0) { _E("target process pid is not valid"); - ctx->root_stats.ac_pid = ctx->root_stats.ac_ppid = -1; + ctx->pid = -1; return ret; } + ctx->pid = stats.ac_pid; + return 0; } @@ -180,29 +323,119 @@ static const struct resource_control process_group_ctrls[] = { }, }; +#define saturatingSub(a, b) (a > b ? a - b : 0) + static void free_node(void *_node) { struct process_info_node *node = _node; + if (node->prev) + free(node->prev); if (node->stats) free(node->stats); - free(node); } +static u_int64_t get_total_cpu_time(void) +{ + struct cpu_stat cpu_stat; + u_int64_t total_time; + int ret; + + ret = kernel_get_total_cpu_stat(&cpu_stat); + if (ret < 0) { + _E("failed to get cpu stat"); + return 0; + }; + + total_time = cpu_stat.user + cpu_stat.system + cpu_stat.nice + cpu_stat.idle; + total_time += cpu_stat.wait + cpu_stat.hard_irq + cpu_stat.soft_irq; + + return total_time; +} + +static int update_aggr_taskstats(struct process_group_context *ctx) +{ + struct process_info_node *node; + struct taskstats *prev, *curr; + u_int64_t total_time; + int online, nproc; + double cpu_period; + GHashTableIter iter; + gpointer key, value; + pid_t pid; + int ret; + + memset(&ctx->info, 0, sizeof(ctx->info)); + + nproc = g_hash_table_size(ctx->pi_map); + online = kernel_get_online_cpu_num(); + total_time = get_total_cpu_time(); + + cpu_period = (double)saturatingSub(total_time, ctx->prev_total_time) / online; + + ctx->prev_total_time = total_time; + + g_hash_table_iter_init(&iter, ctx->pi_map); + while (g_hash_table_iter_next(&iter, &key, &value)) { + node = (struct process_info_node *)value; + + pid = node->tgid; + prev = node->prev; + + curr = calloc(1, sizeof(struct taskstats)); + if (!curr) + return -ENOMEM; + + ret = kernel_get_thread_group_taskstats(curr, pid, true); + if (ret < 0) { + free(curr); + g_hash_table_iter_remove(&iter); + continue; + } + + if (!prev) { + node->stats = node->prev = curr; + continue; + } + + if (cpu_period >= 1E-6) { + double util; + + util = (double)(curr->ac_utime + curr->ac_stime); + util -= (double)(prev->ac_utime + prev->ac_stime); + util *= (jiffy / (cpu_period * 10000.0)); + util = min(util, 100.0); + + ctx->info.cpu_util += (util / nproc); + } + + ctx->info.mem_virt += (curr->virtmem * 1024 * 1024) / curr->ac_stime; + ctx->info.mem_rss += (curr->coremem * 1024 * 1024) / curr->ac_stime; + ctx->info.disk_rbps += ((curr->read_bytes - prev->read_bytes) * 1000000) + / (curr->ac_etime - prev->ac_etime); + ctx->info.disk_wbps += ((curr->write_bytes - prev->write_bytes) * 1000000) + / (curr->ac_etime - prev->ac_etime); + free(prev); + node->prev = curr; + node->stats = curr; + } + + return 0; +} + static int process_group_prepare_update(struct resource *res) { struct process_group_context *ctx; struct process_info_node *pnode, *parent_pnode; struct dirent *task_entry; struct taskstats *stats; - GPtrArray *pi_list; GHashTableIter iter; gpointer key, value; GHashTable *process_hash; DIR *task_dir; int ret = 0; - pid_t pid; + pid_t tgid; if (!res || !res->priv) return -EINVAL; @@ -229,9 +462,9 @@ static int process_group_prepare_update(struct resource *res) if (name[0] < '0' || name[0] > '9') continue; - pid = atoi(name); + tgid = atoi(name); - if (pid == 2) + if (tgid == 2) continue; stats = malloc(sizeof(struct taskstats)); @@ -240,7 +473,7 @@ static int process_group_prepare_update(struct resource *res) goto out_free_hash; } - ret = kernel_get_process_taskstats(stats, TASKSTATS_CMD_ATTR_PID, pid); + ret = kernel_get_process_taskstats(stats, TASKSTATS_CMD_ATTR_PID, tgid); if (ret < 0) { free(stats); continue; /* process might be terminated */ @@ -260,6 +493,7 @@ static int process_group_prepare_update(struct resource *res) } pnode->stats = stats; + pnode->tgid = tgid; if (g_hash_table_contains(process_hash, (gpointer)&pnode->stats->ac_ppid)) { parent_pnode = g_hash_table_lookup(process_hash, @@ -268,57 +502,62 @@ static int process_group_prepare_update(struct resource *res) pnode->parent = parent_pnode; } - g_hash_table_insert(process_hash, (gpointer)&pnode->stats->ac_pid, (gpointer)pnode); + g_hash_table_insert(process_hash, (gpointer)&pnode->tgid, (gpointer)pnode); } - pi_list = g_ptr_array_new_full(100, free_node); - if (!pi_list) { - ret = -ENOMEM; - goto out_free_hash; + g_hash_table_iter_init(&iter, ctx->pi_map); + while (g_hash_table_iter_next(&iter, &key, &value)) { + pnode = (struct process_info_node *)value; + if (!g_hash_table_contains(process_hash, key)) { + pnode = (struct process_info_node *)value; + + g_hash_table_iter_remove(&iter); + } } - if (ctx->root_stats.ac_pid < 0) { + if (ctx->pid < 0) { /* just add all processes into array if parent pid is negative */ g_hash_table_iter_init(&iter, process_hash); while (g_hash_table_iter_next(&iter, &key, &value)) { - pnode = (struct process_info_node *)value; + if (!g_hash_table_contains(ctx->pi_map, key)) { + pnode = (struct process_info_node *)value; - g_ptr_array_add(pi_list, pnode); - g_hash_table_iter_steal(&iter); + g_hash_table_insert(ctx->pi_map, key, pnode); + g_hash_table_iter_steal(&iter); + } } } else { g_hash_table_iter_init(&iter, process_hash); while (g_hash_table_iter_next(&iter, &key, &value)) { pnode = (struct process_info_node *)value; - if (ctx->root_stats.ac_pid == pnode->stats->ac_pid - || ctx->root_stats.ac_pid == pnode->stats->ac_ppid) { - - g_ptr_array_add(pi_list, pnode); - g_hash_table_iter_steal(&iter); - continue; - } - - parent_pnode = pnode->parent; - while (parent_pnode != NULL) { - if (parent_pnode->stats->ac_ppid == ctx->root_stats.ac_pid) { - g_ptr_array_add(pi_list, pnode); + if (!g_hash_table_contains(ctx->pi_map, key)) { + if (ctx->pid == pnode->stats->ac_pid + || ctx->pid == pnode->stats->ac_ppid) { + g_hash_table_insert(ctx->pi_map, key, pnode); g_hash_table_iter_steal(&iter); - break; + continue; + } + + parent_pnode = pnode->parent; + while (parent_pnode != NULL) { + if (parent_pnode->stats->ac_ppid == ctx->pid) { + g_hash_table_insert(ctx->pi_map, key, pnode); + g_hash_table_iter_steal(&iter); + break; + } + parent_pnode = parent_pnode->parent; } - parent_pnode = parent_pnode->parent; } } - } - if (ctx->pi_list) { - /* remove previous list */ - g_ptr_array_free(ctx->pi_list, true); - ctx->pi_list = NULL; + ret = update_aggr_taskstats(ctx); + if (ret < 0) { + ret = -EINVAL; + goto out_free_hash; + } } - ctx->pi_list = pi_list; - ret = 0; out_free_hash: g_hash_table_destroy(process_hash); @@ -331,13 +570,28 @@ out_close: static int process_group_init(struct resource *res) { struct process_group_context *ctx; + int ret; + + if (jiffy == 0) { + /* get system USER_HZ at once */ + jiffy = sysconf(_SC_CLK_TCK); + if (jiffy < 0) + return -EINVAL; + } + + if (total_memory == 0) { + /* get system total memory once at init*/ + ret = kernel_get_memory_total(&total_memory); + if (ret < 0) + return -EINVAL; + } ctx = malloc(sizeof(struct process_group_context)); if (!ctx) return -ENOMEM; - ctx->root_stats.ac_pid = ctx->root_stats.ac_ppid = -1; - ctx->pi_list = NULL; + ctx->pid = -1; + ctx->pi_map = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free_node); res->priv = ctx; @@ -351,10 +605,9 @@ static void process_group_exit(struct resource *res) if (res && res->priv) { ctx = res->priv; - if (ctx->pi_list) { - /* remove previous list */ - g_ptr_array_free(ctx->pi_list, true); - ctx->pi_list = NULL; + if (ctx->pi_map) { + g_hash_table_destroy(ctx->pi_map); + ctx->pi_map = NULL; } free(res->priv); -- 2.7.4 From 71da9223e76231608dc614f0a46eeb56d0d7ef3d Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 11 Apr 2022 20:28:37 +0900 Subject: [PATCH 02/16] resource: process-group: Fix unnecessary assignment and meaningless code Change-Id: I600fc27afa7ecb95853bc492bd997ee8d99d1e9a Signed-off-by: Dongwoo Lee --- src/resource/resource-process-group.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/resource/resource-process-group.c b/src/resource/resource-process-group.c index 959ef43..caab3a0 100644 --- a/src/resource/resource-process-group.c +++ b/src/resource/resource-process-group.c @@ -387,7 +387,7 @@ static int update_aggr_taskstats(struct process_group_context *ctx) if (!curr) return -ENOMEM; - ret = kernel_get_thread_group_taskstats(curr, pid, true); + ret = kernel_get_thread_group_taskstats(curr, pid, false); if (ret < 0) { free(curr); g_hash_table_iter_remove(&iter); @@ -395,7 +395,7 @@ static int update_aggr_taskstats(struct process_group_context *ctx) } if (!prev) { - node->stats = node->prev = curr; + node->prev = curr; continue; } @@ -418,7 +418,6 @@ static int update_aggr_taskstats(struct process_group_context *ctx) / (curr->ac_etime - prev->ac_etime); free(prev); node->prev = curr; - node->stats = curr; } return 0; @@ -506,14 +505,9 @@ static int process_group_prepare_update(struct resource *res) } g_hash_table_iter_init(&iter, ctx->pi_map); - while (g_hash_table_iter_next(&iter, &key, &value)) { - pnode = (struct process_info_node *)value; - if (!g_hash_table_contains(process_hash, key)) { - pnode = (struct process_info_node *)value; - + while (g_hash_table_iter_next(&iter, &key, &value)) + if (!g_hash_table_contains(process_hash, key)) g_hash_table_iter_remove(&iter); - } - } if (ctx->pid < 0) { /* just add all processes into array if parent pid is negative */ -- 2.7.4 From a193fd0fb47a37e666c38f8eec46ebad594f5143 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 8 Apr 2022 12:04:08 +0900 Subject: [PATCH 03/16] monitor: resource: Add timestamp support To provide timeline information of resource update, now provides timestamp as start and end time of update. It is included in resource json as "res_ts" with "start" and "end" object, and it also can be retrieved with following new libpass function: - pass_resource_monitor_get_resource_timestamp() Change-Id: Iad2cf8bb1d1100f4ded44ce5e19aeb119c65575e Signed-off-by: Dongwoo Lee --- include/util/request.h | 1 + include/util/resource.h | 15 ++++++++++++- lib/resource-monitor/resource-monitor.c | 32 ++++++++++++++++++++++++++++ lib/resource-monitor/resource-monitor.h | 11 ++++++++++ src/monitor/request-handler.c | 37 +++++++++++++++++++++++++++++++++ src/util/resource.c | 17 +++++++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/include/util/request.h b/include/util/request.h index fcee614..44d2047 100644 --- a/include/util/request.h +++ b/include/util/request.h @@ -44,6 +44,7 @@ enum { REQUEST_GET_VALUE_DOUBLE, REQUEST_GET_VALUE_STRING, REQUEST_GET_VALUE_ARRAY, + REQUEST_GET_RESOURCE_TS, REQUEST_MAX, }; diff --git a/include/util/resource.h b/include/util/resource.h index 71d756f..97a1b93 100644 --- a/include/util/resource.h +++ b/include/util/resource.h @@ -20,6 +20,7 @@ #ifndef __RESOURCE_H__ #define __RESOURCE_H__ +#include #include #include #include "common.h" @@ -136,6 +137,9 @@ struct resource { const struct resource_control *ctrls; u_int64_t attr_interest; u_int64_t attr_supported; + + int64_t ts_start; + int64_t ts_end; }; #define RESOURCE_DRIVER_REGISTER(resource_driver) \ @@ -180,8 +184,9 @@ resource_attr_supported_always(const struct resource *resource, } int get_resource_attrs_json(struct resource *resource, char **json_string); - int get_resource_attr_json(struct resource *resource, u_int64_t attr_id, char **json_string); +int get_resource_list_json(char **json_string); + int get_resource_attr_int(struct resource *resource, u_int64_t attr_id, int32_t *data); int get_resource_attr_int64(struct resource *resource, u_int64_t attr_id, int64_t *data); int get_resource_attr_uint(struct resource *resource, u_int64_t attr_id, u_int32_t *data); @@ -194,4 +199,12 @@ int get_resource_attr_ptr(struct resource *resource, u_int64_t attr_id, void **d int set_resource_attr_interest(struct resource *resource, u_int64_t interest_mask); int unset_resource_attr_interest(struct resource *resource, u_int64_t interest_mask); + +inline __attribute__((always_inline)) int64_t get_time_now(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec; +} #endif diff --git a/lib/resource-monitor/resource-monitor.c b/lib/resource-monitor/resource-monitor.c index af25357..02361f9 100644 --- a/lib/resource-monitor/resource-monitor.c +++ b/lib/resource-monitor/resource-monitor.c @@ -924,3 +924,35 @@ int pass_resource_monitor_get_array_string(int id, int res_id, u_int64_t attr_id { return pass_resource_monitor_get_array(id, res_id, attr_id, DATA_TYPE_STRING, (void **)array, length); } + +int pass_resource_monitor_get_resource_timestamp(int id, int res_id, int64_t *start, int64_t *end) +{ + char buffer[GENERIC_BUFF_MAX + 1]; + int buffer_len; + int response_req; + int ret; + + buffer_len = sprintf(buffer, "%d$%d", REQUEST_GET_RESOURCE_TS, res_id); + if (send(id, buffer, buffer_len, 0) < 0) { + _E("[libpass] error occurred while sending buffer"); + return -EIO; + } + + /* wait for response */ + buffer_len = recv(id, buffer, GENERIC_BUFF_MAX, 0); + if (buffer_len <= 0) { + _E("[libpass] socket disconnected"); + return -EIO; + } + buffer[buffer_len] = '\0'; + + if (sscanf(buffer, "%d$%"PRId64"$%"PRId64"$%d", &response_req, start, end, &ret) < 3) + return -EINVAL; + + if (response_req != REQUEST_GET_VALUE_INT64) { + _E("[libpass] wrong response"); + return -EINVAL; + } + + return ret; +} diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h index 515ec10..c943dc4 100644 --- a/lib/resource-monitor/resource-monitor.h +++ b/lib/resource-monitor/resource-monitor.h @@ -266,6 +266,17 @@ int pass_resource_monitor_get_array_uint64(int id, int res_id, u_int64_t attr, u int pass_resource_monitor_get_array_double(int id, int res_id, u_int64_t attr, double **array, int *length); int pass_resource_monitor_get_array_string(int id, int res_id, u_int64_t attr, char ***array, int *length); +/** + * @brief Get timestamp of the latest resource update + * @param[in] Resource monitor id + * @param[in] Resource id + * @param[out] start time of update + * @param[out] end time of update + * @return @ 0 on success, otherwise a negative error value + */ + +int pass_resource_monitor_get_resource_timestamp(int id, int res_id, int64_t *start, int64_t *end); + #ifdef __cplusplus } #endif diff --git a/src/monitor/request-handler.c b/src/monitor/request-handler.c index 3bbea40..2bad112 100644 --- a/src/monitor/request-handler.c +++ b/src/monitor/request-handler.c @@ -454,6 +454,32 @@ handle_request_get_value_array(struct request_client *client, char *args, struct return get_resource_attr_array(res, attr_id, arr); } +static int +handle_request_get_resource_ts(struct request_client *client, char *args, + int64_t *start, int64_t *end) +{ + struct resource *res; + int resource_id; + + if (!client || !args) + return -ENOENT; + + /** + * Format of REQUEST_GET_RESOURCE_TS args: + * - + */ + resource_id = atoi(args); + + res = get_resource_by_id(client, resource_id); + if (!res) + return -EINVAL; + + *start = res->ts_start; + *end = res->ts_end; + + return 0; +} + static int split_request_type_and_args(char *buffer, char **args) { char *request_type_str; @@ -690,6 +716,17 @@ static int handle_request(struct request_client *client, char *request) } } break; + case REQUEST_GET_RESOURCE_TS: + { + int64_t start, end; + + ret = handle_request_get_resource_ts(client, args, &start, &end); + if (ret < 0) + _D("failed to get value"); + + ADD_RESPONSE(response, buffer_len, "%"PRId64"$%"PRId64"$", start, end); + } + break; default: _E("Invliad request type: %d", request_type); ret = -EINVAL; diff --git a/src/util/resource.c b/src/util/resource.c index aefe3cc..abe7b49 100644 --- a/src/util/resource.c +++ b/src/util/resource.c @@ -254,6 +254,8 @@ int update_resource_attrs(struct resource *resource) if (!resource || !resource->type) return -EINVAL; + resource->ts_start = get_time_now(); + if (resource->driver && resource->driver->ops.prepare_update) { ret = resource->driver->ops.prepare_update(resource); if (ret < 0) @@ -270,6 +272,8 @@ int update_resource_attrs(struct resource *resource) } } + resource->ts_end = get_time_now(); + return 0; } @@ -468,6 +472,7 @@ static void _put_resource_attr_json(json_object *jobj_attr) int get_resource_attrs_json(struct resource *resource, char **json_string) { json_object *jobj_root, *jobj_res_name, *jobj_res_type, *jobj_res_attrs, *jobj_attr; + json_object *jobj_res_ts, *jobj_ts_start, *jobj_ts_end; const struct resource_attribute *attr; const struct resource_attribute_value *attr_value; int i; @@ -493,18 +498,30 @@ int get_resource_attrs_json(struct resource *resource, char **json_string) json_object_array_add(jobj_res_attrs, jobj_attr); } + jobj_res_ts = json_object_new_object(); + jobj_ts_start = json_object_new_int64(resource->ts_start); + jobj_ts_end = json_object_new_int64(resource->ts_end); + + json_object_object_add(jobj_res_ts, "start", jobj_ts_start); + json_object_object_add(jobj_res_ts, "end", jobj_ts_end); + json_object_object_add(jobj_root, "res_name", jobj_res_name); json_object_object_add(jobj_root, "res_type", jobj_res_type); json_object_object_add(jobj_root, "res_attrs", jobj_res_attrs); + json_object_object_add(jobj_root, "res_ts", jobj_res_ts); *json_string = strdup(json_object_to_json_string(jobj_root)); + json_object_object_del(jobj_res_ts, "end"); + json_object_object_del(jobj_res_ts, "start"); + for (i = 0; i < json_object_array_length(jobj_res_attrs); i++) { jobj_attr = json_object_array_get_idx(jobj_res_attrs, i); _put_resource_attr_json(jobj_attr); } json_object_array_del_idx(jobj_res_attrs, 0, json_object_array_length(jobj_res_attrs)); + json_object_object_del(jobj_root, "res_ts"); json_object_object_del(jobj_root, "res_attrs"); json_object_object_del(jobj_root, "res_type"); json_object_object_del(jobj_root, "res_name"); -- 2.7.4 From bb23b347050aa995adaffb8831ffbc9eea0955a1 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 8 Apr 2022 16:59:30 +0900 Subject: [PATCH 04/16] monitor: resource: Add function for getting resource and its attributes list To provide way to manage monitoring module without static list, now json type information for resource and its attributes list can be retrieved with following function: - pass_resource_monitor_get_resource_list_json() Change-Id: Ib9c8787a081f674fc1d6bdf12d9d027cca4b0352 Signed-off-by: Dongwoo Lee --- include/util/request.h | 1 + lib/resource-monitor/resource-monitor.c | 9 +++ lib/resource-monitor/resource-monitor.h | 8 +++ src/monitor/request-handler.c | 11 ++- src/util/resource.c | 122 ++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) diff --git a/include/util/request.h b/include/util/request.h index 44d2047..c640830 100644 --- a/include/util/request.h +++ b/include/util/request.h @@ -45,6 +45,7 @@ enum { REQUEST_GET_VALUE_STRING, REQUEST_GET_VALUE_ARRAY, REQUEST_GET_RESOURCE_TS, + REQUEST_GET_RESOURCE_LIST_JSON, REQUEST_MAX, }; diff --git a/lib/resource-monitor/resource-monitor.c b/lib/resource-monitor/resource-monitor.c index 02361f9..fc70700 100644 --- a/lib/resource-monitor/resource-monitor.c +++ b/lib/resource-monitor/resource-monitor.c @@ -461,6 +461,9 @@ static int pass_resource_monitor_get_json(int id, char *json_string, int request buffer_len = snprintf(buffer, HUGE_BUFF_MAX, "%d$%d$%"PRIu64, request_type, resource_id, attr_id); break; + case REQUEST_GET_RESOURCE_LIST_JSON: + buffer_len = snprintf(buffer, HUGE_BUFF_MAX, "%d", request_type); + break; default: va_end(args); free(buffer); @@ -512,6 +515,12 @@ int pass_resource_monitor_get_value_json(int id, int resource_id, u_int64_t attr } EXPORT +int pass_resource_monitor_get_resource_list_json(int id, char *json_string) +{ + return pass_resource_monitor_get_json(id, json_string, REQUEST_GET_RESOURCE_LIST_JSON); +} + +EXPORT int pass_resource_monitor_get_value_int(int id, int resource_id, u_int64_t attr_id, int32_t *value) { char buffer[GENERIC_BUFF_MAX + 1]; diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h index c943dc4..4644d96 100644 --- a/lib/resource-monitor/resource-monitor.h +++ b/lib/resource-monitor/resource-monitor.h @@ -277,6 +277,14 @@ int pass_resource_monitor_get_array_string(int id, int res_id, u_int64_t attr, c int pass_resource_monitor_get_resource_timestamp(int id, int res_id, int64_t *start, int64_t *end); +/** + * @brief Get all available resource list which monitoring module supported + * @param[in] Resource monitor id + * @param[out] JSON type string for resource + * @return @c positive integer as resource count on success, otherwise a negative error value + */ +int pass_resource_monitor_get_resource_list_json(int id, char *json_string); + #ifdef __cplusplus } #endif diff --git a/src/monitor/request-handler.c b/src/monitor/request-handler.c index 2bad112..184631d 100644 --- a/src/monitor/request-handler.c +++ b/src/monitor/request-handler.c @@ -255,7 +255,7 @@ handle_request_get_json(struct request_client *client, char *args, u_int64_t attr_id; int resource_id; - if (!client || !args) + if (!client) return -ENOENT; /** @@ -263,6 +263,8 @@ handle_request_get_json(struct request_client *client, char *args, * - * Format of REQUEST_GET_VALUE_JSON args: * - : + * Format of REQUEST_GET_RESOURCE_LIST_JSON args: + * - NO ARGUMENTS */ switch (request_type) { case REQUEST_GET_RESOURCE_JSON: @@ -272,6 +274,8 @@ handle_request_get_json(struct request_client *client, char *args, if (sscanf(args, "%d$%"PRIu64, &resource_id, &attr_id) < 2) return -EINVAL; break; + case REQUEST_GET_RESOURCE_LIST_JSON: + goto skip_res; default: return -EINVAL; } @@ -280,11 +284,14 @@ handle_request_get_json(struct request_client *client, char *args, if (!res) return -EINVAL; +skip_res: switch (request_type) { case REQUEST_GET_RESOURCE_JSON: return get_resource_attrs_json(res, json_string); case REQUEST_GET_VALUE_JSON: return get_resource_attr_json(res, attr_id, json_string); + case REQUEST_GET_RESOURCE_LIST_JSON: + return get_resource_list_json(json_string); default: return -EINVAL; } @@ -511,6 +518,7 @@ static int handle_request(struct request_client *client, char *request) case REQUEST_GET_RESOURCE_JSON: case REQUEST_GET_VALUE_JSON: case REQUEST_GET_VALUE_ARRAY: + case REQUEST_GET_RESOURCE_LIST_JSON: buffer_len = HUGE_BUFF_MAX + 1; break; default: @@ -573,6 +581,7 @@ static int handle_request(struct request_client *client, char *request) break; case REQUEST_GET_RESOURCE_JSON: case REQUEST_GET_VALUE_JSON: + case REQUEST_GET_RESOURCE_LIST_JSON: { char *json_string; diff --git a/src/util/resource.c b/src/util/resource.c index abe7b49..9c2233d 100644 --- a/src/util/resource.c +++ b/src/util/resource.c @@ -551,6 +551,128 @@ int get_resource_attr_json(struct resource *resource, u_int64_t attr_id, char ** return 0; } +static json_object *get_resource_driver_json(const struct resource_driver *driver) +{ + json_object *jobj_drv, *jobj_drv_name, *jobj_drv_type; + json_object *jobj_drv_attrs_array, *jobj_drv_attr, *jobj_drv_ctrls_array, *jobj_drv_ctrl; + json_object *jobj_drv_attr_name, *jobj_drv_attr_type, *jobj_drv_attr_id; + json_object *jobj_drv_ctrl_name, *jobj_drv_ctrl_id; + const struct resource_attribute *attr; + const struct resource_control *ctrl; + int i; + + jobj_drv = json_object_new_object(); + + jobj_drv_name = json_object_new_string(driver->name); + jobj_drv_type = json_object_new_int(driver->type); + + jobj_drv_attrs_array = json_object_new_array(); + + for (i = 0; i < driver->num_attrs; i++) { + attr = &driver->attrs[i]; + + jobj_drv_attr = json_object_new_object(); + + jobj_drv_attr_name = json_object_new_string(attr->name); + jobj_drv_attr_type = json_object_new_int(attr->type); + jobj_drv_attr_id = json_object_new_uint64(attr->id); + + json_object_object_add(jobj_drv_attr, "name", jobj_drv_attr_name); + json_object_object_add(jobj_drv_attr, "type", jobj_drv_attr_type); + json_object_object_add(jobj_drv_attr, "id", jobj_drv_attr_id); + + json_object_array_add(jobj_drv_attrs_array, jobj_drv_attr); + } + + jobj_drv_ctrls_array = json_object_new_array(); + + for (i = 0; i < driver->num_ctrls; i++) { + ctrl = &driver->ctrls[i]; + + jobj_drv_ctrl = json_object_new_object(); + + jobj_drv_ctrl_name = json_object_new_string(ctrl->name); + jobj_drv_ctrl_id = json_object_new_uint64(ctrl->id); + + json_object_object_add(jobj_drv_ctrl, "name", jobj_drv_ctrl_name); + json_object_object_add(jobj_drv_ctrl, "id", jobj_drv_ctrl_id); + + json_object_array_add(jobj_drv_ctrls_array, jobj_drv_ctrl); + } + + json_object_object_add(jobj_drv, "name", jobj_drv_name); + json_object_object_add(jobj_drv, "type", jobj_drv_type); + json_object_object_add(jobj_drv, "attrs", jobj_drv_attrs_array); + json_object_object_add(jobj_drv, "ctrls", jobj_drv_ctrls_array); + + return jobj_drv; +} + +void put_resource_driver_json(json_object *jobj_drv) +{ + json_object *jobj_array, *jobj_obj; + int i; + + if (json_object_object_get_ex(jobj_drv, "ctrls", &jobj_array)) { + for (i = 0; i < json_object_array_length(jobj_array); i++) { + jobj_obj = json_object_array_get_idx(jobj_array, i); + + json_object_object_del(jobj_obj, "id"); + json_object_object_del(jobj_obj, "name"); + } + json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array)); + } + + if (json_object_object_get_ex(jobj_drv, "attrs", &jobj_array)) { + for (i = 0; i < json_object_array_length(jobj_array); i++) { + jobj_obj = json_object_array_get_idx(jobj_array, i); + + json_object_object_del(jobj_obj, "id"); + json_object_object_del(jobj_obj, "type"); + json_object_object_del(jobj_obj, "name"); + } + json_object_array_del_idx(jobj_array, 0, json_object_array_length(jobj_array)); + } + + json_object_object_del(jobj_drv, "ctrls"); + json_object_object_del(jobj_drv, "attrs"); + json_object_object_del(jobj_drv, "type"); + json_object_object_del(jobj_drv, "name"); +} + +int get_resource_list_json(char **json_string) +{ + const struct resource_driver *driver; + json_object *jobj_root, *jobj_drvs_array, *jobj_drv; + int i; + + jobj_root = json_object_new_object(); + jobj_drvs_array = json_object_new_array(); + + for (i = 0; i < g_list_length(g_resource_driver_head); i++) { + driver = g_list_nth(g_list_first(g_resource_driver_head), i)->data; + + jobj_drv = get_resource_driver_json(driver); + json_object_array_add(jobj_drvs_array, jobj_drv); + } + + json_object_object_add(jobj_root, "resources", jobj_drvs_array); + + *json_string = strdup(json_object_to_json_string(jobj_root)); + + for (i = 0; i < json_object_array_length(jobj_drvs_array); i++) { + jobj_drv = json_object_array_get_idx(jobj_drvs_array, i); + + put_resource_driver_json(jobj_drv); + } + json_object_array_del_idx(jobj_drvs_array, 0, json_object_array_length(jobj_drvs_array)); + + json_object_object_del(jobj_root, "resources"); + json_object_put(jobj_root); + + return 0; +} + int get_resource_attr_int(struct resource *resource, u_int64_t attr_id, int32_t *data) { struct resource_attribute_value *attr_value = NULL; -- 2.7.4 From b858204d0487a359df0e1843bb3eb42c1d9b3c02 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 12 May 2022 16:09:32 +0900 Subject: [PATCH 05/16] util: timer: Fix possible dangling pointer and memory leak Change-Id: I466617b365e91108c0ed3cdf1d95c8a237feaad8 Signed-off-by: Dongwoo Lee --- src/util/timer.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/util/timer.c b/src/util/timer.c index 849baef..26aad82 100644 --- a/src/util/timer.c +++ b/src/util/timer.c @@ -38,19 +38,11 @@ struct uevent_data { int fd; }; -static gint __compare_timer_id(gconstpointer data, gconstpointer input) -{ - guint id= *(guint *)data; - guint input_id = *(guint *)input; - - return (id == input_id) ? 0 : -1; -} - static bool find_timer(int id) { GList *node; - node = g_list_find_custom(g_timer_list, &id, __compare_timer_id); + node = g_list_find(g_timer_list, GINT_TO_POINTER(id)); if (!node) return false; @@ -89,8 +81,7 @@ int add_timer_handler(unsigned int interval, if (!timer_id) return -EPERM; - g_timer_list = g_list_append(g_timer_list, - (gpointer)&timer_id); + g_timer_list = g_list_append(g_timer_list, GINT_TO_POINTER(timer_id)); return timer_id; } @@ -101,8 +92,7 @@ void delete_timer_handler(int timer_id) return; g_source_remove(timer_id); - g_timer_list = g_list_remove(g_timer_list, - (gpointer)&timer_id); + g_timer_list = g_list_remove(g_timer_list, GINT_TO_POINTER(timer_id)); } struct udev_monitor *add_uevent_handler( @@ -215,6 +205,7 @@ void delete_uevent_handler(struct udev_monitor *udev_monitor) g_source_remove(uevent_data->fd); uevent_data->fd = -1; + free(uevent_data); } void init_timer(void) @@ -235,7 +226,7 @@ void exit_timer(void) */ g_list_free(g_timer_list); - g_list_free(g_uevent_list); + g_list_free_full(g_uevent_list, free); g_timer_list = NULL; g_uevent_list = NULL; -- 2.7.4 From bd3d91617c9448074267869d6ec6f21df2ba2d1f Mon Sep 17 00:00:00 2001 From: Sung-hun Kim Date: Mon, 30 May 2022 15:59:21 +0900 Subject: [PATCH 06/16] resource: memory: Add MEMORY_ATTR_SWAP_TOTAL and MEMORY_ATTR_SWAP_FREE attributes Change-Id: I8f6e3ff274c429fe2e5d2f9378ea4e8ae18dccaf Signed-off-by: Sung-hun Kim --- lib/resource-monitor/resource-monitor.h | 2 ++ src/resource/resource-memory.c | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h index 4644d96..5bfbb3f 100644 --- a/lib/resource-monitor/resource-monitor.h +++ b/lib/resource-monitor/resource-monitor.h @@ -86,6 +86,8 @@ extern "C" { #define MEMORY_ATTR_CACHED BIT(4) /* DATA_TYPE_UINT64 */ #define MEMORY_ATTR_CMA_TOTAL BIT(5) /* DATA_TYPE_UINT64 */ #define MEMORY_ATTR_CMA_FREE BIT(6) /* DATA_TYPE_UINT64 */ +#define MEMORY_ATTR_SWAP_TOTAL BIT(7) /* DATA_TYPE_UINT64 */ +#define MEMORY_ATTR_SWAP_FREE BIT(8) /* DATA_TYPE_UINT64 */ /* Battery Resource */ #define BATTERY_ATTR_CAPACITY BIT(0) /* DATA_TYPE_INT */ diff --git a/src/resource/resource-memory.c b/src/resource/resource-memory.c index f0b8782..48c627d 100644 --- a/src/resource/resource-memory.c +++ b/src/resource/resource-memory.c @@ -38,6 +38,7 @@ #define PROC_MEM_INFO_BUFFER "Buffers" #define PROC_MEM_INFO_CACHED "Cached" #define PROC_MEM_INFO_CMA_FREE "CmaFree" +#define PROC_MEM_INFO_SWAP_FREE "SwapFree" static int memory_get_cma_total(u_int64_t *val) { @@ -57,6 +58,24 @@ static int memory_get_cma_total(u_int64_t *val) return 0; } +static int memory_get_swap_total(u_int64_t *val) +{ + static u_int64_t swap_total = 0; + int ret; + + if (!swap_total) { + ret = kernel_get_memory_info("SwapTotal", &swap_total); + if (ret < 0) { + _E("failed to get system SWAP total memory\n"); + return -EINVAL; + } + } + + *val = swap_total; + + return 0; +} + static int memory_get_memory_info(const struct resource *res, const struct resource_attribute *attr, void *data) @@ -89,6 +108,12 @@ static int memory_get_memory_info(const struct resource *res, case MEMORY_ATTR_CMA_FREE: ret = kernel_get_memory_info(PROC_MEM_INFO_CMA_FREE, val); break; + case MEMORY_ATTR_SWAP_TOTAL: + ret = memory_get_swap_total(val); + break; + case MEMORY_ATTR_SWAP_FREE: + ret = kernel_get_memory_info(PROC_MEM_INFO_SWAP_FREE, val); + break; default: _E("wrong memory resource attribute\n"); ret = -EINVAL; @@ -149,6 +174,20 @@ static const struct resource_attribute memory_attrs[] = { .ops = { .get = memory_get_memory_info, } + }, { + .name = "MEMORY_ATTR_SWAP_TOTAL", + .id = MEMORY_ATTR_SWAP_TOTAL, + .type = DATA_TYPE_UINT64, + .ops = { + .get = memory_get_memory_info, + } + }, { + .name = "MEMORY_ATTR_SWAP_FREE", + .id = MEMORY_ATTR_SWAP_FREE, + .type = DATA_TYPE_UINT64, + .ops = { + .get = memory_get_memory_info, + } }, }; -- 2.7.4 From 5e3193730bd2a1095da2e792341f6940decc2541 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 17 Jun 2022 15:04:56 +0900 Subject: [PATCH 07/16] packaging: Remove unnecessary symlink in sockets.target.wants After removing pass.socket, symlink to it in sockets.target.wants remains. Remove unnecessary symlink. This removes next packaging warning message: warning: Installed (but unpackaged) file(s) found: /usr/lib/systemd/system/sockets.target.wants/pass.socket Change-Id: I8f02dc5d83d8ecd41cf4c3e440b8eeb917bb0aee Fixes: commit 00a3aedc ("pass: Remove unused pass.socket file") Signed-off-by: Seung-Woo Kim --- packaging/pass.spec | 1 - 1 file changed, 1 deletion(-) diff --git a/packaging/pass.spec b/packaging/pass.spec index a9820c8..7c64eae 100644 --- a/packaging/pass.spec +++ b/packaging/pass.spec @@ -89,7 +89,6 @@ rm -rf %{buildroot} %make_install %install_service delayed.target.wants %{daemon_name}.service -%install_service sockets.target.wants %{daemon_name}.socket %post -- 2.7.4 From 22c73d2d9e34d64bca4e4d2b69f2ebbf685271ed Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 17 Jun 2022 15:15:15 +0900 Subject: [PATCH 08/16] pass: Remove unnecessary installed service files The dbus activation service files are not necessary in systemd unitdir. Remove unnecessary installation of dbus activation service files. This removes below packaging warning message: warning: Installed (but unpackaged) file(s) found: /usr/lib/systemd/system/org.tizen.system.pass.service /usr/lib/systemd/system/org.tizen.system.thermal.service Change-Id: I5c13e31032b07db7ac11271ad5f231737383b0f8 Fixes: commit d0b00031fc66 ("core: Add support for dbus activation for thermal") Fixes: commit da1dc2ab2a66 ("core: Apply systemd-based dbus activation") Signed-off-by: Seung-Woo Kim --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba83e67..517d855 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,7 @@ INSTALL(FILES ${CMAKE_SOURCE_DIR}/systemd/org.tizen.system.thermal.service DESTI INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/system FILES_MATCHING - PATTERN "*.service" + PATTERN "${PROJECT_NAME}.service" ) ADD_SUBDIRECTORY(unittest) -- 2.7.4 From b9f08a7f088b274b8018d7ac34b2f74a45dcad9e Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 12 May 2022 14:44:33 +0900 Subject: [PATCH 09/16] util: kernel: Add functions for getting process smaps file Change-Id: Id8b9d677585ccc4381c33eb53373037c64540f59 Signed-off-by: Dongwoo Lee --- include/util/kernel.h | 8 ++++++++ src/util/kernel.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/util/kernel.h b/include/util/kernel.h index 5938d9f..c640bd5 100644 --- a/include/util/kernel.h +++ b/include/util/kernel.h @@ -35,6 +35,13 @@ struct cpu_stat { int64_t soft_irq; }; +struct proc_map_info { + uint32_t rss; + uint32_t pss; + uint32_t swap; + uint32_t swap_pss; +}; + enum { PROCESS_STAT_FIELD_PID, PROCESS_STAT_FIELD_COMM, @@ -58,4 +65,5 @@ int kernel_get_process_stat_fields(pid_t pid, char *buffer, int buf_len, char *stat_fields[PROCESS_STAT_FIELD_MAX]); int kernel_get_process_taskstats(struct taskstats *stats, int cmd_type, pid_t pid); int kernel_get_thread_group_taskstats(struct taskstats *stats, pid_t tgid, bool get_proc_info); +int kernel_get_thread_group_map_info(struct proc_map_info *map_info, pid_t tgid); #endif diff --git a/src/util/kernel.c b/src/util/kernel.c index 653b297..2101535 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -27,6 +27,8 @@ #include #include +static int have_smaps_rollup; + static int __get_cpu_num(char *path) { FILE *fp; @@ -407,3 +409,44 @@ int kernel_get_thread_group_taskstats(struct taskstats *stats, pid_t tgid, bool return 0; } + +int kernel_get_thread_group_map_info(struct proc_map_info *map_info, pid_t tgid) +{ + char smap_file_path[BUFF_MAX]; + char buffer[BUFF_MAX]; + FILE *smaps_file; + + sprintf(smap_file_path, "/proc/%d/%s", tgid, have_smaps_rollup ? "smaps_rollup" : "smaps"); + + smaps_file = fopen(smap_file_path, "r"); + if (!smaps_file) + return -EIO; + + map_info->rss = 0; + map_info->pss = 0; + map_info->swap = 0; + map_info->swap_pss = 0; + + while (fgets(buffer, sizeof(buffer), smaps_file)) { + if (strchr(buffer, '\n') == 0) + continue; + + if (strstr(buffer, "Rss:")) + map_info->rss += strtol(buffer + 4, NULL, 10); + else if (strstr(buffer, "Pss:")) + map_info->pss += strtol(buffer + 4, NULL, 10); + else if (strstr(buffer, "Swap:")) + map_info->swap += strtol(buffer + 5, NULL, 10); + else if (strstr(buffer, "SwapPss:")) + map_info->swap_pss += strtol(buffer + 8, NULL, 10); + } + + fclose(smaps_file); + + return 0; +} + +static void __CONSTRUCTOR__ kernel_init(void) +{ + have_smaps_rollup = !access("/proc/self/smaps_rollup", R_OK); +} -- 2.7.4 From 0c15611cbf696b7fb212e8f37a97b6b35dcb10d4 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 17 Jun 2022 18:03:11 +0900 Subject: [PATCH 10/16] tests: Move test code into tests directory and redefine the test role Move test code into tests directory and redefine the test role as following because unittest will be added for each module. - intergraion test : Test the public interface of PASS daemon - haltest : Test the HAL interface of PASS daemon Change-Id: Ief0d07b38491454dc0dbb06a268e5c56de31a886 Signed-off-by: Chanwoo Choi --- CMakeLists.txt | 5 +-- packaging/pass.spec | 2 +- {unittest => tests/haltest}/CMakeLists.txt | 9 +----- {unittest => tests/haltest}/power-haltests.cpp | 0 tests/integration-test/CMakeLists.txt | 37 ++++++++++++++++++++++ .../integration-test/pass-tests.cpp | 0 6 files changed, 42 insertions(+), 11 deletions(-) rename {unittest => tests/haltest}/CMakeLists.txt (73%) rename {unittest => tests/haltest}/power-haltests.cpp (100%) create mode 100644 tests/integration-test/CMakeLists.txt rename unittest/pass-unittests.cpp => tests/integration-test/pass-tests.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 517d855..6116b46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(pass C) +PROJECT(pass) ######################################################## # PASS CMakeLists.txt @@ -130,5 +130,6 @@ INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/s PATTERN "${PROJECT_NAME}.service" ) -ADD_SUBDIRECTORY(unittest) +ADD_SUBDIRECTORY(tests/integration-test) +ADD_SUBDIRECTORY(tests/haltest) ADD_SUBDIRECTORY(lib) diff --git a/packaging/pass.spec b/packaging/pass.spec index 7c64eae..29a506e 100644 --- a/packaging/pass.spec +++ b/packaging/pass.spec @@ -123,7 +123,7 @@ systemctl daemon-reload %files -n %{unittest_name} %defattr(-,root,root,-) -%{_bindir}/pass-unittests +%{_bindir}/pass-tests %files -n %{libpass_resource_monitor_name} %license LICENSE diff --git a/unittest/CMakeLists.txt b/tests/haltest/CMakeLists.txt similarity index 73% rename from unittest/CMakeLists.txt rename to tests/haltest/CMakeLists.txt index 802fa58..1f0e9a3 100644 --- a/unittest/CMakeLists.txt +++ b/tests/haltest/CMakeLists.txt @@ -29,16 +29,9 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}") SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") -SET(src ${CMAKE_SOURCE_DIR}/unittest/power-haltests.cpp) +SET(src ${CMAKE_SOURCE_DIR}/tests/haltest/power-haltests.cpp) GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) MESSAGE("${src_name}") ADD_EXECUTABLE(${src_name} ${SRCS} ${src}) TARGET_LINK_LIBRARIES(${src_name} ${gtest_LDFLAGS} ${gtest_pkgs_LDFLAGS} -ldl -L${LIBDIR}/hal) INSTALL(TARGETS ${src_name} DESTINATION /usr/bin/hal) - -SET(src ${CMAKE_SOURCE_DIR}/unittest/pass-unittests.cpp) -GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) -MESSAGE("${src_name}") -ADD_EXECUTABLE(${src_name} ${SRCS} ${src}) -TARGET_LINK_LIBRARIES(${src_name} ${gtest_LDFLAGS} ${gtest_pkgs_LDFLAGS} -ldl -L${LIBDIR}/hal) -INSTALL(TARGETS ${src_name} DESTINATION /usr/bin/) diff --git a/unittest/power-haltests.cpp b/tests/haltest/power-haltests.cpp similarity index 100% rename from unittest/power-haltests.cpp rename to tests/haltest/power-haltests.cpp diff --git a/tests/integration-test/CMakeLists.txt b/tests/integration-test/CMakeLists.txt new file mode 100644 index 0000000..2f12af5 --- /dev/null +++ b/tests/integration-test/CMakeLists.txt @@ -0,0 +1,37 @@ +PROJECT(pass C CXX) + +SET(SRCS ${CMAKE_SOURCE_DIR}/src/pass/pass-hal.c + ${CMAKE_SOURCE_DIR}/src/pass/pass-parser.c + ${CMAKE_SOURCE_DIR}/src/util/common.c +) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/pass) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) + +INCLUDE(FindPkgConfig) +pkg_check_modules(gtest_pkgs REQUIRED + glib-2.0 + gio-2.0 + gmock + dlog + json-c + hal-api-power +) + +FOREACH(flag ${gtest_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall -fPIE -fPIC") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +SET(src ${CMAKE_SOURCE_DIR}/tests/integration-test/pass-tests.cpp) +GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) +MESSAGE("${src_name}") +ADD_EXECUTABLE(${src_name} ${SRCS} ${src}) +TARGET_LINK_LIBRARIES(${src_name} ${gtest_LDFLAGS} ${gtest_pkgs_LDFLAGS} -ldl -L${LIBDIR}/hal) +INSTALL(TARGETS ${src_name} DESTINATION /usr/bin/) diff --git a/unittest/pass-unittests.cpp b/tests/integration-test/pass-tests.cpp similarity index 100% rename from unittest/pass-unittests.cpp rename to tests/integration-test/pass-tests.cpp -- 2.7.4 From a2b9e042d7c07281d4ecfd85add4995b3278fa97 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 20 Jun 2022 13:38:01 +0900 Subject: [PATCH 11/16] tests: unittest: Add pass-unittest skeleton for testing pass module PASS daemon contains the modules such as pass-parser, pass-hal, pass-rescon, pass-resmon and son on. It requires the testing on building time. In order to support the unittest of pass module, add pass-unittest skeleton code. Change-Id: Ie4c8637b4c0b5045b59eb3a92495f132aeb0c6e3 Signed-off-by: Chanwoo Choi --- CMakeLists.txt | 2 ++ packaging/pass.spec | 3 +++ tests/unittest/CMakeLists.txt | 39 +++++++++++++++++++++++++++++++++++++++ tests/unittest/pass-unittests.cc | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 tests/unittest/CMakeLists.txt create mode 100644 tests/unittest/pass-unittests.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 6116b46..71ab2c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,4 +132,6 @@ INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/systemd/ DESTINATION lib/systemd/s ADD_SUBDIRECTORY(tests/integration-test) ADD_SUBDIRECTORY(tests/haltest) +ADD_SUBDIRECTORY(tests/unittest) + ADD_SUBDIRECTORY(lib) diff --git a/packaging/pass.spec b/packaging/pass.spec index 29a506e..74c735a 100644 --- a/packaging/pass.spec +++ b/packaging/pass.spec @@ -84,6 +84,9 @@ cp %{SOURCE1} . cp %{SOURCE2} . make %{?jobs:-j%jobs} +%check +(cd tests/unittest && LD_LIBRARY_PATH=../../ ctest -V) + %install rm -rf %{buildroot} %make_install diff --git a/tests/unittest/CMakeLists.txt b/tests/unittest/CMakeLists.txt new file mode 100644 index 0000000..25b89aa --- /dev/null +++ b/tests/unittest/CMakeLists.txt @@ -0,0 +1,39 @@ +ENABLE_TESTING() +SET(PASS_UNITTEST "pass-unittests") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Werror") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror") + +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ PASS_UNITTEST_SRCS) +ADD_EXECUTABLE(${PASS_UNITTEST} ${PASS_UNITTEST_SRCS}) + +TARGET_INCLUDE_DIRECTORIES(${PASS_UNITTEST} PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}/../../include" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/src" + "${CMAKE_SOURCE_DIR}/src/pass" + "${CMAKE_SOURCE_DIR}/include" +) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pass_unittest_pkgs REQUIRED + glib-2.0 + gio-2.0 + gmock + dlog + json-c + hal-api-power +) + +FOREACH(flag ${pass_unittest_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +TARGET_LINK_LIBRARIES(${PASS_UNITTEST} ${pass_unittest_pkgs_LDFLAGS}) +SET_TARGET_PROPERTIES(${PASS_UNITTEST} PROPERTIES COMPILE_FLAGS "-fPIE -fvisibility=default") +SET_TARGET_PROPERTIES(${PASS_UNITTEST} PROPERTIES LINK_FLAGS "-pie") + +ADD_TEST( + NAME ${PASS_UNITTEST} + COMMAND ${PASS_UNITTEST} +) diff --git a/tests/unittest/pass-unittests.cc b/tests/unittest/pass-unittests.cc new file mode 100644 index 0000000..14748d2 --- /dev/null +++ b/tests/unittest/pass-unittests.cc @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + try { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + } catch (...) { + return EXIT_FAILURE; + } +} -- 2.7.4 From 6573f55ef63684eac95a6dc1dcf1fa3d0467f7ba Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 20 Jun 2022 17:10:30 +0900 Subject: [PATCH 12/16] tests: unittest: Add hal-api-power mock class PASS comunicates with hal-api-power to read/write the h/w resources such as CPU/Memory Bus/GPU/Memroy and so on. For the testing on build time, it requires the mocking of hal-api-power. In result, add hal-api-power mock class. Change-Id: I75e7537d3a94059d586943810c502882d24a1517 Signed-off-by: Chanwoo Choi --- tests/unittest/hal-api-power-mock.cpp | 352 ++++++++++++++++++++++++++++++++++ tests/unittest/hal-api-power-mock.hpp | 183 ++++++++++++++++++ 2 files changed, 535 insertions(+) create mode 100644 tests/unittest/hal-api-power-mock.cpp create mode 100644 tests/unittest/hal-api-power-mock.hpp diff --git a/tests/unittest/hal-api-power-mock.cpp b/tests/unittest/hal-api-power-mock.cpp new file mode 100644 index 0000000..b9a550f --- /dev/null +++ b/tests/unittest/hal-api-power-mock.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2022 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include + +extern "C" { +#include "pass.h" +#include "pass-hal.h" +#include "pass-parser.h" +} + +#include "hal-api-power-mock.hpp" + +using namespace std; +using ::testing::Return; +using ::testing::_; + +HalApiPowerMock *gHalApiPowerMock; + +/** + * Get and put power hal backend + */ +int hal_power_get_backend(unsigned int res_type) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_get_backend(res_type); +} +int hal_power_put_backend(void) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_put_backend(); +} + +/** + * DVFS (Dynamic Voltage Frequency Scaling) Operation for CPU/BUS/GPU H/W + */ +/* Get and set the current governor. */ +int hal_power_dvfs_get_curr_governor(unsigned int res_type, char *res_name, char *governor) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_curr_governor( + res_type, res_name, governor); +} +int hal_power_dvfs_set_curr_governor(unsigned int res_type, char *res_name, char *governor) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_set_curr_governor( + res_type, res_name, governor); +} +int hal_power_dvfs_get_avail_governor(unsigned int res_type, char *res_name, char **avail_governor) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_avail_governor( + res_type, res_name, avail_governor); +} + +/* Get the current frequency. */ +int hal_power_dvfs_get_curr_freq(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_curr_freq( + res_type, res_name); +} + +/* Get and set the minimum frequency. */ +int hal_power_dvfs_get_min_freq(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_min_freq( + res_type, res_name); +} +int hal_power_dvfs_set_min_freq(unsigned int res_type, char *res_name, int freq) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_set_min_freq( + res_type, res_name, freq); +} + +/* Get and set the maximum frequency. */ +int hal_power_dvfs_get_max_freq(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_max_freq( + res_type, res_name); +} +int hal_power_dvfs_set_max_freq(unsigned int res_type, char *res_name, int freq) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_set_max_freq( + res_type, res_name, freq); +} + +/* Get the minimum/maximum frequency which can be set to resource. */ +int hal_power_dvfs_get_available_min_freq(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + return gHalApiPowerMock->hal_power_dvfs_get_available_min_freq( + res_type, res_name); +} +int hal_power_dvfs_get_available_max_freq(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_available_max_freq( + res_type, res_name); +} + +/* Get and set the up_threshold to support boosting. */ +int hal_power_dvfs_get_up_threshold(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_up_threshold( + res_type, res_name); +} +int hal_power_dvfs_set_up_threshold(unsigned int res_type, char *res_name, int up_threshold) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_set_up_threshold( + res_type, res_name, up_threshold); +} + +/* Get the load_table of each resource to estimate the system load. */ +int hal_power_dvfs_get_load_table(unsigned int res_type, char *name, void *pass_cpu_load_table) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_dvfs_get_load_table( + res_type, name, pass_cpu_load_table); +} + +/** + * CPU Hotplug Operation for CPU H/W + */ +/* Get and set the online status of resource. */ +int hal_power_hotplug_get_online_state(unsigned int res_type, char *res_name, int cpu) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_hotplug_get_online_state( + res_type, res_name, cpu); +} +int hal_power_hotplug_set_online_state(unsigned int res_type, char *res_name, int cpu, int on) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_hotplug_set_online_state( + res_type, res_name, cpu, on); +} + +/* Get and set the minimum number of online CPUs */ +int hal_power_hotplug_get_online_min_num (unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_hotplug_get_online_min_num ( + res_type, res_name); +} +int hal_power_hotplug_set_online_min_num (unsigned int res_type, char *res_name, int min_num) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_hotplug_set_online_min_num ( + res_type, res_name, min_num); +} + +/* Get and set the maximum number of online CPUs */ +int hal_power_hotplug_get_online_max_num (unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_hotplug_get_online_max_num ( + res_type, res_name); +} +int hal_power_hotplug_set_online_max_num (unsigned int res_type, char *res_name, int max_num) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_hotplug_set_online_max_num ( + res_type, res_name, max_num); +} + +/** + * Thermal Operation for CPU/BUS/GPU H/W + */ +/* Get the current temperature of resource. */ +int hal_power_thermal_get_temp(unsigned int res_type, char *res_thermal_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_thermal_get_temp( + res_type, res_thermal_name); +} + +/* Get the policy of thermal management unit. */ +int hal_power_thermal_get_policy(unsigned int res_type, char *res_thermal_name, char *policy) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_thermal_get_policy( + res_type, res_thermal_name, policy); +} + +/* Get and set the state of thermal cooling-device */ +int hal_power_thermal_get_cooling_device_state(unsigned int device_type, char *cooling_device_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_thermal_get_cooling_device_state( + device_type, cooling_device_name); +} +int hal_power_thermal_set_cooling_device_state(unsigned int device_type, char *cooling_device_name, int state) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_thermal_set_cooling_device_state( + device_type, cooling_device_name, state); +} + +/* Get maximum state of thermal cooling-device */ +int hal_power_thermal_get_cooling_device_max_state(unsigned int device_type, char *cooling_device_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_thermal_get_cooling_device_max_state( + device_type, cooling_device_name); +} + +/* Get and set the battery charging state */ +int hal_power_battery_get_charging_status(unsigned int device_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_battery_get_charging_status( + device_type, res_name); +} +int hal_power_battery_set_charging_status(unsigned int device_type, char *res_name, int state) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_battery_set_charging_status( + device_type, res_name, state); +} + +/* Get and set the battery charging current (unit: uA) */ +int hal_power_battery_get_charging_current(unsigned int device_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_battery_get_charging_current( + device_type, res_name); +} +int hal_power_battery_set_charging_current(unsigned int device_type, char *res_name, int charing_current_uA) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_battery_set_charging_current( + device_type, res_name, charing_current_uA); +} + +/** + * Memory Operation for Memory H/W + */ +/* Get and set the /sys/kernel/debug/fault_around_bytes */ +int hal_power_memory_get_fault_around_bytes(unsigned int res_type, char *res_name) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_memory_get_fault_around_bytes( + res_type, res_name); +} +int hal_power_memory_set_fault_around_bytes(unsigned int res_type, char *res_name, int fault_around_bytes) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_memory_set_fault_around_bytes( + res_type, res_name, fault_around_bytes); +} + +/** + * Miscellaneous Operation for CPU/BUS/GPU H/W + */ +int hal_power_misc_set_pmqos_data(unsigned int res_type, char *res_name, void *data) +{ + if (!gHalApiPowerMock) + return -ENOTSUP; + + return gHalApiPowerMock->hal_power_misc_set_pmqos_data( + res_type, res_name, data); +} diff --git a/tests/unittest/hal-api-power-mock.hpp b/tests/unittest/hal-api-power-mock.hpp new file mode 100644 index 0000000..e03c2ba --- /dev/null +++ b/tests/unittest/hal-api-power-mock.hpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2022 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include + +extern "C" { +#include "pass.h" +#include "pass-hal.h" +#include "pass-parser.h" +} + +using namespace std; +using ::testing::Return; +using ::testing::_; + +class HalApiPowerMockInterface { +public: + virtual ~HalApiPowerMockInterface() {}; + + /** + * Get and put power hal backend + */ + virtual int hal_power_get_backend(unsigned int res_type) = 0; + virtual int hal_power_put_backend(void) = 0; + + /** + * DVFS (Dynamic Voltage Frequency Scaling) Operation for CPU/BUS/GPU H/W + */ + /* Get and set the current governor. */ + virtual int hal_power_dvfs_get_curr_governor(unsigned int res_type, char *res_name, char *governor) = 0; + virtual int hal_power_dvfs_set_curr_governor(unsigned int res_type, char *res_name, char *governor) = 0; + virtual int hal_power_dvfs_get_avail_governor(unsigned int res_type, char *res_name, char **avail_governor) = 0; + + /* Get the current frequency. */ + virtual int hal_power_dvfs_get_curr_freq(unsigned int res_type, char *res_name) = 0; + + /* Get and set the minimum frequency. */ + virtual int hal_power_dvfs_get_min_freq(unsigned int res_type, char *res_name) = 0; + virtual int hal_power_dvfs_set_min_freq(unsigned int res_type, char *res_name, int freq) = 0; + + /* Get and set the maximum frequency. */ + virtual int hal_power_dvfs_get_max_freq(unsigned int res_type, char *res_name) = 0; + virtual int hal_power_dvfs_set_max_freq(unsigned int res_type, char *res_name, int freq) = 0; + + /* Get the minimum/maximum frequency which can be set to resource. */ + virtual int hal_power_dvfs_get_available_min_freq(unsigned int res_type, char *res_name) = 0; + virtual int hal_power_dvfs_get_available_max_freq(unsigned int res_type, char *res_name) = 0; + + /* Get and set the up_threshold to support boosting. */ + virtual int hal_power_dvfs_get_up_threshold(unsigned int res_type, char *res_name) = 0; + virtual int hal_power_dvfs_set_up_threshold(unsigned int res_type, char *res_name, int up_threshold) = 0; + + /* Get the load_table of each resource to estimate the system load. */ + virtual int hal_power_dvfs_get_load_table(unsigned int res_type, char *name, void *pass_cpu_load_table) = 0; + + /** + * CPU Hotplug Operation for CPU H/W + */ + /* Get and set the online status of resource. */ + virtual int hal_power_hotplug_get_online_state(unsigned int res_type, char *res_name, int cpu) = 0; + virtual int hal_power_hotplug_set_online_state(unsigned int res_type, char *res_name, int cpu, int on) = 0; + + /* Get and set the minimum number of online CPUs */ + virtual int hal_power_hotplug_get_online_min_num (unsigned int res_type, char *res_name) = 0; + virtual int hal_power_hotplug_set_online_min_num (unsigned int res_type, char *res_name, int min_num) = 0; + + /* Get and set the maximum number of online CPUs */ + virtual int hal_power_hotplug_get_online_max_num (unsigned int res_type, char *res_name) = 0; + virtual int hal_power_hotplug_set_online_max_num (unsigned int res_type, char *res_name, int max_num) = 0; + + /** + * Thermal Operation for CPU/BUS/GPU H/W + */ + /* Get the current temperature of resource. */ + virtual int hal_power_thermal_get_temp(unsigned int res_type, char *res_thermal_name) = 0; + + /* Get the policy of thermal management unit. */ + virtual int hal_power_thermal_get_policy(unsigned int res_type, char *res_thermal_name, char *policy) = 0; + + /* Get and set the state of thermal cooling-device */ + virtual int hal_power_thermal_set_cooling_device_state(unsigned int device_type, char *cooling_device_name, int state) = 0; + virtual int hal_power_thermal_get_cooling_device_state(unsigned int device_type, char *cooling_device_name) = 0; + + /* Get maximum state of thermal cooling-device */ + virtual int hal_power_thermal_get_cooling_device_max_state(unsigned int device_type, char *cooling_device_name) = 0; + + /* Get and set the battery charging state */ + virtual int hal_power_battery_set_charging_status(unsigned int device_type, char *res_name, int state) = 0; + virtual int hal_power_battery_get_charging_status(unsigned int device_type, char *res_name) = 0; + + /* Get and set the battery charging current (unit: uA) */ + virtual int hal_power_battery_set_charging_current(unsigned int device_type, char *res_name, int charing_current_uA) = 0; + virtual int hal_power_battery_get_charging_current(unsigned int device_type, char *res_name) = 0; + + /** + * Memory Operation for Memory H/W + */ + /* Get and set the /sys/kernel/debug/fault_around_bytes */ + virtual int hal_power_memory_get_fault_around_bytes(unsigned int res_type, char *res_name) = 0; + virtual int hal_power_memory_set_fault_around_bytes(unsigned int res_type, char *res_name, int fault_around_bytes) = 0; + + /** + * Miscellaneous Operation for CPU/BUS/GPU H/W + */ + virtual int hal_power_misc_set_pmqos_data(unsigned int res_type, char *res_name, void *data) = 0; +}; + +class HalApiPowerMock:HalApiPowerMockInterface { +public: + MOCK_METHOD1(hal_power_get_backend, int (unsigned int res_type)); + MOCK_METHOD0(hal_power_put_backend, int (void)); + + MOCK_METHOD3(hal_power_dvfs_get_curr_governor, int (unsigned int res_type, char *res_name, char *governor)); + MOCK_METHOD3(hal_power_dvfs_set_curr_governor, int (unsigned int res_type, char *res_name, char *governor)); + MOCK_METHOD3(hal_power_dvfs_get_avail_governor, int (unsigned int res_type, char *res_name, char **avail_governor)); + + MOCK_METHOD2(hal_power_dvfs_get_curr_freq, int (unsigned int res_type, char *res_name)); + + MOCK_METHOD2(hal_power_dvfs_get_min_freq, int (unsigned int res_type, char *res_name)); + MOCK_METHOD3(hal_power_dvfs_set_min_freq, int (unsigned int res_type, char *res_name, int freq)); + + MOCK_METHOD2(hal_power_dvfs_get_max_freq, int (unsigned int res_type, char *res_name)); + MOCK_METHOD3(hal_power_dvfs_set_max_freq, int (unsigned int res_type, char *res_name, int freq)); + + MOCK_METHOD2(hal_power_dvfs_get_available_min_freq, int (unsigned int res_type, char *res_name)); + MOCK_METHOD2(hal_power_dvfs_get_available_max_freq, int (unsigned int res_type, char *res_name)); + + MOCK_METHOD2(hal_power_dvfs_get_up_threshold, int (unsigned int res_type, char *res_name)); + MOCK_METHOD3(hal_power_dvfs_set_up_threshold, int (unsigned int res_type, char *res_name, int up_threshold)); + + MOCK_METHOD3(hal_power_dvfs_get_load_table, int (unsigned int res_type, char *name, void *pass_cpu_load_table)); + + MOCK_METHOD3(hal_power_hotplug_get_online_state, int (unsigned int res_type, char *res_name, int cpu)); + MOCK_METHOD4(hal_power_hotplug_set_online_state, int (unsigned int res_type, char *res_name, int cpu, int on)); + + MOCK_METHOD2(hal_power_hotplug_get_online_min_num, int (unsigned int res_type, char *res_name)); + MOCK_METHOD3(hal_power_hotplug_set_online_min_num, int (unsigned int res_type, char *res_name, int min_num)); + + MOCK_METHOD2(hal_power_hotplug_get_online_max_num, int (unsigned int res_type, char *res_name)); + MOCK_METHOD3(hal_power_hotplug_set_online_max_num, int (unsigned int res_type, char *res_name, int max_num)); + + MOCK_METHOD2(hal_power_thermal_get_temp, int (unsigned int res_type, char *res_thermal_name)); + + MOCK_METHOD3(hal_power_thermal_get_policy, int (unsigned int res_type, char *res_thermal_name, char *policy)); + + MOCK_METHOD3(hal_power_thermal_set_cooling_device_state, int (unsigned int device_type, char *cooling_device_name, int state)); + MOCK_METHOD2(hal_power_thermal_get_cooling_device_state, int (unsigned int device_type, char *cooling_device_name)); + + MOCK_METHOD2(hal_power_thermal_get_cooling_device_max_state, int (unsigned int device_type, char *cooling_device_name)); + + MOCK_METHOD3(hal_power_battery_set_charging_status, int (unsigned int device_type, char *res_name, int state)); + MOCK_METHOD2(hal_power_battery_get_charging_status, int (unsigned int device_type, char *res_name)); + + MOCK_METHOD3(hal_power_battery_set_charging_current, int (unsigned int device_type, char *res_name, int charing_current_uA)); + MOCK_METHOD2(hal_power_battery_get_charging_current, int (unsigned int device_type, char *res_name)); + + MOCK_METHOD2(hal_power_memory_get_fault_around_bytes, int (unsigned int res_type, char *res_name)); + MOCK_METHOD3(hal_power_memory_set_fault_around_bytes, int (unsigned int res_type, char *res_name, int fault_around_bytes)); + + MOCK_METHOD3(hal_power_misc_set_pmqos_data, int (unsigned int res_type, char *res_name, void *data)); + +}; + +extern HalApiPowerMock *gHalApiPowerMock; -- 2.7.4 From 8fb09d193c7c6be346c88b8eeb739640a54dfb85 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 20 Jun 2022 17:10:48 +0900 Subject: [PATCH 13/16] tests: unittest: Add unittest of pass-hal module The pass-hal module is in charge of communicating with hal-api-power for writing the value to h/w resource such as CPU/GPU/Battery etc and for reading the value from h/w resources. Change-Id: Icc9b5d48b2a30771753afd241e39e67ddf86c62f Signed-off-by: Chanwoo Choi --- tests/unittest/CMakeLists.txt | 6 +- tests/unittest/pass-unittests.cc | 469 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 474 insertions(+), 1 deletion(-) diff --git a/tests/unittest/CMakeLists.txt b/tests/unittest/CMakeLists.txt index 25b89aa..9d89951 100644 --- a/tests/unittest/CMakeLists.txt +++ b/tests/unittest/CMakeLists.txt @@ -4,8 +4,12 @@ SET(PASS_UNITTEST "pass-unittests") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Werror") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -Wall -Werror") +SET(PASS_SRCS + ${CMAKE_SOURCE_DIR}/src/pass/pass-hal.c +) + AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ PASS_UNITTEST_SRCS) -ADD_EXECUTABLE(${PASS_UNITTEST} ${PASS_UNITTEST_SRCS}) +ADD_EXECUTABLE(${PASS_UNITTEST} ${PASS_UNITTEST_SRCS} ${PASS_SRCS}) TARGET_INCLUDE_DIRECTORIES(${PASS_UNITTEST} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../../include" diff --git a/tests/unittest/pass-unittests.cc b/tests/unittest/pass-unittests.cc index 14748d2..736ebde 100644 --- a/tests/unittest/pass-unittests.cc +++ b/tests/unittest/pass-unittests.cc @@ -21,6 +21,475 @@ #include #include +extern "C" { +#include + +#include "pass.h" +#include "pass-hal.h" +} + +#include "hal-api-power-mock.hpp" + +#define FREQ_100MZ 100000 +#define CHARGING_CURRNT_1A 1000000 +#define DEFAULT_MINUS_INT -1 +#define DEFAULT_UP_THRESHOLD 90 + +using namespace std; +using ::testing::Return; +using ::testing::_; + +class PassHalTest : public testing::Test { +public: + void SetUp() override { + gHalApiPowerMock = new HalApiPowerMock(); + } + + void TearDown() override { + if (!gHalApiPowerMock) + return; + + delete gHalApiPowerMock; + gHalApiPowerMock = NULL; + } +}; + +TEST_F(PassHalTest, pass_hal_get_resource) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, + hal_power_get_backend(_)).WillRepeatedly(Return(0)); + + ret = pass_hal_get_resource(&res); + EXPECT_EQ(ret, 0); + + ret = pass_hal_get_resource(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_put_resource) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, + hal_power_put_backend()).WillRepeatedly(Return(0)); + + ret = pass_hal_put_resource(&res); + EXPECT_EQ(ret, 0); + + ret = pass_hal_put_resource(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_curr_governor) { + struct pass_resource res; + char buf[BUFF_MAX]; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_curr_governor(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_curr_governor(&res, buf); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_curr_governor(&res, NULL); + EXPECT_NE(ret, 0); + ret = pass_hal_get_curr_governor(NULL, buf); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_curr_governor) { + struct pass_resource res; + char buf[BUFF_MAX]; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_set_curr_governor(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_curr_governor(&res, buf); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_curr_governor(&res, NULL); + EXPECT_NE(ret, 0); + ret = pass_hal_set_curr_governor(NULL, buf); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_curr_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_curr_freq(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_curr_freq(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_curr_freq(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_min_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_min_freq(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_min_freq(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_min_freq(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_min_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_set_min_freq(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_min_freq(&res, FREQ_100MZ); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_min_freq(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_min_freq(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_max_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_max_freq(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_max_freq(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_max_freq(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_max_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_set_max_freq(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_max_freq(&res, FREQ_100MZ); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_max_freq(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_max_freq(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_available_min_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_available_min_freq(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_available_min_freq(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_available_min_freq(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_available_max_freq) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_available_max_freq(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_available_max_freq(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_available_max_freq(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_up_threshold) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_get_up_threshold(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_up_threshold(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_up_threshold(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_up_threshold) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_dvfs_set_up_threshold(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_up_threshold(&res, DEFAULT_UP_THRESHOLD); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_up_threshold(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_up_threshold(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_online_state) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_hotplug_get_online_state(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_online_state(&res, 0); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_online_state(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_get_online_state(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_online_state) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_hotplug_set_online_state(_, _, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_online_state(&res, 0, 1); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_online_state(&res, 0, 0); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_online_state(&res, 0, 10); + EXPECT_NE(ret, 0); + ret = pass_hal_set_online_state(&res, DEFAULT_MINUS_INT, 1); + EXPECT_NE(ret, 0); + ret = pass_hal_set_online_state(&res, 0, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_online_state(NULL, DEFAULT_MINUS_INT, 1); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_online_min_num) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_hotplug_get_online_min_num (_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_online_min_num(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_online_min_num(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_online_min_num) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_hotplug_set_online_min_num (_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_online_min_num(&res, 1); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_online_min_num(NULL, 2); + EXPECT_NE(ret, 0); + ret = pass_hal_set_online_min_num(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_online_max_num) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_hotplug_get_online_max_num (_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_online_max_num(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_online_max_num(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_online_max_num) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_hotplug_set_online_max_num (_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_online_max_num(&res, 1); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_online_max_num(NULL, 2); + EXPECT_NE(ret, 0); + ret = pass_hal_set_online_max_num(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_temp) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_thermal_get_temp(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_temp(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_temp(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_tmu_policy) { + struct pass_resource res; + char buf[BUFF_MAX]; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_thermal_get_policy(_, _,_)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_tmu_policy(&res, buf); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_tmu_policy(&res, NULL); + EXPECT_NE(ret, 0); + ret = pass_hal_get_tmu_policy(NULL, buf); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_cooling_device_state) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_thermal_get_cooling_device_state(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_cooling_device_state(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_cooling_device_state(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_cooling_device_state) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_thermal_set_cooling_device_state(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_cooling_device_state(&res, 1); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_cooling_device_state(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_cooling_device_state(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_battery_charging_status) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_battery_get_charging_status(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_battery_charging_status(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_battery_charging_status(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_battery_charging_status) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_battery_set_charging_status(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_battery_charging_status(&res, 0); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_battery_charging_status(&res, 1); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_battery_charging_status(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_battery_charging_status(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_battery_charging_current) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_battery_get_charging_current(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_battery_charging_current(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_battery_charging_current(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_battery_charging_current) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_battery_set_charging_current(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_battery_charging_current(&res, CHARGING_CURRNT_1A); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_battery_charging_current(&res, 0); + EXPECT_NE(ret, 0); + ret = pass_hal_set_battery_charging_current(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_battery_charging_current(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_get_fault_around_bytes) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_memory_get_fault_around_bytes(_, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_get_fault_around_bytes(&res); + EXPECT_EQ(ret, 0); + ret = pass_hal_get_fault_around_bytes(NULL); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_fault_around_bytes) { + struct pass_resource res; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_memory_set_fault_around_bytes(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_fault_around_bytes(&res, FREQ_100MZ); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_fault_around_bytes(&res, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); + ret = pass_hal_set_fault_around_bytes(NULL, DEFAULT_MINUS_INT); + EXPECT_NE(ret, 0); +} + +TEST_F(PassHalTest, pass_hal_set_pmqos_data) { + struct pass_resource res; + char buf[BUFF_MAX]; + int ret; + + EXPECT_CALL(*gHalApiPowerMock, hal_power_misc_set_pmqos_data(_, _, _)) + .WillRepeatedly(Return(0)); + + ret = pass_hal_set_pmqos_data(&res, (void *)buf); + EXPECT_EQ(ret, 0); + ret = pass_hal_set_pmqos_data(NULL, (void *)buf); + EXPECT_NE(ret, 0); + ret = pass_hal_set_pmqos_data(NULL, NULL); + EXPECT_NE(ret, 0); +} + int main(int argc, char *argv[]) { try { -- 2.7.4 From d90a2c8bffade2af262d08099742689bf443f614 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 21 Jun 2022 12:05:45 +0900 Subject: [PATCH 14/16] pass: hal: Add missing parameter validation If enter the wrong value, it cause the fault and wrong operation. So that add the missing parameter validation checking to prevent the wrong operation. Add missing parameter validation by using the unittest result of pass-hal module. - Detailed the unittest result of pass-hal module [ FAILED ] PassHalTest.pass_hal_set_online_state (7 ms) [ FAILED ] PassHalTest.pass_hal_set_cooling_device_state (1 ms) [ FAILED ] PassHalTest.pass_hal_set_battery_charging_status (1 ms) [ FAILED ] PassHalTest.pass_hal_set_battery_charging_current (1 ms) [ FAILED ] PassHalTest.pass_hal_set_fault_around_bytes (1 ms) Change-Id: Id320b77188508d82bc68137c65bb5b7d81729c55 Signed-off-by: Chanwoo Choi --- src/pass/pass-hal.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pass/pass-hal.c b/src/pass/pass-hal.c index f5d81b5..a5a679d 100644 --- a/src/pass/pass-hal.c +++ b/src/pass/pass-hal.c @@ -277,7 +277,10 @@ int pass_hal_get_online_state(struct pass_resource *res, int cpu) */ int pass_hal_set_online_state(struct pass_resource *res, int cpu, int on) { - if (!res || cpu < 0 || on < 0) + if (!res || cpu < 0) + return -EINVAL; + + if (on != 0 && on != 1) return -EINVAL; return hal_power_hotplug_set_online_state(res->config_data.res_type, @@ -434,7 +437,7 @@ int pass_hal_get_cooling_device_state(struct pass_resource *res) */ int pass_hal_set_cooling_device_state(struct pass_resource *res, int state) { - if (!res) + if (!res || state < 0) return -EINVAL; /* @@ -480,7 +483,7 @@ int pass_hal_get_cooling_device_max_state(struct pass_resource *res) */ int pass_hal_set_battery_charging_status(struct pass_resource *res, int charging_status) { - if (!res) + if (!res || charging_status < 0) return -EINVAL; return hal_power_battery_set_charging_status(res->config_data.res_type, @@ -517,7 +520,7 @@ int pass_hal_get_battery_charging_status(struct pass_resource *res) int pass_hal_set_battery_charging_current(struct pass_resource *res, int charging_current_uA) { - if (!res) + if (!res || charging_current_uA <= 0) return -EINVAL; return hal_power_battery_set_charging_current(res->config_data.res_type, @@ -555,7 +558,7 @@ int pass_hal_get_battery_charging_current(struct pass_resource *res) int pass_hal_set_fault_around_bytes(struct pass_resource *res, int fault_around_bytes) { - if (!res) + if (!res || fault_around_bytes <= 0) return -EINVAL; return hal_power_memory_set_fault_around_bytes(res->config_data.res_type, -- 2.7.4 From dfdc931c6d63dedb6c98770b834762cd65e1e275 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 16 Jun 2022 16:40:34 +0900 Subject: [PATCH 15/16] pass: Add capability for procfs access Change-Id: I72c186afad13f4a21400ea96f09ad72e3a42a8a1 Signed-off-by: Dongwoo Lee --- systemd/pass.service.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemd/pass.service.in b/systemd/pass.service.in index 3bd6f96..ac5f160 100644 --- a/systemd/pass.service.in +++ b/systemd/pass.service.in @@ -10,7 +10,7 @@ RestartSec=0 KillSignal=SIGUSR1 User=system_fw Group=system_fw -Capabilities=cap_net_admin=i +Capabilities=cap_net_admin,cap_sys_ptrace=i SecureBits=keep-caps [Install] -- 2.7.4 From 6223400fba2ec058e0c7346aadb3955e0c14a230 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 12 May 2022 14:45:29 +0900 Subject: [PATCH 16/16] resource: process-group: Add additional memory attributes This adds new memory attributes: - PROCESS_GROUP_ATTR_MEM_PSS - PROCESS_GROUP_ATTR_MEM_SWAP - PROCESS_GROUP_ATTR_MEM_SWAP_PSS Change-Id: I78062afa487d186489e4b9a7eea479f7b5f1be72 Signed-off-by: Dongwoo Lee --- lib/resource-monitor/resource-monitor.h | 3 ++ src/resource/resource-process-group.c | 59 ++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h index 5bfbb3f..8956376 100644 --- a/lib/resource-monitor/resource-monitor.h +++ b/lib/resource-monitor/resource-monitor.h @@ -134,6 +134,9 @@ extern "C" { #define PROCESS_GROUP_ATTR_DISK_WRITE_BPS BIT(4) /* DATA_TYPE_UINT */ #define PROCESS_GROUP_ATTR_MEM_VIRT BIT(5) /* DATA_TYPE_UINT64 */ #define PROCESS_GROUP_ATTR_MEM_RSS BIT(6) /* DATA_TYPE_UINT64 */ +#define PROCESS_GROUP_ATTR_MEM_PSS BIT(7) /* DATA_TYPE_UINT64 */ +#define PROCESS_GROUP_ATTR_MEM_SWAP BIT(8) /* DATA_TYPE_UINT64 */ +#define PROCESS_GROUP_ATTR_MEM_SWAP_PSS BIT(9) /* DATA_TYPE_UINT64 */ #define PROCESS_GROUP_CTRL_ROOT_PID BIT(0) diff --git a/src/resource/resource-process-group.c b/src/resource/resource-process-group.c index caab3a0..81565e0 100644 --- a/src/resource/resource-process-group.c +++ b/src/resource/resource-process-group.c @@ -41,6 +41,9 @@ struct process_group_context { u_int64_t mem_virt; u_int32_t disk_rbps; u_int32_t disk_wbps; + u_int64_t mem_pss; + u_int64_t mem_swap; + u_int64_t mem_swap_pss; } info; u_int64_t prev_total_time; }; @@ -174,15 +177,20 @@ static int process_group_get_mem(const struct resource *res, switch (attr->id) { case PROCESS_GROUP_ATTR_MEM_RSS: - { *mem = ctx->info.mem_rss; break; - } case PROCESS_GROUP_ATTR_MEM_VIRT: - { *mem = ctx->info.mem_virt; break; - } + case PROCESS_GROUP_ATTR_MEM_PSS: + *mem = ctx->info.mem_pss; + break; + case PROCESS_GROUP_ATTR_MEM_SWAP: + *mem = ctx->info.mem_swap; + break; + case PROCESS_GROUP_ATTR_MEM_SWAP_PSS: + *mem = ctx->info.mem_swap_pss; + break; default: return -EINVAL; } @@ -227,8 +235,7 @@ static const struct resource_attribute process_group_attrs[] = { .get = process_group_get_pid_list, .is_supported = resource_attr_supported_always, }, - }, - { + }, { .name = "PROCESS_GROUP_ATTR_COMM_LIST", .id = PROCESS_GROUP_ATTR_COMM_LIST, .type = DATA_TYPE_ARRAY, @@ -236,8 +243,7 @@ static const struct resource_attribute process_group_attrs[] = { .get = process_group_get_comm_list, .is_supported = resource_attr_supported_always, }, - }, - { + }, { .name = "PROCESS_GROUP_ATTR_CPU_UTIL", .id = PROCESS_GROUP_ATTR_CPU_UTIL, .type = DATA_TYPE_DOUBLE, @@ -277,6 +283,30 @@ static const struct resource_attribute process_group_attrs[] = { .get = process_group_get_mem, .is_supported = resource_attr_supported_always, }, + }, { + .name = "PROCESS_GROUP_ATTR_MEM_PSS", + .id = PROCESS_GROUP_ATTR_MEM_PSS, + .type = DATA_TYPE_UINT64, + .ops = { + .get = process_group_get_mem, + .is_supported = resource_attr_supported_always, + }, + }, { + .name = "PROCESS_GROUP_ATTR_MEM_SWAP", + .id = PROCESS_GROUP_ATTR_MEM_SWAP, + .type = DATA_TYPE_UINT64, + .ops = { + .get = process_group_get_mem, + .is_supported = resource_attr_supported_always, + }, + }, { + .name = "PROCESS_GROUP_ATTR_MEM_SWAP_PSS", + .id = PROCESS_GROUP_ATTR_MEM_SWAP_PSS, + .type = DATA_TYPE_UINT64, + .ops = { + .get = process_group_get_mem, + .is_supported = resource_attr_supported_always, + }, }, }; @@ -358,6 +388,7 @@ static int update_aggr_taskstats(struct process_group_context *ctx) { struct process_info_node *node; struct taskstats *prev, *curr; + struct proc_map_info map_info; u_int64_t total_time; int online, nproc; double cpu_period; @@ -399,6 +430,13 @@ static int update_aggr_taskstats(struct process_group_context *ctx) continue; } + ret = kernel_get_thread_group_map_info(&map_info, pid); + if (ret < 0) { + free(curr); + g_hash_table_iter_remove(&iter); + continue; + } + if (cpu_period >= 1E-6) { double util; @@ -416,6 +454,11 @@ static int update_aggr_taskstats(struct process_group_context *ctx) / (curr->ac_etime - prev->ac_etime); ctx->info.disk_wbps += ((curr->write_bytes - prev->write_bytes) * 1000000) / (curr->ac_etime - prev->ac_etime); + + ctx->info.mem_pss += (u_int64_t)map_info.pss * 1024; + ctx->info.mem_swap += (u_int64_t)map_info.swap * 1024; + ctx->info.mem_swap_pss += (u_int64_t)map_info.swap_pss * 1024; + free(prev); node->prev = curr; } -- 2.7.4