lmkd: Allow killing perceptible apps when recorded stall is too high am: 5ae47a9563 am: 744462fdf0 am: 38cbc12b33 am: 915a384a57
Original change: https://android-review.googlesource.com/c/platform/system/memory/lmkd/+/1992290 Change-Id: I3820ed100c64683f6ff1c5b50405678436d02cb7
This commit is contained in:
commit
cddacf8864
|
|
@ -22,12 +22,25 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define PSI_PATH_MEMORY "/proc/pressure/memory"
|
||||
|
||||
enum psi_stall_type {
|
||||
PSI_SOME,
|
||||
PSI_FULL,
|
||||
PSI_TYPE_COUNT
|
||||
};
|
||||
|
||||
struct psi_stats {
|
||||
float avg10;
|
||||
float avg60;
|
||||
float avg300;
|
||||
unsigned long total;
|
||||
};
|
||||
|
||||
struct psi_data {
|
||||
struct psi_stats mem_stats[PSI_TYPE_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes psi monitor.
|
||||
* stall_type, threshold_us and window_us are monitor parameters
|
||||
|
|
@ -63,6 +76,13 @@ int unregister_psi_monitor(int epollfd, int fd);
|
|||
*/
|
||||
void destroy_psi_monitor(int fd);
|
||||
|
||||
/*
|
||||
* Parse psi file line content. Expected file format is:
|
||||
* some avg10=0.00 avg60=0.00 avg300=0.00 total=0
|
||||
* full avg10=0.00 avg60=0.00 avg300=0.00 total=0
|
||||
*/
|
||||
int parse_psi_line(char *line, enum psi_stall_type stall_type, struct psi_stats stats[]);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // __ANDROID_PSI_H__
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
#include <stdio.h>
|
||||
#include "psi/psi.h"
|
||||
|
||||
#define PSI_MON_FILE_MEMORY "/proc/pressure/memory"
|
||||
|
||||
static const char* stall_type_name[] = {
|
||||
"some",
|
||||
"full",
|
||||
|
|
@ -41,7 +39,7 @@ int init_psi_monitor(enum psi_stall_type stall_type,
|
|||
int res;
|
||||
char buf[256];
|
||||
|
||||
fd = TEMP_FAILURE_RETRY(open(PSI_MON_FILE_MEMORY, O_WRONLY | O_CLOEXEC));
|
||||
fd = TEMP_FAILURE_RETRY(open(PSI_PATH_MEMORY, O_WRONLY | O_CLOEXEC));
|
||||
if (fd < 0) {
|
||||
ALOGE("No kernel psi monitor support (errno=%d)", errno);
|
||||
return -1;
|
||||
|
|
@ -61,7 +59,7 @@ int init_psi_monitor(enum psi_stall_type stall_type,
|
|||
|
||||
if (res >= (ssize_t)sizeof(buf)) {
|
||||
ALOGE("%s line overflow for psi stall type '%s'",
|
||||
PSI_MON_FILE_MEMORY, stall_type_name[stall_type]);
|
||||
PSI_PATH_MEMORY, stall_type_name[stall_type]);
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -69,7 +67,7 @@ int init_psi_monitor(enum psi_stall_type stall_type,
|
|||
res = TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf) + 1));
|
||||
if (res < 0) {
|
||||
ALOGE("%s write failed for psi stall type '%s'; errno=%d",
|
||||
PSI_MON_FILE_MEMORY, stall_type_name[stall_type], errno);
|
||||
PSI_PATH_MEMORY, stall_type_name[stall_type], errno);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -102,3 +100,17 @@ void destroy_psi_monitor(int fd) {
|
|||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
int parse_psi_line(char *line, enum psi_stall_type stall_type, struct psi_stats stats[]) {
|
||||
char type_name[5];
|
||||
struct psi_stats *stat = &stats[stall_type];
|
||||
|
||||
if (!line || sscanf(line, "%4s avg10=%f avg60=%f avg300=%f total=%lu",
|
||||
type_name, &stat->avg10, &stat->avg60, &stat->avg300, &stat->total) != 5) {
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(type_name, stall_type_name[stall_type])) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
43
lmkd.cpp
43
lmkd.cpp
|
|
@ -218,6 +218,7 @@ static int thrashing_limit_decay_pct;
|
|||
static int thrashing_critical_pct;
|
||||
static int swap_util_max;
|
||||
static int64_t filecache_min_kb;
|
||||
static int64_t stall_limit_critical;
|
||||
static bool use_psi_monitors = false;
|
||||
static int kpoll_fd;
|
||||
static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
|
||||
|
|
@ -1915,6 +1916,37 @@ static int vmstat_parse(union vmstat *vs) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int psi_parse(struct reread_data *file_data, struct psi_stats stats[], bool full) {
|
||||
char *buf;
|
||||
char *save_ptr;
|
||||
char *line;
|
||||
|
||||
if ((buf = reread_file(file_data)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
line = strtok_r(buf, "\n", &save_ptr);
|
||||
if (parse_psi_line(line, PSI_SOME, stats)) {
|
||||
return -1;
|
||||
}
|
||||
if (full) {
|
||||
line = strtok_r(NULL, "\n", &save_ptr);
|
||||
if (parse_psi_line(line, PSI_FULL, stats)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psi_parse_mem(struct psi_data *psi_data) {
|
||||
static struct reread_data file_data = {
|
||||
.filename = PSI_PATH_MEMORY,
|
||||
.fd = -1,
|
||||
};
|
||||
return psi_parse(&file_data, psi_data->mem_stats, true);
|
||||
}
|
||||
|
||||
enum wakeup_reason {
|
||||
Event,
|
||||
Polling
|
||||
|
|
@ -2500,6 +2532,7 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
|
|||
|
||||
union meminfo mi;
|
||||
union vmstat vs;
|
||||
struct psi_data psi_data;
|
||||
struct timespec curr_tm;
|
||||
int64_t thrashing = 0;
|
||||
bool swap_is_low = false;
|
||||
|
|
@ -2515,6 +2548,7 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
|
|||
int64_t swap_low_threshold;
|
||||
long since_thrashing_reset_ms;
|
||||
int64_t workingset_refault_file;
|
||||
bool critical_stall = false;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_tm) != 0) {
|
||||
ALOGE("Failed to get current time");
|
||||
|
|
@ -2647,6 +2681,9 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
|
|||
/* Find out which watermark is breached if any */
|
||||
wmark = get_lowest_watermark(&mi, &watermarks);
|
||||
|
||||
if (!psi_parse_mem(&psi_data)) {
|
||||
critical_stall = psi_data.mem_stats[PSI_FULL].avg10 > (float)stall_limit_critical;
|
||||
}
|
||||
/*
|
||||
* TODO: move this logic into a separate function
|
||||
* Decide if killing a process is necessary and record the reason
|
||||
|
|
@ -2744,6 +2781,11 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_
|
|||
.thrashing = (int)thrashing,
|
||||
.max_thrashing = max_thrashing,
|
||||
};
|
||||
|
||||
/* Allow killing perceptible apps if the system is stalled */
|
||||
if (critical_stall) {
|
||||
min_score_adj = 0;
|
||||
}
|
||||
int pages_freed = find_and_kill_process(min_score_adj, &ki, &mi, &wi, &curr_tm);
|
||||
if (pages_freed > 0) {
|
||||
killing = true;
|
||||
|
|
@ -3601,6 +3643,7 @@ static void update_props() {
|
|||
thrashing_limit_pct * 2));
|
||||
swap_util_max = clamp(0, 100, GET_LMK_PROPERTY(int32, "swap_util_max", 100));
|
||||
filecache_min_kb = GET_LMK_PROPERTY(int64, "filecache_min_kb", 0);
|
||||
stall_limit_critical = GET_LMK_PROPERTY(int64, "stall_limit_critical", 100);
|
||||
|
||||
reaper.enable_debug(debug_process_killing);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue