Merge "lmkd: add ability to monitor all vmpressure events"
This commit is contained in:
commit
5422a0cb59
136
lmkd.c
136
lmkd.c
|
|
@ -44,8 +44,6 @@
|
||||||
#define MEMCG_SYSFS_PATH "/dev/memcg/"
|
#define MEMCG_SYSFS_PATH "/dev/memcg/"
|
||||||
#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
|
#define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes"
|
||||||
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
|
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
|
||||||
#define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium"
|
|
||||||
#define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical"
|
|
||||||
#define ZONEINFO_PATH "/proc/zoneinfo"
|
#define ZONEINFO_PATH "/proc/zoneinfo"
|
||||||
#define LINE_MAX 128
|
#define LINE_MAX 128
|
||||||
|
|
||||||
|
|
@ -72,13 +70,22 @@ enum lmk_cmd {
|
||||||
static int use_inkernel_interface = 1;
|
static int use_inkernel_interface = 1;
|
||||||
static bool has_inkernel_module;
|
static bool has_inkernel_module;
|
||||||
|
|
||||||
/* memory pressure level medium event */
|
/* memory pressure levels */
|
||||||
static int mpevfd[2];
|
enum vmpressure_level {
|
||||||
#define CRITICAL_INDEX 1
|
VMPRESS_LEVEL_LOW = 0,
|
||||||
#define MEDIUM_INDEX 0
|
VMPRESS_LEVEL_MEDIUM,
|
||||||
|
VMPRESS_LEVEL_CRITICAL,
|
||||||
|
VMPRESS_LEVEL_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
static int medium_oomadj;
|
static const char *level_name[] = {
|
||||||
static int critical_oomadj;
|
"low",
|
||||||
|
"medium",
|
||||||
|
"critical"
|
||||||
|
};
|
||||||
|
|
||||||
|
static int level_oomadj[VMPRESS_LEVEL_COUNT];
|
||||||
|
static int mpevfd[VMPRESS_LEVEL_COUNT];
|
||||||
static bool debug_process_killing;
|
static bool debug_process_killing;
|
||||||
static bool enable_pressure_upgrade;
|
static bool enable_pressure_upgrade;
|
||||||
static int64_t upgrade_pressure;
|
static int64_t upgrade_pressure;
|
||||||
|
|
@ -90,8 +97,8 @@ static int ctrl_lfd;
|
||||||
static int ctrl_dfd = -1;
|
static int ctrl_dfd = -1;
|
||||||
static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
|
static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
|
||||||
|
|
||||||
/* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
|
/* 3 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */
|
||||||
#define MAX_EPOLL_EVENTS 4
|
#define MAX_EPOLL_EVENTS 5
|
||||||
static int epollfd;
|
static int epollfd;
|
||||||
static int maxevents;
|
static int maxevents;
|
||||||
|
|
||||||
|
|
@ -226,7 +233,7 @@ static int pid_remove(int pid) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writefilestring(char *path, char *s) {
|
static void writefilestring(const char *path, char *s) {
|
||||||
int fd = open(path, O_WRONLY | O_CLOEXEC);
|
int fd = open(path, O_WRONLY | O_CLOEXEC);
|
||||||
int len = strlen(s);
|
int len = strlen(s);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -587,7 +594,8 @@ static struct proc *proc_adj_lru(int oomadj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kill one process specified by procp. Returns the size of the process killed */
|
/* Kill one process specified by procp. Returns the size of the process killed */
|
||||||
static int kill_one_process(struct proc* procp, int min_score_adj, bool is_critical) {
|
static int kill_one_process(struct proc* procp, int min_score_adj,
|
||||||
|
enum vmpressure_level level) {
|
||||||
int pid = procp->pid;
|
int pid = procp->pid;
|
||||||
uid_t uid = procp->uid;
|
uid_t uid = procp->uid;
|
||||||
char *taskname;
|
char *taskname;
|
||||||
|
|
@ -606,12 +614,12 @@ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_criti
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = kill(pid, SIGKILL);
|
||||||
ALOGI(
|
ALOGI(
|
||||||
"Killing '%s' (%d), uid %d, adj %d\n"
|
"Killing '%s' (%d), uid %d, adj %d\n"
|
||||||
" to free %ldkB because system is under %s memory pressure oom_adj %d\n",
|
" to free %ldkB because system is under %s memory pressure oom_adj %d\n",
|
||||||
taskname, pid, uid, procp->oomadj, tasksize * page_k, is_critical ? "critical" : "medium",
|
taskname, pid, uid, procp->oomadj, tasksize * page_k,
|
||||||
min_score_adj);
|
level_name[level], min_score_adj);
|
||||||
r = kill(pid, SIGKILL);
|
|
||||||
pid_remove(pid);
|
pid_remove(pid);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
|
|
@ -626,10 +634,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_criti
|
||||||
* Find a process to kill based on the current (possibly estimated) free memory
|
* Find a process to kill based on the current (possibly estimated) free memory
|
||||||
* and cached memory sizes. Returns the size of the killed processes.
|
* and cached memory sizes. Returns the size of the killed processes.
|
||||||
*/
|
*/
|
||||||
static int find_and_kill_process(bool is_critical) {
|
static int find_and_kill_process(enum vmpressure_level level) {
|
||||||
int i;
|
int i;
|
||||||
int killed_size = 0;
|
int killed_size = 0;
|
||||||
int min_score_adj = is_critical ? critical_oomadj : medium_oomadj;
|
int min_score_adj = level_oomadj[level];
|
||||||
|
|
||||||
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
|
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
|
||||||
struct proc *procp;
|
struct proc *procp;
|
||||||
|
|
@ -638,7 +646,7 @@ retry:
|
||||||
procp = proc_adj_lru(i);
|
procp = proc_adj_lru(i);
|
||||||
|
|
||||||
if (procp) {
|
if (procp) {
|
||||||
killed_size = kill_one_process(procp, min_score_adj, is_critical);
|
killed_size = kill_one_process(procp, min_score_adj, level);
|
||||||
if (killed_size < 0) {
|
if (killed_size < 0) {
|
||||||
goto retry;
|
goto retry;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -674,14 +682,23 @@ static int64_t get_memory_usage(const char* path) {
|
||||||
return mem_usage;
|
return mem_usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_event_common(bool is_critical) {
|
enum vmpressure_level upgrade_level(enum vmpressure_level level) {
|
||||||
|
return (enum vmpressure_level)((level < VMPRESS_LEVEL_CRITICAL) ?
|
||||||
|
level + 1 : level);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum vmpressure_level downgrade_level(enum vmpressure_level level) {
|
||||||
|
return (enum vmpressure_level)((level > VMPRESS_LEVEL_LOW) ?
|
||||||
|
level - 1 : level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_event_common(enum vmpressure_level level) {
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long long evcount;
|
unsigned long long evcount;
|
||||||
int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
|
|
||||||
int64_t mem_usage, memsw_usage;
|
int64_t mem_usage, memsw_usage;
|
||||||
int64_t mem_pressure;
|
int64_t mem_pressure;
|
||||||
|
|
||||||
ret = read(mpevfd[index], &evcount, sizeof(evcount));
|
ret = read(mpevfd[level], &evcount, sizeof(evcount));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ALOGE("Error reading memory pressure event fd; errno=%d",
|
ALOGE("Error reading memory pressure event fd; errno=%d",
|
||||||
errno);
|
errno);
|
||||||
|
|
@ -689,18 +706,19 @@ static void mp_event_common(bool is_critical) {
|
||||||
mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
|
mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
|
||||||
memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
|
memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
|
||||||
if (memsw_usage < 0 || mem_usage < 0) {
|
if (memsw_usage < 0 || mem_usage < 0) {
|
||||||
find_and_kill_process(is_critical);
|
goto do_kill;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate percent for swappinness.
|
// Calculate percent for swappinness.
|
||||||
mem_pressure = (mem_usage * 100) / memsw_usage;
|
mem_pressure = (mem_usage * 100) / memsw_usage;
|
||||||
|
|
||||||
if (enable_pressure_upgrade && !is_critical) {
|
if (enable_pressure_upgrade && level != VMPRESS_LEVEL_CRITICAL) {
|
||||||
// We are swapping too much.
|
// We are swapping too much.
|
||||||
if (mem_pressure < upgrade_pressure) {
|
if (mem_pressure < upgrade_pressure) {
|
||||||
ALOGI("Event upgraded to critical.");
|
level = upgrade_level(level);
|
||||||
is_critical = true;
|
if (debug_process_killing) {
|
||||||
|
ALOGI("Event upgraded to %s", level_name[level]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -708,41 +726,51 @@ static void mp_event_common(bool is_critical) {
|
||||||
// kill any process, since enough memory is available.
|
// kill any process, since enough memory is available.
|
||||||
if (mem_pressure > downgrade_pressure) {
|
if (mem_pressure > downgrade_pressure) {
|
||||||
if (debug_process_killing) {
|
if (debug_process_killing) {
|
||||||
ALOGI("Ignore %s memory pressure", is_critical ? "critical" : "medium");
|
ALOGI("Ignore %s memory pressure", level_name[level]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (is_critical && mem_pressure > upgrade_pressure) {
|
} else if (level == VMPRESS_LEVEL_CRITICAL &&
|
||||||
|
mem_pressure > upgrade_pressure) {
|
||||||
if (debug_process_killing) {
|
if (debug_process_killing) {
|
||||||
ALOGI("Downgrade critical memory pressure");
|
ALOGI("Downgrade critical memory pressure");
|
||||||
}
|
}
|
||||||
// Downgrade event to medium, since enough memory available.
|
// Downgrade event, since enough memory available.
|
||||||
is_critical = false;
|
level = downgrade_level(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (find_and_kill_process(is_critical) == 0) {
|
do_kill:
|
||||||
|
if (find_and_kill_process(level) == 0) {
|
||||||
if (debug_process_killing) {
|
if (debug_process_killing) {
|
||||||
ALOGI("Nothing to kill");
|
ALOGI("Nothing to kill");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_event(uint32_t events __unused) {
|
static void mp_event_low(uint32_t events __unused) {
|
||||||
mp_event_common(false);
|
mp_event_common(VMPRESS_LEVEL_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_event_medium(uint32_t events __unused) {
|
||||||
|
mp_event_common(VMPRESS_LEVEL_MEDIUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mp_event_critical(uint32_t events __unused) {
|
static void mp_event_critical(uint32_t events __unused) {
|
||||||
mp_event_common(true);
|
mp_event_common(VMPRESS_LEVEL_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_mp_common(char *levelstr, void *event_handler, bool is_critical)
|
static bool init_mp_common(void *event_handler, enum vmpressure_level level) {
|
||||||
{
|
|
||||||
int mpfd;
|
int mpfd;
|
||||||
int evfd;
|
int evfd;
|
||||||
int evctlfd;
|
int evctlfd;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
struct epoll_event epev;
|
struct epoll_event epev;
|
||||||
int ret;
|
int ret;
|
||||||
int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX;
|
const char *levelstr = level_name[level];
|
||||||
|
|
||||||
|
if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) {
|
||||||
|
ALOGI("%s pressure events are disabled", levelstr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
|
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC);
|
||||||
if (mpfd < 0) {
|
if (mpfd < 0) {
|
||||||
|
|
@ -783,8 +811,8 @@ static int init_mp_common(char *levelstr, void *event_handler, bool is_critical)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
maxevents++;
|
maxevents++;
|
||||||
mpevfd[mpevfd_index] = evfd;
|
mpevfd[level] = evfd;
|
||||||
return 0;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
close(evfd);
|
close(evfd);
|
||||||
|
|
@ -793,17 +821,7 @@ err_eventfd:
|
||||||
err_open_evctlfd:
|
err_open_evctlfd:
|
||||||
close(mpfd);
|
close(mpfd);
|
||||||
err_open_mpfd:
|
err_open_mpfd:
|
||||||
return -1;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
static int init_mp_medium()
|
|
||||||
{
|
|
||||||
return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init_mp_critical()
|
|
||||||
{
|
|
||||||
return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init(void) {
|
static int init(void) {
|
||||||
|
|
@ -848,10 +866,13 @@ static int init(void) {
|
||||||
if (use_inkernel_interface) {
|
if (use_inkernel_interface) {
|
||||||
ALOGI("Using in-kernel low memory killer interface");
|
ALOGI("Using in-kernel low memory killer interface");
|
||||||
} else {
|
} else {
|
||||||
ret = init_mp_medium();
|
if (!init_mp_common((void *)&mp_event_low, VMPRESS_LEVEL_LOW) ||
|
||||||
ret |= init_mp_critical();
|
!init_mp_common((void *)&mp_event_medium, VMPRESS_LEVEL_MEDIUM) ||
|
||||||
if (ret)
|
!init_mp_common((void *)&mp_event_critical,
|
||||||
|
VMPRESS_LEVEL_CRITICAL)) {
|
||||||
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
|
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
|
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
|
||||||
|
|
@ -892,8 +913,13 @@ int main(int argc __unused, char **argv __unused) {
|
||||||
.sched_priority = 1,
|
.sched_priority = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
medium_oomadj = property_get_int32("ro.lmk.medium", 800);
|
/* By default disable low level vmpressure events */
|
||||||
critical_oomadj = property_get_int32("ro.lmk.critical", 0);
|
level_oomadj[VMPRESS_LEVEL_LOW] =
|
||||||
|
property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1);
|
||||||
|
level_oomadj[VMPRESS_LEVEL_MEDIUM] =
|
||||||
|
property_get_int32("ro.lmk.medium", 800);
|
||||||
|
level_oomadj[VMPRESS_LEVEL_CRITICAL] =
|
||||||
|
property_get_int32("ro.lmk.critical", 0);
|
||||||
debug_process_killing = property_get_bool("ro.lmk.debug", false);
|
debug_process_killing = property_get_bool("ro.lmk.debug", false);
|
||||||
enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false);
|
enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false);
|
||||||
upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50);
|
upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue