summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lmkd/README.md5
-rw-r--r--lmkd/lmkd.c105
2 files changed, 85 insertions, 25 deletions
diff --git a/lmkd/README.md b/lmkd/README.md
index ba2e83d06..656a6ea0a 100644
--- a/lmkd/README.md
+++ b/lmkd/README.md
@@ -29,6 +29,11 @@ properties:
29 ro.config.low_ram: choose between low-memory vs high-performance 29 ro.config.low_ram: choose between low-memory vs high-performance
30 device. Default = false. 30 device. Default = false.
31 31
32 ro.lmk.use_minfree_levels: use free memory and file cache thresholds for
33 making decisions when to kill. This mode works
34 the same way kernel lowmemorykiller driver used
35 to work. Default = false
36
32 ro.lmk.low: min oom_adj score for processes eligible to be 37 ro.lmk.low: min oom_adj score for processes eligible to be
33 killed at low vmpressure level. Default = 1001 38 killed at low vmpressure level. Default = 1001
34 (disabled) 39 (disabled)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 5eb3fbe15..151e1dc7b 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -109,6 +109,7 @@ static int64_t downgrade_pressure;
109static bool low_ram_device; 109static bool low_ram_device;
110static bool kill_heaviest_task; 110static bool kill_heaviest_task;
111static unsigned long kill_timeout_ms; 111static unsigned long kill_timeout_ms;
112static bool use_minfree_levels;
112 113
113/* data required to handle events */ 114/* data required to handle events */
114struct event_handler_info { 115struct event_handler_info {
@@ -972,11 +973,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj,
972 * Returns the size of the killed processes. 973 * Returns the size of the killed processes.
973 */ 974 */
974static int find_and_kill_processes(enum vmpressure_level level, 975static int find_and_kill_processes(enum vmpressure_level level,
975 int pages_to_free) { 976 int min_score_adj, int pages_to_free) {
976 int i; 977 int i;
977 int killed_size; 978 int killed_size;
978 int pages_freed = 0; 979 int pages_freed = 0;
979 int min_score_adj = level_oomadj[level];
980 980
981 for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) { 981 for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
982 struct proc *procp; 982 struct proc *procp;
@@ -1071,9 +1071,14 @@ static void mp_event_common(int data, uint32_t events __unused) {
1071 int64_t mem_pressure; 1071 int64_t mem_pressure;
1072 enum vmpressure_level lvl; 1072 enum vmpressure_level lvl;
1073 union meminfo mi; 1073 union meminfo mi;
1074 union zoneinfo zi;
1074 static struct timeval last_report_tm; 1075 static struct timeval last_report_tm;
1075 static unsigned long skip_count = 0; 1076 static unsigned long skip_count = 0;
1076 enum vmpressure_level level = (enum vmpressure_level)data; 1077 enum vmpressure_level level = (enum vmpressure_level)data;
1078 long other_free = 0, other_file = 0;
1079 int min_score_adj;
1080 int pages_to_free = 0;
1081 int minfree = 0;
1077 static struct reread_data mem_usage_file_data = { 1082 static struct reread_data mem_usage_file_data = {
1078 .filename = MEMCG_MEMORY_USAGE, 1083 .filename = MEMCG_MEMORY_USAGE,
1079 .fd = -1, 1084 .fd = -1,
@@ -1114,11 +1119,40 @@ static void mp_event_common(int data, uint32_t events __unused) {
1114 skip_count = 0; 1119 skip_count = 0;
1115 } 1120 }
1116 1121
1117 if (meminfo_parse(&mi) < 0) { 1122 if (meminfo_parse(&mi) < 0 || zoneinfo_parse(&zi) < 0) {
1118 ALOGE("Failed to get free memory!"); 1123 ALOGE("Failed to get free memory!");
1119 return; 1124 return;
1120 } 1125 }
1121 1126
1127 if (use_minfree_levels) {
1128 int i;
1129
1130 other_free = mi.field.nr_free_pages - zi.field.totalreserve_pages;
1131 if (mi.field.nr_file_pages > (mi.field.shmem + mi.field.unevictable + mi.field.swap_cached)) {
1132 other_file = (mi.field.nr_file_pages - mi.field.shmem -
1133 mi.field.unevictable - mi.field.swap_cached);
1134 } else {
1135 other_file = 0;
1136 }
1137
1138 min_score_adj = OOM_SCORE_ADJ_MAX + 1;
1139 for (i = 0; i < lowmem_targets_size; i++) {
1140 minfree = lowmem_minfree[i];
1141 if (other_free < minfree && other_file < minfree) {
1142 min_score_adj = lowmem_adj[i];
1143 break;
1144 }
1145 }
1146
1147 if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
1148 return;
1149
1150 /* Free up enough pages to push over the highest minfree level */
1151 pages_to_free = lowmem_minfree[lowmem_targets_size - 1] -
1152 ((other_free < other_file) ? other_free : other_file);
1153 goto do_kill;
1154 }
1155
1122 if (level == VMPRESS_LEVEL_LOW) { 1156 if (level == VMPRESS_LEVEL_LOW) {
1123 record_low_pressure_levels(&mi); 1157 record_low_pressure_levels(&mi);
1124 } 1158 }
@@ -1167,39 +1201,58 @@ static void mp_event_common(int data, uint32_t events __unused) {
1167do_kill: 1201do_kill:
1168 if (low_ram_device) { 1202 if (low_ram_device) {
1169 /* For Go devices kill only one task */ 1203 /* For Go devices kill only one task */
1170 if (find_and_kill_processes(level, 0) == 0) { 1204 if (find_and_kill_processes(level, level_oomadj[level], 0) == 0) {
1171 if (debug_process_killing) { 1205 if (debug_process_killing) {
1172 ALOGI("Nothing to kill"); 1206 ALOGI("Nothing to kill");
1173 } 1207 }
1174 } 1208 }
1175 } else { 1209 } else {
1176 /* If pressure level is less than critical and enough free swap then ignore */ 1210 int pages_freed;
1177 if (level < VMPRESS_LEVEL_CRITICAL && 1211
1178 mi.field.free_swap > low_pressure_mem.max_nr_free_pages) { 1212 if (!use_minfree_levels) {
1213 /* If pressure level is less than critical and enough free swap then ignore */
1214 if (level < VMPRESS_LEVEL_CRITICAL &&
1215 mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
1216 if (debug_process_killing) {
1217 ALOGI("Ignoring pressure since %" PRId64
1218 " swap pages are available ",
1219 mi.field.free_swap);
1220 }
1221 return;
1222 }
1223 /* Free up enough memory to downgrate the memory pressure to low level */
1224 if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) {
1225 pages_to_free = low_pressure_mem.max_nr_free_pages -
1226 mi.field.nr_free_pages;
1227 } else {
1228 if (debug_process_killing) {
1229 ALOGI("Ignoring pressure since more memory is "
1230 "available (%" PRId64 ") than watermark (%" PRId64 ")",
1231 mi.field.nr_free_pages, low_pressure_mem.max_nr_free_pages);
1232 }
1233 return;
1234 }
1235 min_score_adj = level_oomadj[level];
1236 } else {
1179 if (debug_process_killing) { 1237 if (debug_process_killing) {
1180 ALOGI("Ignoring pressure since %" PRId64 1238 ALOGI("Killing because cache %ldkB is below "
1181 " swap pages are available ", 1239 "limit %ldkB for oom_adj %d\n"
1182 mi.field.free_swap); 1240 " Free memory is %ldkB %s reserved",
1241 other_file * page_k, minfree * page_k, min_score_adj,
1242 other_free * page_k, other_free >= 0 ? "above" : "below");
1183 } 1243 }
1184 return;
1185 } 1244 }
1186 1245
1187 /* Free up enough memory to downgrate the memory pressure to low level */ 1246 if (debug_process_killing) {
1188 if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) { 1247 ALOGI("Trying to free %d pages", pages_to_free);
1189 int pages_to_free = low_pressure_mem.max_nr_free_pages - 1248 }
1190 mi.field.nr_free_pages; 1249 pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
1250 if (pages_freed < pages_to_free) {
1191 if (debug_process_killing) { 1251 if (debug_process_killing) {
1192 ALOGI("Trying to free %d pages", pages_to_free); 1252 ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed);
1193 }
1194 int pages_freed = find_and_kill_processes(level, pages_to_free);
1195 if (pages_freed < pages_to_free) {
1196 if (debug_process_killing) {
1197 ALOGI("Unable to free enough memory (pages freed=%d)",
1198 pages_freed);
1199 }
1200 } else {
1201 gettimeofday(&last_report_tm, NULL);
1202 } 1253 }
1254 } else {
1255 gettimeofday(&last_report_tm, NULL);
1203 } 1256 }
1204 } 1257 }
1205} 1258}
@@ -1409,6 +1462,8 @@ int main(int argc __unused, char **argv __unused) {
1409 low_ram_device = property_get_bool("ro.config.low_ram", false); 1462 low_ram_device = property_get_bool("ro.config.low_ram", false);
1410 kill_timeout_ms = 1463 kill_timeout_ms =
1411 (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0); 1464 (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
1465 use_minfree_levels =
1466 property_get_bool("ro.lmk.use_minfree_levels", false);
1412 1467
1413 if (!init()) { 1468 if (!init()) {
1414 if (!use_inkernel_interface) { 1469 if (!use_inkernel_interface) {