From e12a067ee062e567c866cb7c73419fc865b76a15 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 15 Jul 2019 14:50:49 -0700 Subject: [PATCH] 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 --- lmkd.c | 120 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 28 deletions(-) diff --git a/lmkd.c b/lmkd.c index 8fde3b4..04662fe 100644 --- a/lmkd.c +++ b/lmkd.c @@ -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; } } }