From e032d2cb1a2ce83d6483f78b93208c1ff90e9f93 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 17 Feb 2022 13:12:49 +0900 Subject: [PATCH 01/16] resource: Add battery resource driver Add battery resouce driver which read the Linux standard power_supply interface to get the battery information. [Detailed description of battery attributes] - BATTERY_CAPACITY indicates the SoC (State of Charging)and unit is %. - BATTERY_STATUS indicates the charging status. - BATTERY_TEMPERATURE indicates the battery temperature. - BATTERY_VOLTAGE_NOW indicates the voltage value now. - BATTERY_CURRENT_NOW indicates the current value now. - BATTERY_PRESENT indicates the connection status of battery. - BATTERY_ONLINE indicates the connection status of charging cable. Change-Id: I6011e155d3e401f82538abbccba7ba02e33d796b Signed-off-by: Chanwoo Choi --- CMakeLists.txt | 1 + lib/tmonitor/tmonitor.h | 6 +- src/resource/resource-battery.c | 156 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 src/resource/resource-battery.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cbd328..9cc70e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ SET(SRCS src/resource/resource-memory.c src/resource/resource-display.c src/resource/resource-system.c + src/resource/resource-battery.c src/monitor/monitor.c src/monitor/monitor-thread.c src/monitor/monitor-command.c diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index 890f0b3..d4d2fb1 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -72,8 +72,12 @@ extern "C" { #define MEMORY_FAULT_AROUND_BYTES BIT(3) #define BATTERY_CAPACITY BIT(0) -#define BATTERY_CHARGING_STATUS BIT(1) +#define BATTERY_STATUS BIT(1) #define BATTERY_TEMPERATURE BIT(2) +#define BATTERY_VOLTAGE_NOW BIT(3) +#define BATTERY_CURRENT_NOW BIT(4) +#define BATTERY_PRESENT BIT(5) +#define BATTERY_ONLINE BIT(6) #define DISPLAY_FPS BIT(0) diff --git a/src/resource/resource-battery.c b/src/resource/resource-battery.c new file mode 100644 index 0000000..0e2364c --- /dev/null +++ b/src/resource/resource-battery.c @@ -0,0 +1,156 @@ +/* + * PASS (Power Aware System Service) - Battery Resource Driver + * + * 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. + */ + +/** + * @file resource-battery.c + * @brief TBD + * @ingroup TBD + */ + +#include + +#include +#include +#include + +#include + +static int battery_get_info(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + char *path = NULL; + int ret, val = 0; + + if (!res || !attr || !data) + return -EINVAL; + + switch (attr->id) { + case BATTERY_CAPACITY: + path = "/sys/class/power_supply/battery/capacity"; + break; + case BATTERY_TEMPERATURE: + path = "/sys/class/power_supply/battery/temp"; + break; + case BATTERY_VOLTAGE_NOW: + path = "/sys/class/power_supply/battery/voltage_now"; + break; + case BATTERY_CURRENT_NOW: + path = "/sys/class/power_supply/battery/current_now"; + break; + case BATTERY_PRESENT: + path = "/sys/class/power_supply/battery/present"; + break; + case BATTERY_ONLINE: + path = "/sys/class/power_supply/battery/online"; + break; + default: + return -EINVAL; + } + + ret = sysfs_get_int(path, &val); + if (ret < 0) + return ret; + + *data = (void *)(intptr_t)val; + + return 0; +} + +static int battery_get_status(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + char buf[BUFF_MAX]; + int ret; + + if (!res || !attr || !data) + return -EINVAL; + + ret = sys_get_str("/sys/class/power_supply/battery/status", buf); + if (ret < 0) + return ret; + + *data = strdup(buf); + if (!*data) + return -ENOMEM; + + return 0; +} + +static const struct resource_attribute battery_attrs[] = { + { + .name = "BATTERY_CAPACITY", + .id = BATTERY_CAPACITY, + .type = DATA_TYPE_INT, + .ops = { + .get = battery_get_info, + } + }, { + .name = "BATTERY_STATUS", + .id = BATTERY_STATUS, + .type = DATA_TYPE_STRING, + .ops = { + .get = battery_get_status, + } + }, { + .name = "BATTERY_TEMPERATURE", + .id = BATTERY_TEMPERATURE, + .type = DATA_TYPE_INT, + .ops = { + .get = battery_get_info, + } + }, { + .name = "BATTERY_VOLTAGE_NOW", + .id = BATTERY_VOLTAGE_NOW, + .type = DATA_TYPE_INT, + .ops = { + .get = battery_get_info, + } + }, { + .name = "BATTERY_CURRENT_NOW", + .id = BATTERY_CURRENT_NOW, + .type = DATA_TYPE_INT, + .ops = { + .get = battery_get_info, + } + }, { + .name = "BATTERY_PRESENT", + .id = BATTERY_PRESENT, + .type = DATA_TYPE_INT, + .ops = { + .get = battery_get_info, + } + }, { + .name = "BATTERY_ONLINE", + .id = BATTERY_ONLINE, + .type = DATA_TYPE_INT, + .ops = { + .get = battery_get_info, + } + }, +}; + +static const struct resource_driver battery_resource_driver = { + .name = "BATTERY", + .type = RESOURCE_TYPE_BATTERY, + .attrs = battery_attrs, + .num_attrs = ARRAY_SIZE(battery_attrs), + .flags = RESOURCE_DRIVER_NO_DEVICE, +}; +RESOURCE_DRIVER_REGISTER(&battery_resource_driver) -- 2.7.4 From afd41ae3268076cea0f9438537f7e0852ac0a2d2 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 17 Feb 2022 18:16:05 +0900 Subject: [PATCH 02/16] util: resource: Add missing NULL checking for setting interest mask Change-Id: Ibd91d659b9f0c8fee73114b97fafdde2cd3118a9 Signed-off-by: Chanwoo Choi --- src/util/resource.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/resource.c b/src/util/resource.c index 087f3c3..fedcb71 100644 --- a/src/util/resource.c +++ b/src/util/resource.c @@ -437,10 +437,16 @@ int put_resource_attr_ptr(struct resource *resource, u_int64_t attr_id) void set_resource_attr_interest(struct resource *resource, u_int64_t interest_mask) { + if (!resource) + return; + resource->attr_interest |= interest_mask; } void unset_resource_attr_interest(struct resource *resource, u_int64_t interest_mask) { + if (!resource) + return; + resource->attr_interest &= ~interest_mask; } -- 2.7.4 From b67f828d8a39782599e375ab4861fa8dad3250a1 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 4 Feb 2022 15:54:46 +0900 Subject: [PATCH 03/16] resource: Add process resource driver Process resource driver provides information about process using procfs and taskstats. [Detailed description of added system attributes] PROCESS_CPU_UTIL: It shows cpu usage including its all threads. PROCESS_MEM_VIRT: It shows all memory that the process can access, including memory that is swapped out, memory that is allocated, but not used, and memory that is from shared libraries. PROCESS_MEM_RSS: It shows how much memory is allocated to that process and is in RAM. PROCESS_DISK_READ: It shows acutal disk read bytes per second. PROCESS_DISK_WRITE: It shows acutal disk write bytes per second. Change-Id: Iab4a76334fc786f068cbee396f3896184cbfff47 Signed-off-by: Dongwoo Lee --- CMakeLists.txt | 3 + lib/tmonitor/tmonitor.h | 6 + packaging/pass.spec | 1 + src/resource/resource-process.c | 458 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 468 insertions(+) create mode 100644 src/resource/resource-process.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cc70e7..9a04a81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ SET(SRCS src/resource/resource-display.c src/resource/resource-system.c src/resource/resource-battery.c + src/resource/resource-process.c src/monitor/monitor.c src/monitor/monitor-thread.c src/monitor/monitor-command.c @@ -65,6 +66,8 @@ SET(PKG_MODULES gio-unix-2.0 libudev libsystemd + libnl-3.0 + libnl-genl-3.0 json-c hal-api-power ) diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index d4d2fb1..f06e54b 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -90,6 +90,12 @@ extern "C" { #define SYSTEM_POSSIBLE_CPU BIT(6) #define SYSTEM_ONLINE_CPU BIT(7) +#define PROCESS_CPU_UTIL BIT(0) +#define PROCESS_MEM_VIRT BIT(1) +#define PROCESS_MEM_RSS BIT(2) +#define PROCESS_DISK_READ BIT(3) +#define PROCESS_DISK_WRITE BIT(4) + /** * @brief Initialize the tizen monitor * @param[in] Timer period (unit: millisecond, minimum value is 100ms) diff --git a/packaging/pass.spec b/packaging/pass.spec index f21d2b0..0a5aa54 100644 --- a/packaging/pass.spec +++ b/packaging/pass.spec @@ -22,6 +22,7 @@ BuildRequires: pkgconfig(gio-unix-2.0) BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(gmock) BuildRequires: pkgconfig(libudev) +BuildRequires: pkgconfig(libnl-3.0) BuildRequires: pkgconfig(libsystemd) BuildRequires: pkgconfig(json-c) BuildRequires: pkgconfig(hal-api-power) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c new file mode 100644 index 0000000..acdb542 --- /dev/null +++ b/src/resource/resource-process.c @@ -0,0 +1,458 @@ +/* + * PASS (Power Aware System Service) - Process Resource Driver + * + * 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 +#include +#include + +#include + +struct process_context { + pid_t pid; + struct taskstats prev; + struct taskstats curr; + + u_int64_t prev_total_time; + double cpu_period; + int online_cpu; +}; + +static long jiffy; + +static int process_get_cpu_util(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + struct process_context *ctx; + struct taskstats *prev, *curr; + double util = 0.0; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + prev = &ctx->prev; + curr = &ctx->curr; + + if (ctx->cpu_period >= 1E-6) { + util = (double)(curr->ac_utime + curr->ac_stime); + util -= (double)(prev->ac_utime + prev->ac_stime); + util *= (jiffy / (ctx->cpu_period * 10.0)); + + /* + * To obtain precision after converting types between double and + * void pointer, utilization increased 1000 times (0~100000), so + * value should be divided by 1000 at user-side. + */ + util = min(util, 100000.0); + } + + *data = (void *)(intptr_t)(int)util; + + return 0; +} + +static int process_get_mem_virt(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + struct process_context *ctx; + struct taskstats *curr; + double virt; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + curr = &ctx->curr; + + virt = (double)curr->virtmem / (double)curr->ac_stime; + virt *= 1024.0 * 1000.0; + + *data = (void *)(uintptr_t)(int)virt; + + return 0; +} + +static int process_get_mem_rss(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + struct process_context *ctx; + struct taskstats *curr; + double rss; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + curr = &ctx->curr; + + rss = (double)curr->coremem / (double)curr->ac_stime; + rss *= 1024.0 * 1000.0; + + *data = (void *)(intptr_t)(int)rss; + + return 0; +} + +static int process_get_disk_read(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + struct process_context *ctx; + struct taskstats *prev, *curr; + u_int64_t period; + double bps = 0.0; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + prev = &ctx->prev; + curr = &ctx->curr; + + period = curr->ac_etime - prev->ac_etime; + bps = (double)(curr->read_bytes - prev->read_bytes) * 1000000 / period; + + *data = (void *)(intptr_t)(int)bps; + + return 0; +} + +static int process_get_disk_write(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + struct process_context *ctx; + struct taskstats *prev, *curr; + u_int64_t period; + double bps = 0.0; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + prev = &ctx->prev; + curr = &ctx->curr; + + period = curr->ac_etime - prev->ac_etime; + + bps = (double)(curr->write_bytes - prev->write_bytes) * 1000000 / period; + + *data = (void *)(intptr_t)(int)bps; + + return 0; +} + +static const struct resource_attribute process_attrs[] = { + { + .name = "PROCESS_CPU_UTIL", + .id = PROCESS_CPU_UTIL, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_cpu_util, + }, + }, + { + .name = "PROCESS_MEM_VIRT", + .id = PROCESS_MEM_VIRT, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_mem_virt, + }, + }, + { + .name = "PROCESS_MEM_RSS", + .id = PROCESS_MEM_RSS, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_mem_rss, + }, + }, + { + .name = "PROCESS_DISK_READ", + .id = PROCESS_DISK_READ, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_disk_read, + }, + }, + { + .name = "PROCESS_DISK_WRITE", + .id = PROCESS_DISK_WRITE, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_disk_write, + }, + }, +}; + +#define saturatingSub(a, b) (a > b ? a - b : 0) + +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 parse_aggregate_task_stats(struct nlattr *attr, int attr_size, + struct taskstats *stats) +{ + nla_for_each_attr(attr, attr, attr_size, attr_size) { + switch (attr->nla_type) { + case TASKSTATS_TYPE_STATS: + nla_memcpy(stats, attr, sizeof(struct taskstats)); + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int parse_task_stats(struct nl_msg *msg, void *arg) +{ + struct genlmsghdr *hdr = (struct genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *attr = genlmsg_attrdata(hdr, 0); + int remaining = genlmsg_attrlen(hdr, 0); + int ret; + + nla_for_each_attr(attr, attr, remaining, remaining) { + switch (attr->nla_type) { + case TASKSTATS_TYPE_AGGR_PID: + case TASKSTATS_TYPE_AGGR_TGID: + ret = parse_aggregate_task_stats(nla_data(attr), + nla_len(attr), arg); + if (ret < 0) { + _E("failed to parse netlink message\n"); + return NL_STOP; + } + break; + default: + break; + } + } + return NL_STOP; +} + +static int print_receive_error(struct sockaddr_nl *address, + struct nlmsgerr *error, void *arg) +{ + return NL_STOP; +} + +static int query_taskstats(struct taskstats *stats, int cmd_type, pid_t pid) +{ + struct nl_sock *sock; + struct nl_msg *msg; + struct nl_cb *cb; + int ret; + + sock = nl_socket_alloc(); + if (!sock) + return -ENOMEM; + + ret = genl_connect(sock); + if (ret < 0) + goto err_free_sock; + + ret = genl_ctrl_resolve(sock, TASKSTATS_GENL_NAME); + if (ret < 0) + goto err_genl_close; + + msg = nlmsg_alloc(); + if (!msg) { + ret = -ENOMEM; + goto err_genl_close; + } + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ret, 0, 0, TASKSTATS_CMD_GET, TASKSTATS_VERSION); + + nla_put_u32(msg, cmd_type, pid); + + ret = nl_send_auto_complete(sock, msg); + nlmsg_free(msg); + if (ret < 0) + goto err_genl_close; + + cb = nl_cb_get(nl_cb_alloc(NL_CB_CUSTOM)); + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, &parse_task_stats, stats); + nl_cb_err(cb, NL_CB_CUSTOM, &print_receive_error, NULL); + + ret = nl_recvmsgs(sock, cb); + nl_cb_put(cb); + if (ret < 0) + goto err_genl_close; + + nl_close(sock); + nl_socket_free(sock); + + return 0; + +err_genl_close: + nl_close(sock); +err_free_sock: + nl_socket_free(sock); + + return ret; +} + +static int update_taskstats(struct process_context *ctx) +{ + struct taskstats stats, *curr = &ctx->curr; + struct dirent *task_entry; + DIR *task_dir; + char task_dir_path[BUFF_MAX]; + pid_t pid; + int ret; + + memset(curr, 0, sizeof(struct taskstats)); + + sprintf(task_dir_path, "/proc/%d/task/", ctx->pid); + + task_dir = opendir(task_dir_path); + if (!task_dir) + return -ESRCH; + + while ((task_entry = readdir(task_dir)) != NULL) { + const char *name = task_entry->d_name; + + if (task_entry->d_type != DT_DIR && task_entry->d_type != DT_UNKNOWN) + continue; + + if (name[0] < '0' || name[0] > '9') + continue; + + pid = strtoul(name, NULL, 10); + + ret = query_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, pid); + if (ret < 0) + /* threads can be removed before get taskstats */ + continue; + + curr->ac_utime += stats.ac_utime; + curr->ac_stime += stats.ac_stime; + curr->ac_etime += stats.ac_etime; + curr->virtmem += stats.virtmem; + curr->coremem += stats.coremem; + curr->read_bytes += stats.read_bytes; + curr->write_bytes += stats.write_bytes; + } + + closedir(task_dir); + + return 0; +} + +static int process_prepare_update(struct resource *res) +{ + struct process_context *ctx = res->priv; + u_int64_t total_time; + int ret, online; + + memcpy(&ctx->prev, &ctx->curr, sizeof(struct taskstats)); + + ret = update_taskstats(ctx); + if (ret < 0) + return ret; + + online = kernel_get_online_cpu_num(); + total_time = get_total_cpu_time(); + + ctx->online_cpu = online; + ctx->cpu_period = (double)saturatingSub(total_time, ctx->prev_total_time) / online; + ctx->prev_total_time = total_time; + + return 0; +} + +static int process_init(struct resource *res) +{ + struct process_context *ctx; + int ret; + + if (jiffy == 0) { + /* get system USER_HZ at once */ + jiffy = sysconf(_SC_CLK_TCK); + if (jiffy < 0) + return -EINVAL; + } + + ctx = calloc(1, sizeof(struct process_context)); + if (!ctx) + return -ENOMEM; + + ctx->prev_total_time = get_total_cpu_time(); + ctx->pid = (pid_t)(intptr_t)res->user_data; + + /* update initial status */ + ret = update_taskstats(ctx); + if (ret < 0) { + free(ctx); + return -EINVAL; + } + + res->priv = ctx; + + return 0; +} + +static void process_exit(struct resource *res) +{ + struct process_context *ctx; + + if (res->priv) { + ctx = res->priv; + free(ctx); + res->priv = NULL; + } +} + +static const struct resource_driver process_resource_driver = { + .name = "PROCESS", + .type = RESOURCE_TYPE_PROCESS, + .attrs = process_attrs, + .flags = RESOURCE_DRIVER_NO_DEVICE, + .num_attrs = ARRAY_SIZE(process_attrs), + .ops = { + .init = process_init, + .exit = process_exit, + .prepare_update = process_prepare_update, + }, +}; +RESOURCE_DRIVER_REGISTER(&process_resource_driver) -- 2.7.4 From 12f899171da9cc06f84a29ed074f11e0285c507a Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 21 Feb 2022 16:22:01 +0900 Subject: [PATCH 04/16] resource: process: Handle pid, tgid into parsing nla types To prevent pid, tgid is considered error case, add handling of them. Change-Id: I3ef127312e860f8bf625a8427d5e40cfb68196cc Signed-off-by: Dongwoo Lee --- src/resource/resource-process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index acdb542..aff58e1 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -234,6 +234,9 @@ static int parse_aggregate_task_stats(struct nlattr *attr, int attr_size, { nla_for_each_attr(attr, attr, attr_size, attr_size) { switch (attr->nla_type) { + case TASKSTATS_TYPE_PID: + case TASKSTATS_TYPE_TGID: + break; case TASKSTATS_TYPE_STATS: nla_memcpy(stats, attr, sizeof(struct taskstats)); break; -- 2.7.4 From 085b6e558e1b92f3da18c32bc04d10e9aa7f8214 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 23 Feb 2022 16:58:04 +0900 Subject: [PATCH 05/16] util: kernel: Read stationary values once Since statinary kernel sysfs or procfs nodes is not have to be read every time, it lets them being read once. Change-Id: Icee5f825694867ecb84847fd46830274fe8219d3 Signed-off-by: Dongwoo Lee --- src/util/kernel.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/util/kernel.c b/src/util/kernel.c index 490432f..41c1637 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -105,7 +105,12 @@ int kernel_get_online_cpu_num(void) int kernel_get_possible_cpu_num(void) { - return __get_cpu_num("/sys/devices/system/cpu/possible"); + static int possible = 0; + + if (!possible) + possible = __get_cpu_num("/sys/devices/system/cpu/possible"); + + return possible; } int kernel_get_total_cpu_stat(struct cpu_stat *total) -- 2.7.4 From 8622c74f1e582ee0db8b7e80ac71d76829000646 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 23 Feb 2022 17:39:57 +0900 Subject: [PATCH 06/16] util: kernel: export apis for getting memory info Change-Id: Ibd7c78f61de9ffcc8b9635a42c779af550c61124 Signed-off-by: Dongwoo Lee --- include/util/kernel.h | 3 +++ src/resource/resource-memory.c | 30 +++--------------------------- src/util/kernel.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/include/util/kernel.h b/include/util/kernel.h index ad76c83..4596ff6 100644 --- a/include/util/kernel.h +++ b/include/util/kernel.h @@ -40,4 +40,7 @@ int kernel_get_possible_cpu_num(void); int kernel_get_total_cpu_stat(struct cpu_stat *total); int kernel_get_per_cpu_stat(struct cpu_stat *cpus, int num_possible_cpus, int *num_online_cpus); + +int kernel_get_memory_info(const char *key); +int kernel_get_memory_total(void); #endif diff --git a/src/resource/resource-memory.c b/src/resource/resource-memory.c index 15131b1..6338d7a 100644 --- a/src/resource/resource-memory.c +++ b/src/resource/resource-memory.c @@ -32,42 +32,18 @@ #include -#define PROC_MEM_INFO_PATH "/proc/meminfo" -#define PROC_MEM_INFO_MEM_TOTAL "MemTotal" #define PROC_MEM_INFO_MEM_AVAILABLE "MemAvailable" #define PROC_MEM_INFO_MEM_FREE "MemFree" -static int __memory_read_val_from_proc_node(const char *key) -{ - int ret = -EINVAL; - char buf[BUFF_MAX]; - char str[BUFF_MAX]; - FILE *fp = NULL; - - fp = fopen(PROC_MEM_INFO_PATH, "r"); - if (!fp) - return -EIO; - - while (fgets(buf, BUFF_MAX, fp)) { - if (!strncmp(buf, key, strlen(key))) { - sscanf(buf, "%s %d", str, &ret); - break; - } - } - fclose(fp); - - return ret; -} - static inline int memory_read_val_from_proc_node(uint32_t val_id) { switch (val_id) { case MEMORY_TOTAL: - return __memory_read_val_from_proc_node(PROC_MEM_INFO_MEM_TOTAL); + return kernel_get_memory_total(); case MEMORY_AVAILABLE: - return __memory_read_val_from_proc_node(PROC_MEM_INFO_MEM_AVAILABLE); + return kernel_get_memory_info(PROC_MEM_INFO_MEM_AVAILABLE); case MEMORY_FREE: - return __memory_read_val_from_proc_node(PROC_MEM_INFO_MEM_FREE); + return kernel_get_memory_info(PROC_MEM_INFO_MEM_FREE); } return -EINVAL; } diff --git a/src/util/kernel.c b/src/util/kernel.c index 41c1637..6e9fb36 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -169,3 +169,35 @@ err: return ret; } + +int kernel_get_memory_info(const char *key) +{ + int ret = -EINVAL; + char buf[BUFF_MAX]; + char str[BUFF_MAX]; + FILE *fp = NULL; + + fp = fopen("/proc/meminfo", "r"); + if (!fp) + return -EIO; + + while (fgets(buf, BUFF_MAX, fp)) { + if (!strncmp(buf, key, strlen(key))) { + sscanf(buf, "%s %d", str, &ret); + break; + } + } + fclose(fp); + + return ret; +} + +int kernel_get_memory_total(void) +{ + static u_int64_t mem_total = 0; + + if (!mem_total) + mem_total = kernel_get_memory_info("MemTotal"); + + return mem_total; +} -- 2.7.4 From f59d4b5f6785f808605cd6a72e06ba1d26886405 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 22 Feb 2022 15:21:32 +0900 Subject: [PATCH 07/16] resource: process: Add new PROCESS_COMM and PROCESS_MEM_PERCENT attributes This introduces the new attributes as follows: PROCESS_COMM: shows the name of process. PROCESS_MEM_PERCENT: shows ratio of process rss against system memory. Change-Id: Ia50715204c4195deed3b469798f3626a2ea45d5c Signed-off-by: Dongwoo Lee --- lib/tmonitor/tmonitor.h | 6 +++-- src/resource/resource-process.c | 56 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index f06e54b..5bc637c 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -93,8 +93,10 @@ extern "C" { #define PROCESS_CPU_UTIL BIT(0) #define PROCESS_MEM_VIRT BIT(1) #define PROCESS_MEM_RSS BIT(2) -#define PROCESS_DISK_READ BIT(3) -#define PROCESS_DISK_WRITE BIT(4) +#define PROCESS_MEM_PERCENT BIT(3) +#define PROCESS_DISK_READ BIT(4) +#define PROCESS_DISK_WRITE BIT(5) +#define PROCESS_COMM BIT(6) /** * @brief Initialize the tizen monitor diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index aff58e1..2a2419d 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -30,12 +30,14 @@ struct process_context { pid_t pid; + char comm[TS_COMM_LEN]; struct taskstats prev; struct taskstats curr; u_int64_t prev_total_time; double cpu_period; int online_cpu; + u_int64_t total_memory; }; static long jiffy; @@ -112,7 +114,17 @@ static int process_get_mem_rss(const struct resource *res, rss = (double)curr->coremem / (double)curr->ac_stime; rss *= 1024.0 * 1000.0; - *data = (void *)(intptr_t)(int)rss; + switch (attr->id) { + case PROCESS_MEM_RSS: + *data = (void *)(intptr_t)(int)rss; + break; + case PROCESS_MEM_PERCENT: + /* percentage value should be divided by 1000 at user-side */ + *data = (void *)(intptr_t)(int)((rss / ctx->total_memory) * 100000.0); + break; + default: + return -EINVAL; + } return 0; } @@ -166,6 +178,21 @@ static int process_get_disk_write(const struct resource *res, return 0; } +static int process_get_comm(const struct resource *res, + const struct resource_attribute *attr, + void **data) +{ + struct process_context *ctx; + + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + *data = g_strdup(ctx->comm); + + return 0; +} + static const struct resource_attribute process_attrs[] = { { .name = "PROCESS_CPU_UTIL", @@ -192,6 +219,14 @@ static const struct resource_attribute process_attrs[] = { }, }, { + .name = "PROCESS_MEM_PERCENT", + .id = PROCESS_MEM_PERCENT, + .type = DATA_TYPE_INT, + .ops = { + .get = process_get_mem_rss, + }, + }, + { .name = "PROCESS_DISK_READ", .id = PROCESS_DISK_READ, .type = DATA_TYPE_INT, @@ -207,6 +242,14 @@ static const struct resource_attribute process_attrs[] = { .get = process_get_disk_write, }, }, + { + .name = "PROCESS_COMM", + .id = PROCESS_COMM, + .type = DATA_TYPE_STRING, + .ops = { + .get = process_get_comm, + }, + }, }; #define saturatingSub(a, b) (a > b ? a - b : 0) @@ -406,6 +449,8 @@ static int process_prepare_update(struct resource *res) static int process_init(struct resource *res) { + struct resource *memory; + struct taskstats stats; struct process_context *ctx; int ret; @@ -430,6 +475,15 @@ static int process_init(struct resource *res) return -EINVAL; } + ret = query_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, ctx->pid); + if (ret < 0) { + free(ctx); + return -EINVAL; + } + memcpy(ctx->comm, stats.ac_comm, TS_COMM_LEN); + + ctx->total_memory = kernel_get_memory_total() * 1024ULL; + res->priv = ctx; return 0; -- 2.7.4 From 65881a90959dcfd711863cf96108daf6bcf07b0a Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 23 Feb 2022 18:16:16 +0900 Subject: [PATCH 08/16] pass: Add capability for netlink interface Due to CVE-2011-2494 which prohibits non-privileged users from getting process information via netlink, pass daemon should be executed by root or get capability on NET_ADMIN. To do this, it adds capability into systemd service attribute with cap_net_admin. Change-Id: Iefd4ca98e963b38a038a8c326f3abad996bb81ee Signed-off-by: Dongwoo Lee --- systemd/pass.service.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/systemd/pass.service.in b/systemd/pass.service.in index 13b8bcf..3bd6f96 100644 --- a/systemd/pass.service.in +++ b/systemd/pass.service.in @@ -10,6 +10,8 @@ RestartSec=0 KillSignal=SIGUSR1 User=system_fw Group=system_fw +Capabilities=cap_net_admin=i +SecureBits=keep-caps [Install] WantedBy=delayed.target -- 2.7.4 From 624fd47f44680ed2fdfd94d7a630ca5c679c30f3 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 25 Feb 2022 19:35:46 +0900 Subject: [PATCH 09/16] resource: Fix build warning for memory/process resource driver - Build warning 1 src/resource/resource-memory.c:42:10: warning: implicit declaration of function 'kernel_get_memory_total' [-Wimplicit-function-declaration] [ 11s] 42 | return kernel_get_memory_total(); [ 11s] | ^~~~~~~~~~~~~~~~~~~~~~~ src/resource/resource-memory.c:44:10: warning: implicit declaration of function 'kernel_get_memory_info' [-Wimplicit-function-declaration] [ 11s] 44 | return kernel_get_memory_info(PROC_MEM_INFO_MEM_AVAILABLE); - Build warning 2 src/resource/resource-process.c:452:19: warning: unused variable 'memory' [-Wunused-variable] [ 12s] 452 | struct resource *memory; Change-Id: I2a473453fb02fc7dd1eb8319474fe9e8633ea2a0 Signed-off-by: Chanwoo Choi --- src/resource/resource-memory.c | 1 + src/resource/resource-process.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resource/resource-memory.c b/src/resource/resource-memory.c index 6338d7a..63b8c08 100644 --- a/src/resource/resource-memory.c +++ b/src/resource/resource-memory.c @@ -29,6 +29,7 @@ #include #include #include +#include #include diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index 2a2419d..2eb3cf9 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -449,7 +449,6 @@ static int process_prepare_update(struct resource *res) static int process_init(struct resource *res) { - struct resource *memory; struct taskstats stats; struct process_context *ctx; int ret; -- 2.7.4 From 06e5ef03f922731157f2ba61e2e5c94fb6bf496b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 28 Feb 2022 12:03:36 +0900 Subject: [PATCH 10/16] resource: system: Fix NULL_AFTER_DEREF issue Change-Id: I9d25da863b004e11a71e0a44d7f8a0aebb22bc2c Signed-off-by: Chanwoo Choi --- src/resource/resource-system.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/resource/resource-system.c b/src/resource/resource-system.c index a96dd6b..64b0516 100644 --- a/src/resource/resource-system.c +++ b/src/resource/resource-system.c @@ -81,12 +81,14 @@ static int system_get_avg_cpu_util(const struct resource *res, const struct resource_attribute *attr, void **data) { - struct system_resouce_data *sysdata = (struct system_resouce_data *)res->priv; + struct system_resouce_data *sysdata; double util; - if (!res || !attr || !data) + if (!res || !res->priv ||!attr || !data) return -EINVAL; + sysdata = (struct system_resouce_data *)res->priv; + util = __calculate_cpu_util(attr->id, &sysdata->prev_avg, &sysdata->curr_avg); if (util < 0) { _W("failed to calculate average cpu util (%s.%d: %s)\n", @@ -102,13 +104,16 @@ static int system_get_per_cpu_util(const struct resource *res, const struct resource_attribute *attr, void **data) { - struct system_resouce_data *sysdata = (struct system_resouce_data *)res->priv; + struct system_resouce_data *sysdata; struct array_value *array; double *utils; int i; - if (!res || !attr || !data) + if (!res || !res->priv ||!attr || !data) return -EINVAL; + + sysdata = (struct system_resouce_data *)res->priv; + array = calloc(1, sizeof(*array)); if (!array) return -ENOMEM; -- 2.7.4 From c2f5ed192c6f6d9a1e3892a59cd5a31586ddb033 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Mon, 28 Feb 2022 12:42:53 +0900 Subject: [PATCH 11/16] resource: system: avoid possible use-after-free in error path In error path, assigned pointer is not cleared after free. Fix to avoid possible use-after-free with the not cleared pointer. Change-Id: Idaa222afc9660e68cc5021bd251f21cd47e30b97 Signed-off-by: Seung-Woo Kim --- src/resource/resource-system.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resource/resource-system.c b/src/resource/resource-system.c index 64b0516..2538ed0 100644 --- a/src/resource/resource-system.c +++ b/src/resource/resource-system.c @@ -235,7 +235,6 @@ static int system_driver_init(struct resource *res) sysdata = calloc(1, sizeof(struct system_resouce_data)); if (!sysdata) return -ENOMEM; - res->priv = (void *)sysdata; ret = kernel_get_possible_cpu_num(); if (ret < 0) { @@ -263,6 +262,8 @@ static int system_driver_init(struct resource *res) goto err_prev_cpus; } + res->priv = (void *)sysdata; + return 0; err_prev_cpus: @@ -270,7 +271,6 @@ err_prev_cpus: err: sysdata->num_possible_cpus = 0; free(sysdata); - sysdata = NULL; return ret; } -- 2.7.4 From dd6dcd13b9e73e950d697a4d3c9d6e8b065c90c0 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 28 Feb 2022 14:41:36 +0900 Subject: [PATCH 12/16] util: kernel: Fix STATIC_OVERFLOW issue Change-Id: Ic8118a695865913f06da029a47278cccfd266c09 Signed-off-by: Chanwoo Choi --- src/util/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/kernel.c b/src/util/kernel.c index 6e9fb36..a23c40e 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -61,7 +61,7 @@ static int __get_cpu_stat(FILE *fp, struct cpu_stat *data) if (!fp || !data) return -EINVAL; - ret = fscanf(fp, "%s %"PRId64" %"PRId64" %"PRId64" %"PRId64" \ + ret = fscanf(fp, "%7s %"PRId64" %"PRId64" %"PRId64" %"PRId64" \ %"PRId64" %"PRId64" %"PRId64" %*s %*s %*s", data->name, &data->user, -- 2.7.4 From 63fc1facfdcc5c0a3ac723cd3d3142bc307611f6 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 28 Feb 2022 12:46:25 +0900 Subject: [PATCH 13/16] resource: Distinguish signed/unsigned and 32/64 bits integer data types To provide clients with the precise integer values, now support the new data types: - DATA_TYPE_INT(32-bit signed integer), - DATA_TPYE_INT64(64-bit signed integer), - DATA_TYPE_UINT(32-bit unsigned integer), - DATA_TPYE_UINT64(64-bit unsigned integer), Change-Id: I8f70fb38a1fd9876b53d52c2f7592120fc0f9b5c Signed-off-by: Dongwoo Lee --- include/util/resource.h | 8 +++++++- src/util/resource.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/include/util/resource.h b/include/util/resource.h index 00da7f5..a2d3765 100644 --- a/include/util/resource.h +++ b/include/util/resource.h @@ -27,6 +27,9 @@ enum monitor_data_type { DATA_TYPE_UNKNOWN = 0, DATA_TYPE_INT, + DATA_TYPE_INT64, + DATA_TYPE_UINT, + DATA_TYPE_UINT64, DATA_TYPE_DOUBLE, DATA_TYPE_STRING, DATA_TYPE_ARRAY, @@ -142,7 +145,10 @@ const struct resource_attribute *get_resource_attr(struct resource *resource, u_ struct resource_attribute_value * get_resource_attr_value(struct resource *resource, u_int64_t attr_id); -int get_resource_attr_integer(struct resource *resource, u_int64_t attr_id, int *data); +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); +int get_resource_attr_uint64(struct resource *resource, u_int64_t attr_id, u_int32_t *data); int get_resource_attr_double(struct resource *resource, u_int64_t attr_id, double *data); int get_resource_attr_string(struct resource *resource, u_int64_t attr_id, char **data); int put_resource_attr_string(struct resource *resource, u_int64_t attr_id); diff --git a/src/util/resource.c b/src/util/resource.c index fedcb71..fc342f4 100644 --- a/src/util/resource.c +++ b/src/util/resource.c @@ -296,7 +296,7 @@ static bool check_attr_validate(struct resource *resource, u_int64_t attr_id, in return true; } -int get_resource_attr_integer(struct resource *resource, u_int64_t attr_id, int *data) +int get_resource_attr_int(struct resource *resource, u_int64_t attr_id, int32_t *data) { struct resource_attribute_value *attr_value = NULL; @@ -307,7 +307,55 @@ int get_resource_attr_integer(struct resource *resource, u_int64_t attr_id, int if (!attr_value) return -EINVAL; - *data = (int)(intptr_t)attr_value->data; + *data = (int32_t)(intptr_t)attr_value->data; + + return 0; +} + +int get_resource_attr_int64(struct resource *resource, u_int64_t attr_id, int64_t *data) +{ + struct resource_attribute_value *attr_value = NULL; + + if (!check_attr_validate(resource, attr_id, DATA_TYPE_INT)) + return -EINVAL; + + attr_value = get_resource_attr_value(resource, attr_id); + if (!attr_value) + return -EINVAL; + + *data = (int64_t)(intptr_t)attr_value->data; + + return 0; +} + +int get_resource_attr_uint(struct resource *resource, u_int64_t attr_id, u_int32_t *data) +{ + struct resource_attribute_value *attr_value = NULL; + + if (!check_attr_validate(resource, attr_id, DATA_TYPE_INT)) + return -EINVAL; + + attr_value = get_resource_attr_value(resource, attr_id); + if (!attr_value) + return -EINVAL; + + *data = (u_int32_t)(intptr_t)attr_value->data; + + return 0; +} + +int get_resource_attr_uint64(struct resource *resource, u_int64_t attr_id, u_int32_t *data) +{ + struct resource_attribute_value *attr_value = NULL; + + if (!check_attr_validate(resource, attr_id, DATA_TYPE_INT)) + return -EINVAL; + + attr_value = get_resource_attr_value(resource, attr_id); + if (!attr_value) + return -EINVAL; + + *data = (u_int64_t)(intptr_t)attr_value->data; return 0; } -- 2.7.4 From f04876dfced39bf68e11ae0b04fef85da3a652dc Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 28 Feb 2022 14:29:14 +0900 Subject: [PATCH 14/16] util: kernel: Use 64-bit unsigned integer for memory information Since memory information node of kernel can be presented with 32-bit signed variable as maximum 2GB, to overcome this limitation, this changes related functions using 64-bit unsigned integer variable. Change-Id: Id1b1da468ca5e7c98cd65318c854cd5a98ae2086 Signed-off-by: Dongwoo Lee --- include/util/kernel.h | 4 ++-- src/resource/resource-memory.c | 46 ++++++++++++++++++++++++++--------------- src/resource/resource-process.c | 8 +++++-- src/util/kernel.c | 27 ++++++++++++++++-------- 4 files changed, 55 insertions(+), 30 deletions(-) diff --git a/include/util/kernel.h b/include/util/kernel.h index 4596ff6..f268e93 100644 --- a/include/util/kernel.h +++ b/include/util/kernel.h @@ -41,6 +41,6 @@ int kernel_get_total_cpu_stat(struct cpu_stat *total); int kernel_get_per_cpu_stat(struct cpu_stat *cpus, int num_possible_cpus, int *num_online_cpus); -int kernel_get_memory_info(const char *key); -int kernel_get_memory_total(void); +int kernel_get_memory_info(const char *key, u_int64_t *val); +int kernel_get_memory_total(u_int64_t *val); #endif diff --git a/src/resource/resource-memory.c b/src/resource/resource-memory.c index 63b8c08..f376feb 100644 --- a/src/resource/resource-memory.c +++ b/src/resource/resource-memory.c @@ -36,30 +36,40 @@ #define PROC_MEM_INFO_MEM_AVAILABLE "MemAvailable" #define PROC_MEM_INFO_MEM_FREE "MemFree" -static inline int memory_read_val_from_proc_node(uint32_t val_id) +static inline int memory_read_val_from_proc_node(uint32_t val_id, u_int64_t *val) { + int ret; + switch (val_id) { case MEMORY_TOTAL: - return kernel_get_memory_total(); + ret = kernel_get_memory_total(val); + break; case MEMORY_AVAILABLE: - return kernel_get_memory_info(PROC_MEM_INFO_MEM_AVAILABLE); + ret = kernel_get_memory_info(PROC_MEM_INFO_MEM_AVAILABLE, val); + break; case MEMORY_FREE: - return kernel_get_memory_info(PROC_MEM_INFO_MEM_FREE); + ret = kernel_get_memory_info(PROC_MEM_INFO_MEM_FREE, val); + break; + default: + _E("wrong memory resource attribute\n"); + ret = -EINVAL; } - return -EINVAL; + + return ret; } static int memory_get_total_memory(const struct resource *res, const struct resource_attribute *attr, void **data) { - int val; + u_int64_t val; + int ret; if (!res || !attr || !data) return -EINVAL; - val = memory_read_val_from_proc_node(attr->id); - if (val < 0) + ret = memory_read_val_from_proc_node(attr->id, &val); + if (ret < 0) return -EINVAL; *data = (void *)(intptr_t)val; @@ -71,13 +81,14 @@ static int memory_get_available_memory(const struct resource *res, const struct resource_attribute *attr, void **data) { - int val; + u_int64_t val; + int ret; if (!res || !attr || !data) return -EINVAL; - val = memory_read_val_from_proc_node(attr->id); - if (val < 0) + ret = memory_read_val_from_proc_node(attr->id, &val); + if (ret < 0) return -EINVAL; *data = (void *)(intptr_t)val; @@ -89,13 +100,14 @@ static int memory_get_free_memory(const struct resource *res, const struct resource_attribute *attr, void **data) { - int val; + u_int64_t val; + int ret; if (!res || !attr || !data) return -EINVAL; - val = memory_read_val_from_proc_node(attr->id); - if (val < 0) + ret = memory_read_val_from_proc_node(attr->id, &val); + if (ret < 0) return -EINVAL; *data = (void *)(intptr_t)val; @@ -107,21 +119,21 @@ static const struct resource_attribute memory_attrs[] = { { .name = "MEMORY_TOTAL", .id = MEMORY_TOTAL, - .type = DATA_TYPE_INT, + .type = DATA_TYPE_UINT64, .ops = { .get = memory_get_total_memory, }, }, { .name = "MEMORY_AVAILABLE", .id = MEMORY_AVAILABLE, - .type = DATA_TYPE_INT, + .type = DATA_TYPE_UINT64, .ops = { .get = memory_get_available_memory, }, }, { .name = "MEMORY_FREE", .id = MEMORY_FREE, - .type = DATA_TYPE_INT, + .type = DATA_TYPE_UINT64, .ops = { .get = memory_get_free_memory, } diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index 2eb3cf9..4defc09 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -467,6 +467,12 @@ static int process_init(struct resource *res) ctx->prev_total_time = get_total_cpu_time(); ctx->pid = (pid_t)(intptr_t)res->user_data; + ret = kernel_get_memory_total(&ctx->total_memory); + if (ret < 0) { + free(ctx); + return -EINVAL; + } + /* update initial status */ ret = update_taskstats(ctx); if (ret < 0) { @@ -481,8 +487,6 @@ static int process_init(struct resource *res) } memcpy(ctx->comm, stats.ac_comm, TS_COMM_LEN); - ctx->total_memory = kernel_get_memory_total() * 1024ULL; - res->priv = ctx; return 0; diff --git a/src/util/kernel.c b/src/util/kernel.c index a23c40e..a68e05b 100644 --- a/src/util/kernel.c +++ b/src/util/kernel.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -170,11 +171,9 @@ err: return ret; } -int kernel_get_memory_info(const char *key) +int kernel_get_memory_info(const char *key, u_int64_t *val) { - int ret = -EINVAL; char buf[BUFF_MAX]; - char str[BUFF_MAX]; FILE *fp = NULL; fp = fopen("/proc/meminfo", "r"); @@ -183,21 +182,31 @@ int kernel_get_memory_info(const char *key) while (fgets(buf, BUFF_MAX, fp)) { if (!strncmp(buf, key, strlen(key))) { - sscanf(buf, "%s %d", str, &ret); + sscanf(buf, "%*s %"PRIu64, val); + if (strstr(buf, "kB")) + *val *= 1024; break; } } fclose(fp); - return ret; + return 0; } -int kernel_get_memory_total(void) +int kernel_get_memory_total(u_int64_t *val) { static u_int64_t mem_total = 0; + int ret; - if (!mem_total) - mem_total = kernel_get_memory_info("MemTotal"); + if (!mem_total) { + ret = kernel_get_memory_info("MemTotal", &mem_total); + if (ret < 0) { + _E("failed to get system total memory\n"); + return -EINVAL; + } + } + + *val = mem_total; - return mem_total; + return 0; } -- 2.7.4 From 0b850329ce67e3059557625343824e64d8648b6c Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 28 Feb 2022 18:02:10 +0900 Subject: [PATCH 15/16] util: thread: Support free function for destorying queue Since lock-free queue can have various data type, users can pass free function when creating queue along with the corresponding data type in queue. Change-Id: I4ede38bd6e36a1622bb39c7183829c5372e3264b Signed-off-by: Dongwoo Lee --- include/util/queue.h | 3 ++- src/monitor/monitor-thread.c | 2 +- src/util/queue.c | 11 +++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/util/queue.h b/include/util/queue.h index 23b8331..2fdae3b 100644 --- a/include/util/queue.h +++ b/include/util/queue.h @@ -44,6 +44,7 @@ struct queue_node { struct queue { struct queue_node *head; struct queue_node *tail; + void (*free_func)(void *data); }; static inline void cpu_relax(void) @@ -53,7 +54,7 @@ static inline void cpu_relax(void) int enqueue(struct queue *queue, void *data); int dequeue(struct queue *queue, void **data); -int create_queue(struct queue **queue); +int create_queue(struct queue **queue, void (*free_func)(void *data)); void destroy_queue(struct queue *queue); #endif diff --git a/src/monitor/monitor-thread.c b/src/monitor/monitor-thread.c index e8a3b12..8cd535a 100644 --- a/src/monitor/monitor-thread.c +++ b/src/monitor/monitor-thread.c @@ -54,7 +54,7 @@ int monitor_thread_init(struct monitor *monitor) struct queue *queue; int ret; - ret = create_queue(&queue); + ret = create_queue(&queue, free); if (ret < 0) { _E("failed to create command queue\n"); return ret; diff --git a/src/util/queue.c b/src/util/queue.c index ec3819d..1312a2c 100644 --- a/src/util/queue.c +++ b/src/util/queue.c @@ -65,7 +65,7 @@ int dequeue(struct queue *queue, void **data) return 0; } -int create_queue(struct queue **queue) +int create_queue(struct queue **queue, void (*free_func)(void *data)) { struct queue *new_queue; struct queue_node *sentinel; @@ -80,6 +80,7 @@ int create_queue(struct queue **queue) return -ENOMEM; } + new_queue->free_func = free_func; new_queue->head = new_queue->tail = sentinel; new_queue->head->data = NULL; new_queue->head->next = NULL; @@ -91,7 +92,13 @@ int create_queue(struct queue **queue) void destroy_queue(struct queue *queue) { - do { } while (!dequeue(queue, NULL)); + void *data; + + if (queue->free_func) + while (!dequeue(queue, &data)) + queue->free_func(data); + else + do { } while (!dequeue(queue, NULL)); /* freeing remaining sentinel */ free(queue->head); -- 2.7.4 From 1eb3e815b9d4165c92cd6a54814fcaa2e7ef5622 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 24 Feb 2022 20:40:11 +0900 Subject: [PATCH 16/16] resource: Rework resource creation and initialization Change-Id: I386e277a20418b4030d3d5a63dcf10ea15898c6c Signed-off-by: Dongwoo Lee --- include/util/resource.h | 32 +++++++-- lib/tmonitor/tmonitor.h | 10 +++ src/resource/resource-battery.c | 1 - src/resource/resource-bus.c | 151 ++++++++++++++++++++++++++++++++++++---- src/resource/resource-cpu.c | 151 ++++++++++++++++++++++++++++++++++++---- src/resource/resource-display.c | 67 ++++++++++++++++-- src/resource/resource-gpu.c | 151 ++++++++++++++++++++++++++++++++++++---- src/resource/resource-memory.c | 1 - src/resource/resource-process.c | 106 ++++++++++++++++++++++------ src/resource/resource-system.c | 22 ++---- src/util/resource.c | 52 ++++++++------ 11 files changed, 636 insertions(+), 108 deletions(-) diff --git a/include/util/resource.h b/include/util/resource.h index a2d3765..a5057ec 100644 --- a/include/util/resource.h +++ b/include/util/resource.h @@ -68,6 +68,23 @@ struct resource_attribute { const struct resource_attribute_ops ops; }; +struct resource_control; + +struct resource_control_ops { + const int (*set)(const struct resource *res, + const struct resource_control *ctrl, + const void *data); + const int (*get)(const struct resource *res, + const struct resource_control *ctrl, + void **data); +}; + +struct resource_control { + const char name[BUFF_MAX]; + const u_int64_t id; + const struct resource_control_ops ops; +}; + struct resource_driver_ops { int (*init)(struct resource *res); void (*exit)(struct resource *res); @@ -78,15 +95,13 @@ struct resource_driver_ops { int (*prepare_update)(struct resource *res); }; -/* resource driver flags */ -#define RESOURCE_DRIVER_NO_DEVICE BIT32(1) - struct resource_driver { const char *name; const int type; - const int flags; const int num_attrs; const struct resource_attribute *attrs; + const int num_ctrls; + const struct resource_control *ctrls; const struct resource_driver_ops ops; }; @@ -105,13 +120,13 @@ struct resource { char *name; const struct resource_driver *driver; int type; - int index; - void *user_data; void *priv; int num_attrs; const struct resource_attribute *attrs; struct resource_attribute_value *attrs_value; + int num_ctrls; + const struct resource_control *ctrls; u_int64_t attr_interest; }; @@ -136,9 +151,12 @@ int add_resource_device(struct resource_device *resource_device); void remove_resource_device(struct resource_device *resource_device); /* Create/delete resource instance */ -struct resource *create_resource(int resource_type, int resource_index, void *user_data); +struct resource *create_resource(int resource_type); void delete_resource(struct resource *resource); +/* Handle resource control */ +int set_resource_control(struct resource *resource, u_int64_t ctrl_id, const void *data); + /* Handle resource attribute */ int update_resource_attrs(struct resource *resource); const struct resource_attribute *get_resource_attr(struct resource *resource, u_int64_t attr_id); diff --git a/lib/tmonitor/tmonitor.h b/lib/tmonitor/tmonitor.h index 5bc637c..3c4a667 100644 --- a/lib/tmonitor/tmonitor.h +++ b/lib/tmonitor/tmonitor.h @@ -51,6 +51,8 @@ extern "C" { #define CPU_ONLINE_CPU BIT(6) #define CPU_TEMPERATURE BIT(7) +#define CPU_CTRL_CLUSTER_ID BIT(0) + #define BUS_CUR_FREQ BIT(0) #define BUS_MIN_FREQ BIT(1) #define BUS_MAX_FREQ BIT(2) @@ -58,6 +60,8 @@ extern "C" { #define BUS_AVAILABLE_MAX_FREQ BIT(4) #define BUS_CUR_GOVERNOR BIT(5) +#define BUS_CTRL_DEVICE_ID BIT(0) + #define GPU_CUR_FREQ BIT(0) #define GPU_MIN_FREQ BIT(1) #define GPU_MAX_FREQ BIT(2) @@ -66,6 +70,8 @@ extern "C" { #define GPU_CUR_GOVERNOR BIT(5) #define GPU_TEMPERATURE BIT(6) +#define GPU_CTRL_DEVICE_ID BIT(0) + #define MEMORY_TOTAL BIT(0) #define MEMORY_AVAILABLE BIT(1) #define MEMORY_FREE BIT(2) @@ -81,6 +87,8 @@ extern "C" { #define DISPLAY_FPS BIT(0) +#define DISPLAY_CTRL_DEVICE_ID BIT(0) + #define SYSTEM_CPU_UTIL BIT(0) #define SYSTEM_CPU_USER_UTIL BIT(1) #define SYSTEM_CPU_SYS_UTIL BIT(2) @@ -98,6 +106,8 @@ extern "C" { #define PROCESS_DISK_WRITE BIT(5) #define PROCESS_COMM BIT(6) +#define PROCESS_CTRL_TGID BIT(0) + /** * @brief Initialize the tizen monitor * @param[in] Timer period (unit: millisecond, minimum value is 100ms) diff --git a/src/resource/resource-battery.c b/src/resource/resource-battery.c index 0e2364c..d621c37 100644 --- a/src/resource/resource-battery.c +++ b/src/resource/resource-battery.c @@ -151,6 +151,5 @@ static const struct resource_driver battery_resource_driver = { .type = RESOURCE_TYPE_BATTERY, .attrs = battery_attrs, .num_attrs = ARRAY_SIZE(battery_attrs), - .flags = RESOURCE_DRIVER_NO_DEVICE, }; RESOURCE_DRIVER_REGISTER(&battery_resource_driver) diff --git a/src/resource/resource-bus.c b/src/resource/resource-bus.c index f76f047..9ca48d9 100644 --- a/src/resource/resource-bus.c +++ b/src/resource/resource-bus.c @@ -32,16 +32,29 @@ #include +struct bus_context { + char *device_name; + int index; +}; + static int bus_get_cur_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct bus_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; - val = hal_power_dvfs_get_curr_freq(res->type, res->name); + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: BUS_CTRL_DEVICE_ID is not yet initialized\n", res->name); + return -EINVAL; + } + + val = hal_power_dvfs_get_curr_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -54,12 +67,20 @@ static int bus_get_min_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct bus_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; - val = hal_power_dvfs_get_min_freq(res->type, res->name); + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: BUS_CTRL_DEVICE_ID is not yet initialized\n", res->name); + return -EINVAL; + } + + val = hal_power_dvfs_get_min_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -72,12 +93,20 @@ static int bus_get_max_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct bus_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: BUS_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_max_freq(res->type, res->name); + val = hal_power_dvfs_get_max_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -90,12 +119,20 @@ static int bus_get_available_min_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct bus_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: BUS_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_available_min_freq(res->type, res->name); + val = hal_power_dvfs_get_available_min_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -108,12 +145,20 @@ static int bus_get_available_max_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct bus_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: BUS_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_available_max_freq(res->type, res->name); + val = hal_power_dvfs_get_available_max_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -126,13 +171,21 @@ static int bus_get_curr_governor(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct bus_context *ctx; char buf[BUFF_MAX]; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: BUS_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_curr_governor(res->type, res->name, buf); + val = hal_power_dvfs_get_curr_governor(res->type, ctx->device_name, buf); if (val < 0) return -EINVAL; @@ -189,10 +242,84 @@ static const struct resource_attribute bus_attrs[] = { }, }; +static int bus_setup_device_id(const struct resource *res, + const struct resource_control *ctrl, + const void *data) +{ + struct bus_context *ctx; + const struct resource_device *device; + int device_id = (int)(intptr_t)data; + + if (!res || !res->priv || !ctrl) + return -EINVAL; + + device = find_resource_device(res->type, device_id); + if (!device) { + _E("Not available resource: type: %s, index: %d\n", + res->name, device_id); + return -EINVAL; + } + + ctx = res->priv; + + if (ctx->device_name) + free(ctx->device_name); + + ctx->device_name = g_strdup(device->name); + ctx->index = device_id; + + return 0; +} + +static const struct resource_control bus_ctrls[] = { + { + .name = "BUS_CTRL_DEVICE_ID", + .id = BUS_CTRL_DEVICE_ID, + .ops = { + .set = bus_setup_device_id, + }, + }, +}; + +static int bus_init(struct resource *res) +{ + struct bus_context *ctx; + + ctx = calloc(1, sizeof(struct bus_context)); + if (!ctx) + return -ENOMEM; + + res->priv = ctx; + + return 0; +} + +static void bus_exit(struct resource *res) +{ + struct bus_context *ctx; + + if (res && res->priv) { + ctx = res->priv; + if (ctx->device_name) { + free(ctx->device_name); + ctx->device_name = NULL; + } + free(ctx); + res->priv = NULL; + } +} + static const struct resource_driver bus_resource_driver = { .name = "Memory Bus", .type = RESOURCE_TYPE_BUS, .attrs = bus_attrs, .num_attrs = ARRAY_SIZE(bus_attrs), + .ctrls = bus_ctrls, + .num_ctrls = ARRAY_SIZE(bus_ctrls), + .ops = { + .init = bus_init, + .exit = bus_exit, + }, }; RESOURCE_DRIVER_REGISTER(&bus_resource_driver) + diff --git a/src/resource/resource-cpu.c b/src/resource/resource-cpu.c index 8d288f4..9930016 100644 --- a/src/resource/resource-cpu.c +++ b/src/resource/resource-cpu.c @@ -32,16 +32,29 @@ #include +struct cpu_context { + char *device_name; + int index; +}; + static int cpu_get_cur_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct cpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; - val = hal_power_dvfs_get_curr_freq(res->type, res->name); + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: CPU_CTRL_CLUSTER_ID is not yet initialized\n", res->name); + return -EINVAL; + } + + val = hal_power_dvfs_get_curr_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -54,12 +67,20 @@ static int cpu_get_min_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct cpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; - val = hal_power_dvfs_get_min_freq(res->type, res->name); + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: CPU_CTRL_CLUSTER_ID is not yet initialized\n", res->name); + return -EINVAL; + } + + val = hal_power_dvfs_get_min_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -72,12 +93,20 @@ static int cpu_get_max_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct cpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: CPU_CTRL_CLUSTER_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_max_freq(res->type, res->name); + val = hal_power_dvfs_get_max_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -90,12 +119,20 @@ static int cpu_get_available_min_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct cpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: CPU_CTRL_CLUSTER_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_available_min_freq(res->type, res->name); + val = hal_power_dvfs_get_available_min_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -108,12 +145,20 @@ static int cpu_get_available_max_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct cpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: CPU_CTRL_CLUSTER_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_available_max_freq(res->type, res->name); + val = hal_power_dvfs_get_available_max_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -126,13 +171,21 @@ static int cpu_get_curr_governor(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct cpu_context *ctx; char buf[BUFF_MAX]; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: CPU_CTRL_CLUSTER_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_curr_governor(res->type, res->name, buf); + val = hal_power_dvfs_get_curr_governor(res->type, ctx->device_name, buf); if (val < 0) return -EINVAL; @@ -217,10 +270,84 @@ static const struct resource_attribute cpu_attrs[] = { }, }; +static int cpu_setup_cluster_id(const struct resource *res, + const struct resource_control *ctrl, + const void *data) +{ + struct cpu_context *ctx; + const struct resource_device *device; + int resource_index = (int)(intptr_t)data; + + if (!res || !res->priv || !ctrl) + return -EINVAL; + + device = find_resource_device(res->type, resource_index); + if (!device) { + _E("Not available resource: type: %s, index: %d\n", + res->name, resource_index); + return -EINVAL; + } + + ctx = res->priv; + + if (ctx->device_name) + free(ctx->device_name); + + ctx->device_name = g_strdup(device->name); + ctx->index = resource_index; + + return 0; +} + +static const struct resource_control cpu_ctrls[] = { + { + .name = "CPU_CTRL_CLUSTER_ID", + .id = CPU_CTRL_CLUSTER_ID, + .ops = { + .set = cpu_setup_cluster_id, + }, + }, +}; + +static int cpu_init(struct resource *res) +{ + struct cpu_context *ctx; + + ctx = calloc(1, sizeof(struct cpu_context)); + if (!ctx) + return -ENOMEM; + + res->priv = ctx; + + return 0; +} + +static void cpu_exit(struct resource *res) +{ + struct cpu_context *ctx; + + if (res && res->priv) { + ctx = res->priv; + if (ctx->device_name) { + free(ctx->device_name); + ctx->device_name = NULL; + } + free(ctx); + res->priv = NULL; + } +} + static const struct resource_driver cpu_resource_driver = { .name = "CPU", .type = RESOURCE_TYPE_CPU, .attrs = cpu_attrs, .num_attrs = ARRAY_SIZE(cpu_attrs), + .ctrls = cpu_ctrls, + .num_ctrls = ARRAY_SIZE(cpu_ctrls), + .ops = { + .init = cpu_init, + .exit = cpu_exit, + }, }; RESOURCE_DRIVER_REGISTER(&cpu_resource_driver) + diff --git a/src/resource/resource-display.c b/src/resource/resource-display.c index 7210af2..f3b7af9 100644 --- a/src/resource/resource-display.c +++ b/src/resource/resource-display.c @@ -55,11 +55,19 @@ static int display_get_fps(const struct resource *res, GVariant *result, *value; GError *err = NULL; struct display_fps_data fps_data; + int *disp_id; int ret = 0; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; + disp_id = res->priv; + + if (*disp_id < 0) { + _E("%s: DISPLAY_CTRL_DEVICE_ID is not yet initialized\n", res->name); + return -EINVAL; + } + /* Connect dbus interface and receive message */ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); if (err) { @@ -92,13 +100,13 @@ static int display_get_fps(const struct resource *res, /* Parse the received data */ result = g_variant_get_child_value(g_dbus_message_get_body(reply), 0); - if (g_variant_n_children(result) <= res->index) { + if (g_variant_n_children(result) == 0) { fps_data.fps = 0.0; goto out; } /* Get the fps information according to the index of resource_device */ - value = g_variant_get_child_value(result, res->index); + value = g_variant_get_child_value(result, *disp_id); g_variant_get(value, "(usiud)", &fps_data.type, fps_data.output, &fps_data.zpos, &fps_data.window, &fps_data.fps); @@ -127,11 +135,62 @@ static const struct resource_attribute display_attrs[] = { }, }; +static int display_setup_device_id(const struct resource *res, + const struct resource_control *ctrl, + const void *data) +{ + int *disp_id; + + if (!res || !res->priv || !ctrl) + return -EINVAL; + + disp_id = res->priv; + + *disp_id = (int)(intptr_t)data; + + return 0; +} + +static const struct resource_control display_ctrls[] = { + { + .name = "DISPLAY_CTRL_DEVICE_ID", + .id = DISPLAY_CTRL_DEVICE_ID, + .ops = { + .set = display_setup_device_id, + }, + }, +}; + +static int display_init(struct resource *res) +{ + int *disp_id; + + disp_id = malloc(sizeof(int)); + if (!disp_id) + return -ENOMEM; + + *disp_id = -1; + + res->priv = disp_id; + + return 0; +} + +static void display_exit(struct resource *res) +{ + if (res && res->priv) + free(res->priv); +} static const struct resource_driver display_resource_driver = { .name = "DISPLAY", .type = RESOURCE_TYPE_DISPLAY, .attrs = display_attrs, .num_attrs = ARRAY_SIZE(display_attrs), - .flags = RESOURCE_DRIVER_NO_DEVICE, + .ctrls = display_ctrls, + .num_ctrls = ARRAY_SIZE(display_ctrls), + .ops = { + .init = display_init, + .exit = display_exit, + }, }; RESOURCE_DRIVER_REGISTER(&display_resource_driver) diff --git a/src/resource/resource-gpu.c b/src/resource/resource-gpu.c index e7afa19..1c27599 100644 --- a/src/resource/resource-gpu.c +++ b/src/resource/resource-gpu.c @@ -32,16 +32,29 @@ #include +struct gpu_context { + char *device_name; + int index; +}; + static int gpu_get_cur_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct gpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; - val = hal_power_dvfs_get_curr_freq(res->type, res->name); + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: GPU_CTRL_DEVICE_ID is not yet initialized\n", res->name); + return -EINVAL; + } + + val = hal_power_dvfs_get_curr_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -54,12 +67,20 @@ static int gpu_get_min_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct gpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) return -EINVAL; - val = hal_power_dvfs_get_min_freq(res->type, res->name); + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: GPU_CTRL_DEVICE_ID is not yet initialized\n", res->name); + return -EINVAL; + } + + val = hal_power_dvfs_get_min_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -72,12 +93,20 @@ static int gpu_get_max_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct gpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: GPU_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_max_freq(res->type, res->name); + val = hal_power_dvfs_get_available_max_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -90,12 +119,20 @@ static int gpu_get_available_min_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct gpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: GPU_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_available_min_freq(res->type, res->name); + val = hal_power_dvfs_get_available_min_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -108,12 +145,20 @@ static int gpu_get_available_max_freq(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct gpu_context *ctx; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: GPU_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_available_max_freq(res->type, res->name); + val = hal_power_dvfs_get_available_max_freq(res->type, ctx->device_name); if (val < 0) return -EINVAL; @@ -126,13 +171,21 @@ static int gpu_get_curr_governor(const struct resource *res, const struct resource_attribute *attr, void **data) { + struct gpu_context *ctx; char buf[BUFF_MAX]; int val; - if (!res || !attr || !data) + if (!res || !res->priv || !attr || !data) + return -EINVAL; + + ctx = res->priv; + + if (!ctx->device_name) { + _E("%s: GPU_CTRL_DEVICE_ID is not yet initialized\n", res->name); return -EINVAL; + } - val = hal_power_dvfs_get_curr_governor(res->type, res->name, buf); + val = hal_power_dvfs_get_curr_governor(res->type, ctx->device_name, buf); if (val < 0) return -EINVAL; @@ -203,10 +256,84 @@ static const struct resource_attribute gpu_attrs[] = { }, }; +static int gpu_setup_device_id(const struct resource *res, + const struct resource_control *ctrl, + const void *data) +{ + struct gpu_context *ctx; + const struct resource_device *device; + int resource_index = (int)(intptr_t)data; + + if (!res || !res->priv || !ctrl) + return -EINVAL; + + device = find_resource_device(res->type, resource_index); + if (!device) { + _E("Not available resource: type: %s, index: %d\n", + res->name, resource_index); + return -EINVAL; + } + + ctx = res->priv; + + if (ctx->device_name) + free(ctx->device_name); + + ctx->device_name = g_strdup(device->name); + ctx->index = resource_index; + + return 0; +} + +static const struct resource_control gpu_ctrls[] = { + { + .name = "GPU_CTRL_DEVICE_ID", + .id = GPU_CTRL_DEVICE_ID, + .ops = { + .set = gpu_setup_device_id, + }, + }, +}; + +static int gpu_init(struct resource *res) +{ + struct gpu_context *ctx; + + ctx = calloc(1, sizeof(struct gpu_context)); + if (!ctx) + return -ENOMEM; + + res->priv = ctx; + + return 0; +} + +static void gpu_exit(struct resource *res) +{ + struct gpu_context *ctx; + + if (res && res->priv) { + ctx = res->priv; + if (ctx->device_name) { + free(ctx->device_name); + ctx->device_name = NULL; + } + free(ctx); + res->priv = NULL; + } +} + static const struct resource_driver gpu_resource_driver = { .name = "GPU", .type = RESOURCE_TYPE_GPU, .attrs = gpu_attrs, .num_attrs = ARRAY_SIZE(gpu_attrs), + .ctrls = gpu_ctrls, + .num_ctrls = ARRAY_SIZE(gpu_ctrls), + .ops = { + .init = gpu_init, + .exit = gpu_exit, + }, }; RESOURCE_DRIVER_REGISTER(&gpu_resource_driver) + diff --git a/src/resource/resource-memory.c b/src/resource/resource-memory.c index f376feb..74c8fd4 100644 --- a/src/resource/resource-memory.c +++ b/src/resource/resource-memory.c @@ -145,6 +145,5 @@ static const struct resource_driver memory_resource_driver = { .type = RESOURCE_TYPE_MEMORY, .attrs = memory_attrs, .num_attrs = ARRAY_SIZE(memory_attrs), - .flags = RESOURCE_DRIVER_NO_DEVICE, }; RESOURCE_DRIVER_REGISTER(&memory_resource_driver) diff --git a/src/resource/resource-process.c b/src/resource/resource-process.c index 4defc09..1c28294 100644 --- a/src/resource/resource-process.c +++ b/src/resource/resource-process.c @@ -29,7 +29,7 @@ #include struct process_context { - pid_t pid; + pid_t tgid; char comm[TS_COMM_LEN]; struct taskstats prev; struct taskstats curr; @@ -54,6 +54,12 @@ static int process_get_cpu_util(const struct resource *res, return -EINVAL; ctx = res->priv; + + if (!ctx->tgid) { + _E("resource %s is not yet initialized\n", res->name); + return -EINVAL; + } + prev = &ctx->prev; curr = &ctx->curr; @@ -87,6 +93,12 @@ static int process_get_mem_virt(const struct resource *res, return -EINVAL; ctx = res->priv; + + if (!ctx->tgid) { + _E("resource %s is not yet initialized\n", res->name); + return -EINVAL; + } + curr = &ctx->curr; virt = (double)curr->virtmem / (double)curr->ac_stime; @@ -109,6 +121,12 @@ static int process_get_mem_rss(const struct resource *res, return -EINVAL; ctx = res->priv; + + if (!ctx->tgid) { + _E("resource %s is not yet initialized\n", res->name); + return -EINVAL; + } + curr = &ctx->curr; rss = (double)curr->coremem / (double)curr->ac_stime; @@ -142,6 +160,12 @@ static int process_get_disk_read(const struct resource *res, return -EINVAL; ctx = res->priv; + + if (!ctx->tgid) { + _E("resource %s is not yet initialized\n", res->name); + return -EINVAL; + } + prev = &ctx->prev; curr = &ctx->curr; @@ -166,6 +190,12 @@ static int process_get_disk_write(const struct resource *res, return -EINVAL; ctx = res->priv; + + if (!ctx->tgid) { + _E("resource %s is not yet initialized\n", res->name); + return -EINVAL; + } + prev = &ctx->prev; curr = &ctx->curr; @@ -188,6 +218,12 @@ static int process_get_comm(const struct resource *res, return -EINVAL; ctx = res->priv; + + if (!ctx->tgid) { + _E("resource %s is not yet initialized\n", res->name); + return -EINVAL; + } + *data = g_strdup(ctx->comm); return 0; @@ -389,7 +425,7 @@ static int update_taskstats(struct process_context *ctx) memset(curr, 0, sizeof(struct taskstats)); - sprintf(task_dir_path, "/proc/%d/task/", ctx->pid); + sprintf(task_dir_path, "/proc/%d/task/", ctx->tgid); task_dir = opendir(task_dir_path); if (!task_dir) @@ -425,6 +461,51 @@ static int update_taskstats(struct process_context *ctx) return 0; } +static int process_setup_tgid(const struct resource *res, + const struct resource_control *ctrl, + const void *data) +{ + struct taskstats stats; + struct process_context *ctx; + u_int64_t total_memory; + int ret; + + if (!res || !res->priv || !ctrl) + return -EINVAL; + + ctx = res->priv; + + total_memory = ctx->total_memory; + memset(ctx, 0, sizeof(*ctx)); + + ctx->total_memory = total_memory; + ctx->tgid = (pid_t)(intptr_t)data; + ctx->prev_total_time = get_total_cpu_time(); + + /* update initial status */ + ret = update_taskstats(ctx); + if (ret < 0) + return -EINVAL; + + ret = query_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, ctx->tgid); + if (ret < 0) + return -EINVAL; + + memcpy(ctx->comm, stats.ac_comm, TS_COMM_LEN); + + return 0; +} + +static const struct resource_control process_ctrls[] = { + { + .name = "PROCESS_CTRL_TGID", + .id = PROCESS_CTRL_TGID, + .ops = { + .set = process_setup_tgid, + }, + }, +}; + static int process_prepare_update(struct resource *res) { struct process_context *ctx = res->priv; @@ -449,7 +530,6 @@ static int process_prepare_update(struct resource *res) static int process_init(struct resource *res) { - struct taskstats stats; struct process_context *ctx; int ret; @@ -464,29 +544,12 @@ static int process_init(struct resource *res) if (!ctx) return -ENOMEM; - ctx->prev_total_time = get_total_cpu_time(); - ctx->pid = (pid_t)(intptr_t)res->user_data; - ret = kernel_get_memory_total(&ctx->total_memory); if (ret < 0) { free(ctx); return -EINVAL; } - /* update initial status */ - ret = update_taskstats(ctx); - if (ret < 0) { - free(ctx); - return -EINVAL; - } - - ret = query_taskstats(&stats, TASKSTATS_CMD_ATTR_PID, ctx->pid); - if (ret < 0) { - free(ctx); - return -EINVAL; - } - memcpy(ctx->comm, stats.ac_comm, TS_COMM_LEN); - res->priv = ctx; return 0; @@ -507,8 +570,9 @@ static const struct resource_driver process_resource_driver = { .name = "PROCESS", .type = RESOURCE_TYPE_PROCESS, .attrs = process_attrs, - .flags = RESOURCE_DRIVER_NO_DEVICE, .num_attrs = ARRAY_SIZE(process_attrs), + .ctrls = process_ctrls, + .num_ctrls = ARRAY_SIZE(process_ctrls), .ops = { .init = process_init, .exit = process_exit, diff --git a/src/resource/resource-system.c b/src/resource/resource-system.c index 2538ed0..e62b6d2 100644 --- a/src/resource/resource-system.c +++ b/src/resource/resource-system.c @@ -91,8 +91,7 @@ static int system_get_avg_cpu_util(const struct resource *res, util = __calculate_cpu_util(attr->id, &sysdata->prev_avg, &sysdata->curr_avg); if (util < 0) { - _W("failed to calculate average cpu util (%s.%d: %s)\n", - res->name, res->index, attr->name); + _W("failed to calculate average cpu util (%s: %s)\n", res->name, attr->name); util = 0; } *data = (void *)(intptr_t)util; @@ -132,8 +131,7 @@ static int system_get_per_cpu_util(const struct resource *res, &sysdata->prev_cpus[i], &sysdata->curr_cpus[i]); if (utils[i] < 0) { - _W("failed to calculate per-cpu util (%s.%d: %s)\n", - res->name, res->index, attr->name); + _W("failed to calculate per-cpu util (%s: %s)\n", res->name, attr->name); utils[i] = 0; } } @@ -238,8 +236,7 @@ static int system_driver_init(struct resource *res) ret = kernel_get_possible_cpu_num(); if (ret < 0) { - _I("failed to get possible cpu on system driver (%s.%d)\n", - res->name, res->index); + _I("failed to get possible cpu on system driver (%s)\n", res->name); goto err; } sysdata->num_possible_cpus = ret; @@ -247,8 +244,7 @@ static int system_driver_init(struct resource *res) sysdata->prev_cpus = calloc(sysdata->num_possible_cpus, sizeof(struct cpu_stat)); if (!sysdata->prev_cpus) { - _I("failed to allocate memory of prev_cpus (%s.%d)\n", - res->name, res->index); + _I("failed to allocate memory of prev_cpus (%s)\n", res->name); ret = -ENOMEM; goto err; } @@ -256,8 +252,7 @@ static int system_driver_init(struct resource *res) sysdata->curr_cpus = calloc(sysdata->num_possible_cpus, sizeof(struct cpu_stat)); if (!sysdata->curr_cpus) { - _I("failed to allocate memory of curr_cpus (%s.%d)\n", - res->name, res->index); + _I("failed to allocate memory of curr_cpus (%s)\n", res->name); ret = -ENOMEM; goto err_prev_cpus; } @@ -296,8 +291,7 @@ static int system_driver_prepare_update(struct resource *res) memcpy(&sysdata->prev_avg, &sysdata->curr_avg, sizeof(sysdata->prev_avg)); ret = kernel_get_total_cpu_stat(&sysdata->curr_avg); if (ret < 0) { - _I("failed to calculate average cpu util (%s:%d)\n", - res->name, res->index); + _I("failed to calculate average cpu util (%s)\n", res->name); return ret; } @@ -308,8 +302,7 @@ static int system_driver_prepare_update(struct resource *res) sysdata->num_possible_cpus, &sysdata->num_online_cpus); if (ret < 0) { - _I("failed to calculate per-cpu util (%s:%d)\n", - res->name, res->index); + _I("failed to calculate per-cpu util (%s)\n", res->name); return ret; } @@ -321,7 +314,6 @@ static const struct resource_driver system_resource_driver = { .type = RESOURCE_TYPE_SYSTEM, .attrs = system_attrs, .num_attrs = ARRAY_SIZE(system_attrs), - .flags = RESOURCE_DRIVER_NO_DEVICE, .ops = { .init = system_driver_init, .exit = system_driver_exit, diff --git a/src/util/resource.c b/src/util/resource.c index fc342f4..fd14ec4 100644 --- a/src/util/resource.c +++ b/src/util/resource.c @@ -24,7 +24,9 @@ #include #define RESOURCE_ATTR_MASK (ULLONG_MAX) -#define RESOURCE_ATTR_INDEX(id) (63 - __builtin_clzll(id)) +#define BIT64_INDEX(id) (63 - __builtin_clzll(id)) +#define RESOURCE_ATTR_INDEX(id) BIT64_INDEX(id) +#define RESOURCE_CTRL_INDEX(id) BIT64_INDEX(id) static GList *g_resource_driver_head; static GList *g_resource_device_head; @@ -153,10 +155,8 @@ void delete_resource(struct resource *resource) do_delete_resource(resource); } -struct resource *create_resource(int resource_type, int resource_index, - void *user_data) +struct resource *create_resource(int resource_type) { - const struct resource_device *device = NULL; const struct resource_driver *driver = NULL; struct resource *resource = NULL; int i, ret; @@ -165,30 +165,13 @@ struct resource *create_resource(int resource_type, int resource_index, if (!driver) return NULL; - if (!(driver->flags & RESOURCE_DRIVER_NO_DEVICE)) { - device = find_resource_device(resource_type, resource_index); - if (!device) { - _E("Not available resource: type: %d, index: %d\n", - resource_type, resource_index); - return NULL; - } - } - resource = calloc(1, sizeof(*resource)); if (!resource) return NULL; - if (device) { - resource->type = device->type; - resource->name = g_strdup(device->name); - resource->index = device->index; - } else { - resource->type = resource_type; - resource->name = g_strdup(driver->name); - resource->index = resource_index; - } + resource->type = resource_type; + resource->name = g_strdup(driver->name); resource->driver = driver; - resource->user_data = user_data; resource->num_attrs = driver->num_attrs; resource->attrs = driver->attrs; resource->attrs_value = calloc(resource->num_attrs, @@ -201,6 +184,9 @@ struct resource *create_resource(int resource_type, int resource_index, for (i = 0; i < resource->num_attrs; i++) resource->attrs_value[i].type = driver->attrs[i].type; + resource->ctrls = driver->ctrls; + resource->num_ctrls = driver->num_ctrls; + if (driver->ops.init) { ret = driver->ops.init(resource); if (ret < 0) { @@ -212,6 +198,26 @@ struct resource *create_resource(int resource_type, int resource_index, return resource; } +int set_resource_control(struct resource *resource, u_int64_t ctrl_id, const void *data) +{ + const struct resource_control *ctrl; + int ctrl_index = RESOURCE_CTRL_INDEX(ctrl_id); + int ret; + + if (!resource) + return -EINVAL; + + ctrl = &resource->ctrls[ctrl_index]; + if (!ctrl->ops.set) + return -ENOTSUP; + + ret = ctrl->ops.set(resource, ctrl, data); + if (ret < 0) + return ret; + + return 0; +} + static int update_resource_attr(struct resource *resource, u_int64_t attr_id) { int attr_index = RESOURCE_ATTR_INDEX(attr_id); -- 2.7.4