system/core
Revision | 244ace6b7b6508e97efc0a384c77f4b5b6c0de52 (tree) |
---|---|
Zeit | 2018-10-13 06:28:50 |
Autor | Rajeev Kumar <rajekumar@goog...> |
Commiter | Rajeev Kumar |
Read memory stats from /proc/pid/stat file.
(cherry pick from commit 0301683e49ab255769b15469487feaab3466167a)
Bug: 117333340
Test: Manual testing using alloc-stress tool
Change-Id: Ie555933aafa6a6b7aa1dbf5518ebe804376e0afd
Merged-In: Ie555933aafa6a6b7aa1dbf5518ebe804376e0afd
@@ -114,6 +114,7 @@ static bool low_ram_device; | ||
114 | 114 | static bool kill_heaviest_task; |
115 | 115 | static unsigned long kill_timeout_ms; |
116 | 116 | static bool use_minfree_levels; |
117 | +static bool per_app_memcg; | |
117 | 118 | |
118 | 119 | /* data required to handle events */ |
119 | 120 | struct event_handler_info { |
@@ -523,6 +524,10 @@ static void cmd_procremove(LMKD_CTRL_PACKET packet) { | ||
523 | 524 | return; |
524 | 525 | |
525 | 526 | lmkd_pack_get_procremove(packet, ¶ms); |
527 | + /* | |
528 | + * WARNING: After pid_remove() procp is freed and can't be used! | |
529 | + * Therefore placed at the end of the function. | |
530 | + */ | |
526 | 531 | pid_remove(params.pid); |
527 | 532 | } |
528 | 533 |
@@ -699,7 +704,7 @@ static void ctrl_connect_handler(int data __unused, uint32_t events __unused) { | ||
699 | 704 | } |
700 | 705 | |
701 | 706 | #ifdef LMKD_LOG_STATS |
702 | -static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { | |
707 | +static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) { | |
703 | 708 | char key[LINE_MAX + 1]; |
704 | 709 | int64_t value; |
705 | 710 |
@@ -721,25 +726,62 @@ static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { | ||
721 | 726 | mem_st->swap_in_bytes = value; |
722 | 727 | } |
723 | 728 | |
724 | -static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { | |
725 | - FILE *fp; | |
726 | - char buf[PATH_MAX]; | |
729 | +static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) { | |
730 | + FILE* fp; | |
731 | + char buf[PATH_MAX]; | |
727 | 732 | |
728 | - snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); | |
733 | + snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); | |
729 | 734 | |
730 | - fp = fopen(buf, "r"); | |
735 | + fp = fopen(buf, "r"); | |
731 | 736 | |
732 | - if (fp == NULL) { | |
733 | - ALOGE("%s open failed: %s", buf, strerror(errno)); | |
734 | - return -1; | |
735 | - } | |
737 | + if (fp == NULL) { | |
738 | + ALOGE("%s open failed: %s", buf, strerror(errno)); | |
739 | + return -1; | |
740 | + } | |
736 | 741 | |
737 | - while (fgets(buf, PAGE_SIZE, fp) != NULL ) { | |
738 | - memory_stat_parse_line(buf, mem_st); | |
739 | - } | |
740 | - fclose(fp); | |
742 | + while (fgets(buf, PAGE_SIZE, fp) != NULL) { | |
743 | + memory_stat_parse_line(buf, mem_st); | |
744 | + } | |
745 | + fclose(fp); | |
741 | 746 | |
742 | - return 0; | |
747 | + return 0; | |
748 | +} | |
749 | + | |
750 | +static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) { | |
751 | + char path[PATH_MAX]; | |
752 | + char buffer[PROC_STAT_BUFFER_SIZE]; | |
753 | + int fd, ret; | |
754 | + | |
755 | + snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid); | |
756 | + if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { | |
757 | + ALOGE("%s open failed: %s", path, strerror(errno)); | |
758 | + return -1; | |
759 | + } | |
760 | + | |
761 | + ret = read(fd, buffer, sizeof(buffer)); | |
762 | + if (ret < 0) { | |
763 | + ALOGE("%s read failed: %s", path, strerror(errno)); | |
764 | + close(fd); | |
765 | + return -1; | |
766 | + } | |
767 | + close(fd); | |
768 | + | |
769 | + // field 10 is pgfault | |
770 | + // field 12 is pgmajfault | |
771 | + // field 24 is rss_in_pages | |
772 | + int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0; | |
773 | + if (sscanf(buffer, | |
774 | + "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d " | |
775 | + "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d " | |
776 | + "%*d %*d %" SCNd64 "", | |
777 | + &pgfault, &pgmajfault, &rss_in_pages) != 3) { | |
778 | + return -1; | |
779 | + } | |
780 | + mem_st->pgfault = pgfault; | |
781 | + mem_st->pgmajfault = pgmajfault; | |
782 | + mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE); | |
783 | + | |
784 | + return 0; | |
743 | 785 | } |
744 | 786 | #endif |
745 | 787 |
@@ -964,6 +1006,7 @@ static int kill_one_process(struct proc* procp) { | ||
964 | 1006 | char *taskname; |
965 | 1007 | int tasksize; |
966 | 1008 | int r; |
1009 | + int result = -1; | |
967 | 1010 | |
968 | 1011 | #ifdef LMKD_LOG_STATS |
969 | 1012 | struct memory_stat mem_st = {}; |
@@ -972,46 +1015,57 @@ static int kill_one_process(struct proc* procp) { | ||
972 | 1015 | |
973 | 1016 | taskname = proc_get_name(pid); |
974 | 1017 | if (!taskname) { |
975 | - pid_remove(pid); | |
976 | - return -1; | |
1018 | + goto out; | |
977 | 1019 | } |
978 | 1020 | |
979 | 1021 | tasksize = proc_get_size(pid); |
980 | 1022 | if (tasksize <= 0) { |
981 | - pid_remove(pid); | |
982 | - return -1; | |
1023 | + goto out; | |
983 | 1024 | } |
984 | 1025 | |
985 | 1026 | #ifdef LMKD_LOG_STATS |
986 | 1027 | if (enable_stats_log) { |
987 | - memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid); | |
1028 | + if (per_app_memcg) { | |
1029 | + memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid); | |
1030 | + } else { | |
1031 | + memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid); | |
1032 | + } | |
988 | 1033 | } |
989 | 1034 | #endif |
990 | 1035 | |
991 | 1036 | TRACE_KILL_START(pid); |
992 | 1037 | |
1038 | + /* CAP_KILL required */ | |
993 | 1039 | r = kill(pid, SIGKILL); |
994 | 1040 | ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB", |
995 | 1041 | taskname, pid, uid, procp->oomadj, tasksize * page_k); |
996 | - pid_remove(pid); | |
997 | 1042 | |
998 | 1043 | TRACE_KILL_END(); |
999 | 1044 | |
1000 | 1045 | if (r) { |
1001 | 1046 | ALOGE("kill(%d): errno=%d", pid, errno); |
1002 | - return -1; | |
1047 | + goto out; | |
1003 | 1048 | } else { |
1004 | 1049 | #ifdef LMKD_LOG_STATS |
1005 | 1050 | if (memory_stat_parse_result == 0) { |
1006 | 1051 | stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, |
1007 | 1052 | procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes, |
1008 | 1053 | mem_st.cache_in_bytes, mem_st.swap_in_bytes); |
1054 | + } else if (enable_stats_log) { | |
1055 | + stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, | |
1056 | + -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1); | |
1009 | 1057 | } |
1010 | 1058 | #endif |
1011 | - return tasksize; | |
1059 | + result = tasksize; | |
1012 | 1060 | } |
1013 | 1061 | |
1014 | - return tasksize; | |
1062 | +out: | |
1063 | + /* | |
1064 | + * WARNING: After pid_remove() procp is freed and can't be used! | |
1065 | + * Therefore placed at the end of the function. | |
1066 | + */ | |
1067 | + pid_remove(pid); | |
1068 | + return result; | |
1015 | 1069 | } |
1016 | 1070 | |
1017 | 1071 | /* |
@@ -1556,7 +1610,7 @@ int main(int argc __unused, char **argv __unused) { | ||
1556 | 1610 | (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0); |
1557 | 1611 | use_minfree_levels = |
1558 | 1612 | property_get_bool("ro.lmk.use_minfree_levels", false); |
1559 | - | |
1613 | + per_app_memcg = property_get_bool("ro.config.per_app_memcg", low_ram_device); | |
1560 | 1614 | #ifdef LMKD_LOG_STATS |
1561 | 1615 | statslog_init(&log_ctx, &enable_stats_log); |
1562 | 1616 | #endif |
@@ -67,6 +67,9 @@ struct memory_stat { | ||
67 | 67 | }; |
68 | 68 | |
69 | 69 | #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" |
70 | +#define PROC_STAT_FILE_PATH "/proc/%d/stat" | |
71 | +#define PROC_STAT_BUFFER_SIZE 1024 | |
72 | +#define BYTES_IN_KILOBYTE 1024 | |
70 | 73 | |
71 | 74 | /** |
72 | 75 | * Logs the change in LMKD state which is used as start/stop boundaries for logging |