diff options
author | Dongwoo Lee <dwoo08.lee@samsung.com> | 2023-01-12 21:39:12 +0900 |
---|---|---|
committer | Dongwoo Lee <dwoo08.lee@samsung.com> | 2023-02-07 09:14:04 -0800 |
commit | 60fc91b3c4d56826ca216341e235c47bcecf36d3 (patch) | |
tree | 04a595f44f17225e19978c36c33c63a8f1b43668 | |
parent | a512645a82743e746463e73271426a57d1a8c3b9 (diff) | |
download | pass-60fc91b3c4d56826ca216341e235c47bcecf36d3.tar.gz pass-60fc91b3c4d56826ca216341e235c47bcecf36d3.tar.bz2 pass-60fc91b3c4d56826ca216341e235c47bcecf36d3.zip |
resource: system: Add MEMORY_PRESSURE_LEVEL attribute
This adds the new attribute for representing pressure level of memory
as follows:
- Name: SYSTEM_ATTR_MEMORY_PRESSURE_LEVEL
- Type: SYSCOMMON_RESMAN_DATA_TYPE_INT
- Description:
this attribute represents the current stall level for memory,
which means how long delays memory allocation due to memory
leakage. The level ranges between 0 and 4 (higher is worse).
Change-Id: Ibdce4a983384743e2316967744ac843a6ebb15e2
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
-rw-r--r-- | lib/resource-monitor/resource-monitor.h | 1 | ||||
-rw-r--r-- | src/resource/resource-system.c | 214 | ||||
-rw-r--r-- | tools/resource-monitor/resource-monitor.c | 2 |
3 files changed, 217 insertions, 0 deletions
diff --git a/lib/resource-monitor/resource-monitor.h b/lib/resource-monitor/resource-monitor.h index 6e0e249..e65bb9f 100644 --- a/lib/resource-monitor/resource-monitor.h +++ b/lib/resource-monitor/resource-monitor.h @@ -118,6 +118,7 @@ extern "C" { #define SYSTEM_ATTR_PER_CPU_SYS_UTIL BIT(5) /* SYSCOMMON_RESMAN_DATA_TYPE_ARRAY(DOUBLE) */ #define SYSTEM_ATTR_POSSIBLE_CPU BIT(6) /* SYSCOMMON_RESMAN_DATA_TYPE_INT */ #define SYSTEM_ATTR_ONLINE_CPU BIT(7) /* SYSCOMMON_RESMAN_DATA_TYPE_INT */ +#define SYSTEM_ATTR_MEMORY_PRESSURE_LEVEL BIT(8) /* SYSCOMMON_RESMAN_DATA_TYPE_INT */ /* Process Resource */ #define PROCESS_ATTR_CPU_UTIL BIT(0) /* SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE */ diff --git a/src/resource/resource-system.c b/src/resource/resource-system.c index 4f90c71..7940663 100644 --- a/src/resource/resource-system.c +++ b/src/resource/resource-system.c @@ -23,15 +23,19 @@ */ #include <glib.h> +#include <unistd.h> +#include <fcntl.h> #include <hal/hal-power.h> #include <util/common.h> #include <util/log.h> #include <util/kernel.h> +#include <util/thread.h> #include <libsyscommon/resource-manager.h> #include <libsyscommon/resource-type.h> +#include <libsyscommon/resource-listener.h> #include <resource-monitor/resource-monitor.h> @@ -40,6 +44,8 @@ struct system_resource_data { int num_online_cpus; struct cpu_stat *prev_cpus; struct cpu_stat *curr_cpus; + int memory_pressure_level; + u_int64_t memory_pressure_last_update; }; static double __calculate_cpu_util(int64_t id, struct cpu_stat *prev, @@ -183,6 +189,201 @@ static int system_get_cpu_num(int resource_id, return 0; } +#define PSI_MEMORY_GLOBAL "/proc/pressure/memory" +#define PSI_TYPE_WARN "some" +#define PSI_TYPE_CRITICAL "full" +#define PSI_EVENT_DEBOUNCE_TIME 2000 /* msec */ +#define PSI_EVENT_RESOLVE_CHECK_RATE 3000 /* msec */ + +enum { + MEM_LEVEL_HIGH, + MEM_LEVEL_MEDIUM, + MEM_LEVEL_LOW, + MEM_LEVEL_CRITICAL, + MEM_LEVEL_OOM, + MEM_LEVEL_MAX, +}; + +struct psi_level_desc { + char *type; + int stall; + int window; + u_int32_t level; +}; + +static struct thread *psi_timer; +static int listener_handles[MEM_LEVEL_MAX]; +static int psi_fds[MEM_LEVEL_MAX]; +static const struct psi_level_desc psi_levels[MEM_LEVEL_MAX] = { + [MEM_LEVEL_MEDIUM] = { + .type = PSI_TYPE_WARN, + .stall = 70000, + .window = 1000000, + .level = MEM_LEVEL_MEDIUM, + }, + [MEM_LEVEL_LOW] = { + .type = PSI_TYPE_WARN, + .stall = 150000, + .window = 1000000, + .level = MEM_LEVEL_LOW, + }, + [MEM_LEVEL_CRITICAL] = { + .type = PSI_TYPE_CRITICAL, + .stall = 70000, + .window = 1000000, + .level = MEM_LEVEL_CRITICAL, + }, + [MEM_LEVEL_OOM] = { + .type = PSI_TYPE_CRITICAL, + .stall = 150000, + .window = 1000000, + .level = MEM_LEVEL_OOM, + } +}; + +static int system_get_memory_pressure_level(int resource_id, + const struct syscommon_resman_resource_attribute *attr, + void *data) +{ + struct system_resource_data *sysdata; + int *pressure_level = (int *)data; + + if (resource_id < 0 || !attr || !data) + return -EINVAL; + + sysdata = syscommon_resman_get_resource_privdata(resource_id); + if (!sysdata) + return -EINVAL; + + *pressure_level = sysdata->memory_pressure_level; + + return 0; +} + +static void system_handle_psi_listener(int resource_id, + const struct syscommon_resman_resource_attribute *attr, + void *data, int listener_type) +{ + struct system_resource_data *sysdata; + struct timeval current; + u_int64_t current_msec; + int memory_pressure_level; + + if (resource_id < 0 || !attr || !data) + return; + + sysdata = syscommon_resman_get_resource_privdata(resource_id); + if (!sysdata) + return; + + memory_pressure_level = *(int *)data; + + /* If event occurs in debounce time, lower level event is ignored. */ + gettimeofday(¤t, NULL); + current_msec = current.tv_sec * 1000 + current.tv_usec / 1000; + if (current_msec - sysdata->memory_pressure_last_update < PSI_EVENT_DEBOUNCE_TIME + && memory_pressure_level <= sysdata->memory_pressure_level) + return; + + sysdata->memory_pressure_level = memory_pressure_level; + sysdata->memory_pressure_last_update = current_msec; +} + +static int +register_memory_pressure_listener(const struct psi_level_desc *desc, int resource_id, + const struct syscommon_resman_resource_attribute *attr) +{ + char desc_str[BUFF_MAX]; + int ret, fd; + + fd = open(PSI_MEMORY_GLOBAL, O_RDWR | O_NONBLOCK); + if (fd < 0) { + _E("failed to open psi node: %s %d", PSI_MEMORY_GLOBAL, errno); + return -errno; + } + + ret = snprintf(desc_str, BUFF_MAX, "%s %d %d", desc->type, desc->stall, desc->window); + if (ret >= BUFF_MAX) { + _E("psi event description overflows"); + ret = -EINVAL; + goto err_close_fd; + } + + ret = write(fd, desc_str, strlen(desc_str) + 1); + if (ret < 0) { + _E("failed to write psi description: %s", desc_str); + ret = -errno; + goto err_close_fd; + } + + ret = syscommon_resman_register_epoll_listener(resource_id, attr, fd, (void *)&desc->level); + if (ret < 0) { + _E("failed to register epoll event"); + goto err_close_fd; + } + + listener_handles[desc->level] = ret; + psi_fds[desc->level] = fd; + + return 0; + +err_close_fd: + close(fd); + + return ret; +} + +static int system_check_memory_pressure_resolved(void *data, void **result) +{ + struct syscommon_resman_resource_attribute dummy_attr; + int mem_level_high = MEM_LEVEL_HIGH; + int resource_id = (int)data; + + system_handle_psi_listener(resource_id, &dummy_attr, + &mem_level_high, SYSCOMMON_RESMAN_LISTENER_TYPE_EPOLL); + + return THREAD_RETURN_CONTINUE; +} + +static int system_init_psi_listener(int resource_id, + const struct syscommon_resman_resource_attribute *attr) +{ + int i, ret; + + ret = create_timer_thread(&psi_timer, PSI_EVENT_RESOLVE_CHECK_RATE, + system_check_memory_pressure_resolved, (void *)resource_id); + if (ret < 0) + return ret; + + for (i = MEM_LEVEL_MEDIUM; i < MEM_LEVEL_MAX; i++) { + ret = register_memory_pressure_listener(&psi_levels[i], resource_id, attr); + if (ret < 0) + return ret; + } + + return 0; +} + +static void system_exit_psi_listener(int resource_id, + const struct syscommon_resman_resource_attribute *attr) +{ + int i; + + for (i = MEM_LEVEL_MEDIUM; i < MEM_LEVEL_MAX; i++) { + if (listener_handles[i]) { + syscommon_resman_unregister_epoll_listener(listener_handles[i]); + listener_handles[i] = 0; + } + + if (psi_fds[i]) { + close(psi_fds[i]); + psi_fds[i] = 0; + } + } + + destroy_thread(psi_timer); +} + static const struct syscommon_resman_resource_attribute system_attrs[] = { { .name = "SYSTEM_ATTR_CPU_UTIL", @@ -248,6 +449,19 @@ static const struct syscommon_resman_resource_attribute system_attrs[] = { .ops = { .get = system_get_cpu_num, } + }, { + .name = "SYSTEM_ATTR_MEMORY_PRESSURE_LEVEL", + .id = SYSTEM_ATTR_MEMORY_PRESSURE_LEVEL, + .type = SYSCOMMON_RESMAN_DATA_TYPE_INT, + .flag = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC, + .ops = { + .get = system_get_memory_pressure_level, + }, + .listener_ops = { + .init = system_init_psi_listener, + .exit = system_exit_psi_listener, + .action = system_handle_psi_listener, + } }, }; diff --git a/tools/resource-monitor/resource-monitor.c b/tools/resource-monitor/resource-monitor.c index 815fd4d..3b0d6c8 100644 --- a/tools/resource-monitor/resource-monitor.c +++ b/tools/resource-monitor/resource-monitor.c @@ -118,6 +118,8 @@ static struct syscommon_resman_resource_attr_data system_attrs[] = { { .id = SYSTEM_ATTR_PER_CPU_SYS_UTIL, .type = SYSCOMMON_RESMAN_DATA_TYPE_ARRAY, .name = "SYSTEM_ATTR_PER_CPU_SYS_UTIL", .unit = "%", .desc = "Per-CPU utilization on system", .array_type = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE, }, { .id = SYSTEM_ATTR_POSSIBLE_CPU, .type = SYSCOMMON_RESMAN_DATA_TYPE_INT, .name = "SYSTEM_ATTR_POSSIBLE_CPU", .unit = "ea", .desc = "Number of possible CPU", }, { .id = SYSTEM_ATTR_ONLINE_CPU, .type = SYSCOMMON_RESMAN_DATA_TYPE_INT, .name = "SYSTEM_ATTR_ONLINE_CPU", .unit = "ea", .desc = "Number of online CPU", }, + { .id = SYSTEM_ATTR_MEMORY_PRESSURE_LEVEL, .type = SYSCOMMON_RESMAN_DATA_TYPE_INT, .name = "MEMORY_ATTR_PRESSURE_LEVEL", .unit = "lv", .desc = "Level of memory pressure", }, + }; struct syscommon_resman_resource_attr_data process_attrs[] = { |