Merge "Read memory stats from /proc/pid/stat file." into pi-dev
This commit is contained in:
commit
cc7862d9b7
76
lmkd.c
76
lmkd.c
|
|
@ -114,6 +114,7 @@ static bool low_ram_device;
|
||||||
static bool kill_heaviest_task;
|
static bool kill_heaviest_task;
|
||||||
static unsigned long kill_timeout_ms;
|
static unsigned long kill_timeout_ms;
|
||||||
static bool use_minfree_levels;
|
static bool use_minfree_levels;
|
||||||
|
static bool per_app_memcg;
|
||||||
|
|
||||||
/* data required to handle events */
|
/* data required to handle events */
|
||||||
struct event_handler_info {
|
struct event_handler_info {
|
||||||
|
|
@ -523,6 +524,10 @@ static void cmd_procremove(LMKD_CTRL_PACKET packet) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lmkd_pack_get_procremove(packet, ¶ms);
|
lmkd_pack_get_procremove(packet, ¶ms);
|
||||||
|
/*
|
||||||
|
* WARNING: After pid_remove() procp is freed and can't be used!
|
||||||
|
* Therefore placed at the end of the function.
|
||||||
|
*/
|
||||||
pid_remove(params.pid);
|
pid_remove(params.pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -751,7 +756,7 @@ static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
|
||||||
mem_st->swap_in_bytes = value;
|
mem_st->swap_in_bytes = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) {
|
static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) {
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
|
|
@ -771,6 +776,43 @@ static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
char buffer[PROC_STAT_BUFFER_SIZE];
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
|
||||||
|
if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
|
||||||
|
ALOGE("%s open failed: %s", path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = read(fd, buffer, sizeof(buffer));
|
||||||
|
if (ret < 0) {
|
||||||
|
ALOGE("%s read failed: %s", path, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
// field 10 is pgfault
|
||||||
|
// field 12 is pgmajfault
|
||||||
|
// field 24 is rss_in_pages
|
||||||
|
int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0;
|
||||||
|
if (sscanf(buffer,
|
||||||
|
"%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
|
||||||
|
"%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
|
||||||
|
"%*d %*d %" SCNd64 "",
|
||||||
|
&pgfault, &pgmajfault, &rss_in_pages) != 3) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mem_st->pgfault = pgfault;
|
||||||
|
mem_st->pgmajfault = pgmajfault;
|
||||||
|
mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* /prop/zoneinfo parsing routines */
|
/* /prop/zoneinfo parsing routines */
|
||||||
|
|
@ -994,6 +1036,7 @@ static int kill_one_process(struct proc* procp) {
|
||||||
char *taskname;
|
char *taskname;
|
||||||
int tasksize;
|
int tasksize;
|
||||||
int r;
|
int r;
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
struct memory_stat mem_st = {};
|
struct memory_stat mem_st = {};
|
||||||
|
|
@ -1002,46 +1045,57 @@ static int kill_one_process(struct proc* procp) {
|
||||||
|
|
||||||
taskname = proc_get_name(pid);
|
taskname = proc_get_name(pid);
|
||||||
if (!taskname) {
|
if (!taskname) {
|
||||||
pid_remove(pid);
|
goto out;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasksize = proc_get_size(pid);
|
tasksize = proc_get_size(pid);
|
||||||
if (tasksize <= 0) {
|
if (tasksize <= 0) {
|
||||||
pid_remove(pid);
|
goto out;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
if (enable_stats_log) {
|
if (enable_stats_log) {
|
||||||
memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid);
|
if (per_app_memcg) {
|
||||||
|
memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid);
|
||||||
|
} else {
|
||||||
|
memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TRACE_KILL_START(pid);
|
TRACE_KILL_START(pid);
|
||||||
|
|
||||||
|
/* CAP_KILL required */
|
||||||
r = kill(pid, SIGKILL);
|
r = kill(pid, SIGKILL);
|
||||||
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
|
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
|
||||||
taskname, pid, uid, procp->oomadj, tasksize * page_k);
|
taskname, pid, uid, procp->oomadj, tasksize * page_k);
|
||||||
pid_remove(pid);
|
|
||||||
|
|
||||||
TRACE_KILL_END();
|
TRACE_KILL_END();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
ALOGE("kill(%d): errno=%d", pid, errno);
|
ALOGE("kill(%d): errno=%d", pid, errno);
|
||||||
return -1;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
if (memory_stat_parse_result == 0) {
|
if (memory_stat_parse_result == 0) {
|
||||||
stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
|
stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
|
||||||
procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
|
procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
|
||||||
mem_st.cache_in_bytes, mem_st.swap_in_bytes);
|
mem_st.cache_in_bytes, mem_st.swap_in_bytes);
|
||||||
|
} else if (enable_stats_log) {
|
||||||
|
stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj,
|
||||||
|
-1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return tasksize;
|
result = tasksize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tasksize;
|
out:
|
||||||
|
/*
|
||||||
|
* WARNING: After pid_remove() procp is freed and can't be used!
|
||||||
|
* Therefore placed at the end of the function.
|
||||||
|
*/
|
||||||
|
pid_remove(pid);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1586,7 +1640,7 @@ int main(int argc __unused, char **argv __unused) {
|
||||||
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
|
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
|
||||||
use_minfree_levels =
|
use_minfree_levels =
|
||||||
property_get_bool("ro.lmk.use_minfree_levels", false);
|
property_get_bool("ro.lmk.use_minfree_levels", false);
|
||||||
|
per_app_memcg = property_get_bool("ro.config.per_app_memcg", low_ram_device);
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
statslog_init(&log_ctx, &enable_stats_log);
|
statslog_init(&log_ctx, &enable_stats_log);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,9 @@ struct memory_stat {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
|
#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
|
||||||
|
#define PROC_STAT_FILE_PATH "/proc/%d/stat"
|
||||||
|
#define PROC_STAT_BUFFER_SIZE 1024
|
||||||
|
#define BYTES_IN_KILOBYTE 1024
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs the change in LMKD state which is used as start/stop boundaries for logging
|
* Logs the change in LMKD state which is used as start/stop boundaries for logging
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue