lmkd: Support variable polling intervals set by event handlers

After a memory event happens event handler can assess current memory
condition and decide if and when lmkd should re-check memory metrics in
order to respond to changing memory conditions. Change the event handler
interface to allow control over polling period and ability to start/extend
polling session.

Bug: 132642304
Test: lmkd_unit_test
Change-Id: Ia74011e943140b6cffbf452ff8e1744b7336eacf
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
This commit is contained in:
Suren Baghdasaryan 2019-07-15 14:50:49 -07:00
parent 94ce3dd573
commit ef3650f8a0

View file

@ -112,8 +112,6 @@
#define PSI_WINDOW_SIZE_MS 1000
/* Polling period after initial PSI signal */
#define PSI_POLL_PERIOD_MS 10
/* 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))
@ -168,10 +166,30 @@ static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
static android_log_context ctx;
enum polling_update {
POLLING_DO_NOT_CHANGE,
POLLING_START,
POLLING_STOP,
};
/*
* Data used for periodic polling for the memory state of the device.
* Note that when system is not polling poll_handler is set to NULL,
* when polling starts poll_handler gets set and is reset back to
* NULL when polling stops.
*/
struct polling_params {
struct event_handler_info* poll_handler;
struct timespec poll_start_tm;
struct timespec last_poll_tm;
int polling_interval_ms;
enum polling_update update;
};
/* data required to handle events */
struct event_handler_info {
int data;
void (*handler)(int data, uint32_t events);
void (*handler)(int data, uint32_t events, struct polling_params *poll_params);
};
/* data required to handle socket events */
@ -1091,7 +1109,8 @@ wronglen:
ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
}
static void ctrl_data_handler(int data, uint32_t events) {
static void ctrl_data_handler(int data, uint32_t events,
struct polling_params *poll_params __unused) {
if (events & EPOLLIN) {
ctrl_command_handler(data);
}
@ -1106,7 +1125,8 @@ static int get_free_dsock() {
return -1;
}
static void ctrl_connect_handler(int data __unused, uint32_t events __unused) {
static void ctrl_connect_handler(int data __unused, uint32_t events __unused,
struct polling_params *poll_params __unused) {
struct epoll_event epev;
int free_dscock_idx = get_free_dsock();
@ -1813,7 +1833,7 @@ static bool is_kill_pending(void) {
return false;
}
static void mp_event_common(int data, uint32_t events __unused) {
static void mp_event_common(int data, uint32_t events, struct polling_params *poll_params) {
int ret;
unsigned long long evcount;
int64_t mem_usage, memsw_usage;
@ -1857,6 +1877,15 @@ static void mp_event_common(int data, uint32_t events __unused) {
}
}
/* Start polling after initial PSI event */
if (use_psi_monitors && events) {
/* Override polling params only if current event is more critical */
if (!poll_params->poll_handler || data > poll_params->poll_handler->data) {
poll_params->polling_interval_ms = PSI_POLL_PERIOD_MS;
poll_params->update = POLLING_START;
}
}
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
ALOGE("Failed to get current time");
return;
@ -2308,32 +2337,55 @@ static int init(void) {
static void mainloop(void) {
struct event_handler_info* handler_info;
struct event_handler_info* poll_handler = NULL;
struct timespec last_report_tm, curr_tm;
struct polling_params poll_params;
struct timespec curr_tm;
struct epoll_event *evt;
long delay = -1;
int polling = 0;
poll_params.poll_handler = NULL;
poll_params.update = POLLING_DO_NOT_CHANGE;
while (1) {
struct epoll_event events[maxevents];
int nevents;
int i;
if (polling) {
if (poll_params.poll_handler) {
/* 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;
delay = get_time_diff_ms(&poll_params.last_poll_tm, &curr_tm);
delay = (delay < poll_params.polling_interval_ms) ?
poll_params.polling_interval_ms - delay : poll_params.polling_interval_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) {
polling--;
poll_handler->handler(poll_handler->data, 0);
last_report_tm = curr_tm;
if (get_time_diff_ms(&poll_params.last_poll_tm, &curr_tm) >=
poll_params.polling_interval_ms) {
/* Set input params for the call */
poll_params.poll_handler->handler(poll_params.poll_handler->data, 0, &poll_params);
poll_params.last_poll_tm = curr_tm;
if (poll_params.update != POLLING_DO_NOT_CHANGE) {
switch (poll_params.update) {
case POLLING_START:
poll_params.poll_start_tm = curr_tm;
break;
case POLLING_STOP:
poll_params.poll_handler = NULL;
break;
default:
break;
}
poll_params.update = POLLING_DO_NOT_CHANGE;
} else {
if (get_time_diff_ms(&poll_params.poll_start_tm, &curr_tm) >
PSI_WINDOW_SIZE_MS) {
/* Polled for the duration of PSI window, time to stop */
poll_params.poll_handler = NULL;
}
}
}
} else {
/* Wait for events with no timeout */
@ -2364,25 +2416,37 @@ static void mainloop(void) {
/* Second pass to handle all other events */
for (i = 0, evt = &events[0]; i < nevents; ++i, evt++) {
if (evt->events & EPOLLERR)
if (evt->events & EPOLLERR) {
ALOGD("EPOLLERR on event #%d", i);
}
if (evt->events & EPOLLHUP) {
/* This case was handled in the first pass */
continue;
}
if (evt->data.ptr) {
handler_info = (struct event_handler_info*)evt->data.ptr;
handler_info->handler(handler_info->data, evt->events);
/* Set input params for the call */
handler_info->handler(handler_info->data, evt->events, &poll_params);
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);
if (poll_params.update != POLLING_DO_NOT_CHANGE) {
switch (poll_params.update) {
case POLLING_START:
/*
* Poll for the duration of PSI_WINDOW_SIZE_MS after the
* initial PSI event because psi events are rate-limited
* at one per sec.
*/
clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm);
poll_params.poll_start_tm = poll_params.last_poll_tm = curr_tm;
poll_params.poll_handler = handler_info;
break;
case POLLING_STOP:
poll_params.poll_handler = NULL;
break;
default:
break;
}
poll_params.update = POLLING_DO_NOT_CHANGE;
}
}
}