Merge "lmkd: Add support for psi monitors" am: bec585440c am: b32788fc5e
am: 92a5149a3b Change-Id: I613401d77e33313ba9df7a71ce79938ed7f2538b
This commit is contained in:
commit
2e28615782
|
|
@ -6,6 +6,7 @@ cc_binary {
|
||||||
"libcutils",
|
"libcutils",
|
||||||
"liblog",
|
"liblog",
|
||||||
"libprocessgroup",
|
"libprocessgroup",
|
||||||
|
"libpsi",
|
||||||
],
|
],
|
||||||
static_libs: [
|
static_libs: [
|
||||||
"libstatslogc",
|
"libstatslogc",
|
||||||
|
|
|
||||||
129
lmkd.c
129
lmkd.c
|
|
@ -44,6 +44,7 @@
|
||||||
#include <log/log.h>
|
#include <log/log.h>
|
||||||
#include <log/log_event_list.h>
|
#include <log/log_event_list.h>
|
||||||
#include <log/log_time.h>
|
#include <log/log_time.h>
|
||||||
|
#include <psi/psi.h>
|
||||||
#include <system/thread_defs.h>
|
#include <system/thread_defs.h>
|
||||||
|
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
|
|
@ -93,6 +94,7 @@
|
||||||
#define TARGET_UPDATE_MIN_INTERVAL_MS 1000
|
#define TARGET_UPDATE_MIN_INTERVAL_MS 1000
|
||||||
|
|
||||||
#define NS_PER_MS (NS_PER_SEC / MS_PER_SEC)
|
#define NS_PER_MS (NS_PER_SEC / MS_PER_SEC)
|
||||||
|
#define US_PER_MS (US_PER_SEC / MS_PER_SEC)
|
||||||
|
|
||||||
/* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */
|
/* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */
|
||||||
#define SYSTEM_ADJ (-900)
|
#define SYSTEM_ADJ (-900)
|
||||||
|
|
@ -100,6 +102,18 @@
|
||||||
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
|
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
|
||||||
#define STRINGIFY_INTERNAL(x) #x
|
#define STRINGIFY_INTERNAL(x) #x
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PSI monitor tracking window size.
|
||||||
|
* PSI monitor generates events at most once per window,
|
||||||
|
* therefore we poll memory state for the duration of
|
||||||
|
* PSI_WINDOW_SIZE_MS after the event happens.
|
||||||
|
*/
|
||||||
|
#define PSI_WINDOW_SIZE_MS 1000
|
||||||
|
/* Polling period after initial PSI signal */
|
||||||
|
#define PSI_POLL_PERIOD_MS 200
|
||||||
|
/* Poll for the duration of one window after initial PSI signal */
|
||||||
|
#define PSI_POLL_COUNT (PSI_WINDOW_SIZE_MS / PSI_POLL_PERIOD_MS)
|
||||||
|
|
||||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
#define FAIL_REPORT_RLIMIT_MS 1000
|
#define FAIL_REPORT_RLIMIT_MS 1000
|
||||||
|
|
@ -127,6 +141,11 @@ struct {
|
||||||
int64_t max_nr_free_pages;
|
int64_t max_nr_free_pages;
|
||||||
} low_pressure_mem = { -1, -1 };
|
} low_pressure_mem = { -1, -1 };
|
||||||
|
|
||||||
|
struct psi_threshold {
|
||||||
|
enum psi_stall_type stall_type;
|
||||||
|
int threshold_ms;
|
||||||
|
};
|
||||||
|
|
||||||
static int level_oomadj[VMPRESS_LEVEL_COUNT];
|
static int level_oomadj[VMPRESS_LEVEL_COUNT];
|
||||||
static int mpevfd[VMPRESS_LEVEL_COUNT] = { -1, -1, -1 };
|
static int mpevfd[VMPRESS_LEVEL_COUNT] = { -1, -1, -1 };
|
||||||
static bool debug_process_killing;
|
static bool debug_process_killing;
|
||||||
|
|
@ -139,6 +158,12 @@ static unsigned long kill_timeout_ms;
|
||||||
static bool use_minfree_levels;
|
static bool use_minfree_levels;
|
||||||
static bool per_app_memcg;
|
static bool per_app_memcg;
|
||||||
static int swap_free_low_percentage;
|
static int swap_free_low_percentage;
|
||||||
|
static bool use_psi_monitors = false;
|
||||||
|
static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
|
||||||
|
{ PSI_SOME, 70 }, /* 70ms out of 1sec for partial stall */
|
||||||
|
{ PSI_SOME, 100 }, /* 100ms out of 1sec for partial stall */
|
||||||
|
{ PSI_FULL, 70 }, /* 70ms out of 1sec for complete stall */
|
||||||
|
};
|
||||||
|
|
||||||
static android_log_context ctx;
|
static android_log_context ctx;
|
||||||
|
|
||||||
|
|
@ -1524,6 +1549,11 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
||||||
.fd = -1,
|
.fd = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (debug_process_killing) {
|
||||||
|
ALOGI("%s memory pressure event is triggered", level_name[level]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!use_psi_monitors) {
|
||||||
/*
|
/*
|
||||||
* Check all event counters from low to critical
|
* Check all event counters from low to critical
|
||||||
* and upgrade to the highest priority one. By reading
|
* and upgrade to the highest priority one. By reading
|
||||||
|
|
@ -1537,6 +1567,7 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
||||||
level = lvl;
|
level = lvl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
|
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
|
||||||
ALOGE("Failed to get current time");
|
ALOGE("Failed to get current time");
|
||||||
|
|
@ -1722,6 +1753,54 @@ do_kill:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool init_mp_psi(enum vmpressure_level level) {
|
||||||
|
int fd = init_psi_monitor(psi_thresholds[level].stall_type,
|
||||||
|
psi_thresholds[level].threshold_ms * US_PER_MS,
|
||||||
|
PSI_WINDOW_SIZE_MS * US_PER_MS);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmpressure_hinfo[level].handler = mp_event_common;
|
||||||
|
vmpressure_hinfo[level].data = level;
|
||||||
|
if (register_psi_monitor(epollfd, fd, &vmpressure_hinfo[level]) < 0) {
|
||||||
|
destroy_psi_monitor(fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
maxevents++;
|
||||||
|
mpevfd[level] = fd;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_mp_psi(enum vmpressure_level level) {
|
||||||
|
int fd = mpevfd[level];
|
||||||
|
|
||||||
|
if (unregister_psi_monitor(epollfd, fd) < 0) {
|
||||||
|
ALOGE("Failed to unregister psi monitor for %s memory pressure; errno=%d",
|
||||||
|
level_name[level], errno);
|
||||||
|
}
|
||||||
|
destroy_psi_monitor(fd);
|
||||||
|
mpevfd[level] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool init_psi_monitors() {
|
||||||
|
if (!init_mp_psi(VMPRESS_LEVEL_LOW)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!init_mp_psi(VMPRESS_LEVEL_MEDIUM)) {
|
||||||
|
destroy_mp_psi(VMPRESS_LEVEL_LOW);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!init_mp_psi(VMPRESS_LEVEL_CRITICAL)) {
|
||||||
|
destroy_mp_psi(VMPRESS_LEVEL_MEDIUM);
|
||||||
|
destroy_mp_psi(VMPRESS_LEVEL_LOW);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool init_mp_common(enum vmpressure_level level) {
|
static bool init_mp_common(enum vmpressure_level level) {
|
||||||
int mpfd;
|
int mpfd;
|
||||||
int evfd;
|
int evfd;
|
||||||
|
|
@ -1837,12 +1916,22 @@ 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 {
|
||||||
if (!init_mp_common(VMPRESS_LEVEL_LOW) ||
|
/* Try to use psi monitor first if kernel has it */
|
||||||
|
use_psi_monitors = property_get_bool("ro.lmk.use_psi", true) &&
|
||||||
|
init_psi_monitors();
|
||||||
|
/* Fall back to vmpressure */
|
||||||
|
if (!use_psi_monitors &&
|
||||||
|
(!init_mp_common(VMPRESS_LEVEL_LOW) ||
|
||||||
!init_mp_common(VMPRESS_LEVEL_MEDIUM) ||
|
!init_mp_common(VMPRESS_LEVEL_MEDIUM) ||
|
||||||
!init_mp_common(VMPRESS_LEVEL_CRITICAL)) {
|
!init_mp_common(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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (use_psi_monitors) {
|
||||||
|
ALOGI("Using psi monitors for memory pressure detection");
|
||||||
|
} else {
|
||||||
|
ALOGI("Using vmpressure for memory pressure detection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
|
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
|
||||||
|
|
@ -1857,14 +1946,39 @@ static int init(void) {
|
||||||
|
|
||||||
static void mainloop(void) {
|
static void mainloop(void) {
|
||||||
struct event_handler_info* handler_info;
|
struct event_handler_info* handler_info;
|
||||||
|
struct event_handler_info* poll_handler = NULL;
|
||||||
|
struct timespec last_report_tm, curr_tm;
|
||||||
struct epoll_event *evt;
|
struct epoll_event *evt;
|
||||||
|
long delay = -1;
|
||||||
|
int polling = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct epoll_event events[maxevents];
|
struct epoll_event events[maxevents];
|
||||||
int nevents;
|
int nevents;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (polling) {
|
||||||
|
/* Calculate next timeout */
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
|
||||||
|
delay = get_time_diff_ms(&last_report_tm, &curr_tm);
|
||||||
|
delay = (delay < PSI_POLL_PERIOD_MS) ?
|
||||||
|
PSI_POLL_PERIOD_MS - delay : PSI_POLL_PERIOD_MS;
|
||||||
|
|
||||||
|
/* Wait for events until the next polling timeout */
|
||||||
|
nevents = epoll_wait(epollfd, events, maxevents, delay);
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
|
||||||
|
if (get_time_diff_ms(&last_report_tm, &curr_tm) >= PSI_POLL_PERIOD_MS) {
|
||||||
|
if (polling) {
|
||||||
|
polling--;
|
||||||
|
poll_handler->handler(poll_handler->data, 0);
|
||||||
|
last_report_tm = curr_tm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Wait for events with no timeout */
|
||||||
nevents = epoll_wait(epollfd, events, maxevents, -1);
|
nevents = epoll_wait(epollfd, events, maxevents, -1);
|
||||||
|
}
|
||||||
|
|
||||||
if (nevents == -1) {
|
if (nevents == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
|
|
@ -1899,6 +2013,17 @@ static void mainloop(void) {
|
||||||
if (evt->data.ptr) {
|
if (evt->data.ptr) {
|
||||||
handler_info = (struct event_handler_info*)evt->data.ptr;
|
handler_info = (struct event_handler_info*)evt->data.ptr;
|
||||||
handler_info->handler(handler_info->data, evt->events);
|
handler_info->handler(handler_info->data, evt->events);
|
||||||
|
|
||||||
|
if (use_psi_monitors && handler_info->handler == mp_event_common) {
|
||||||
|
/*
|
||||||
|
* Poll for the duration of PSI_WINDOW_SIZE_MS after the
|
||||||
|
* initial PSI event because psi events are rate-limited
|
||||||
|
* at one per sec.
|
||||||
|
*/
|
||||||
|
polling = PSI_POLL_COUNT;
|
||||||
|
poll_handler = handler_info;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC_COARSE, &last_report_tm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue