xref: /xnu-8792.81.2/bsd/kern/kern_memorystatus_policy.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1 /*
2  * Copyright (c) 2006-2021 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  *
28  */
29 
30 #include <kern/task.h>
31 #include <libkern/libkern.h>
32 #include <machine/atomic.h>
33 #include <mach/coalition.h>
34 #include <os/log.h>
35 #include <sys/coalition.h>
36 #include <sys/proc.h>
37 #include <sys/proc_internal.h>
38 #include <sys/kdebug.h>
39 #include <sys/kern_memorystatus.h>
40 #include <vm/vm_protos.h>
41 
42 #include "kern_memorystatus_internal.h"
43 
44 /*
45  * All memory pressure policy decisions should live here, and there should be
46  * as little mechanism as possible. This file prioritizes readability.
47  */
48 
49 #pragma mark Policy Function Declarations
50 
51 #if CONFIG_JETSAM
52 static bool memorystatus_check_aggressive_jetsam_needed(int *jld_idle_kills);
53 #endif /* CONFIG_JETSAM */
54 
55 #pragma mark Memorystatus Health Check
56 
57 /*
58  * Each subsystem that relies on the memorystatus thread
59  * for resource exhaustion should put a health check in this section.
60  * The memorystatus thread runs all of the health checks
61  * to determine if the system is healthy. If the system is unhealthy
62  * it picks an action based on the system health status. See the
63  * Memorystatus Thread Actions section below.
64  */
65 
66 extern bool vm_compressor_needs_to_swap(bool wake_memorystatus_thread);
67 extern boolean_t vm_compressor_low_on_space(void);
68 extern bool vm_compressor_compressed_pages_nearing_limit(void);
69 extern bool vm_compressor_is_thrashing(void);
70 extern bool vm_compressor_swapout_is_ripe(void);
71 
72 static void
memorystatus_health_check(memorystatus_system_health_t * status)73 memorystatus_health_check(memorystatus_system_health_t *status)
74 {
75 	memset(status, 0, sizeof(memorystatus_system_health_t));
76 #if CONFIG_JETSAM
77 	status->msh_available_pages_below_pressure = memorystatus_avail_pages_below_pressure();
78 	status->msh_available_pages_below_critical = memorystatus_avail_pages_below_critical();
79 	status->msh_compressor_is_low_on_space = (vm_compressor_low_on_space() == TRUE);
80 	status->msh_compressed_pages_nearing_limit = vm_compressor_compressed_pages_nearing_limit();
81 	status->msh_compressor_is_thrashing = !memorystatus_swap_all_apps && vm_compressor_is_thrashing();
82 #if CONFIG_PHANTOM_CACHE
83 	status->msh_phantom_cache_pressure = os_atomic_load(&memorystatus_phantom_cache_pressure, acquire);
84 #else
85 	status->msh_phantom_cache_pressure = false;
86 #endif /* CONFIG_PHANTOM_CACHE */
87 	if (!memorystatus_swap_all_apps &&
88 	    status->msh_phantom_cache_pressure &&
89 	    !(status->msh_compressor_is_thrashing && status->msh_compressor_is_low_on_space)) {
90 		status->msh_filecache_is_thrashing = true;
91 	}
92 	if (os_atomic_load(&memorystatus_compressor_space_shortage, relaxed)) {
93 		status->msh_compressor_is_low_on_space = true;
94 	}
95 	status->msh_swappable_compressor_segments_over_limit = memorystatus_swap_over_trigger(100);
96 	status->msh_swapin_queue_over_limit = memorystatus_swapin_over_trigger();
97 	status->msh_swap_low_on_space = vm_swap_low_on_space();
98 	status->msh_swap_out_of_space = vm_swap_out_of_space();
99 #endif /* CONFIG_JETSAM */
100 	status->msh_zone_map_is_exhausted = os_atomic_load(&memorystatus_zone_map_is_exhausted, relaxed);
101 }
102 
103 bool
memorystatus_is_system_healthy(const memorystatus_system_health_t * status)104 memorystatus_is_system_healthy(const memorystatus_system_health_t *status)
105 {
106 #if CONFIG_JETSAM
107 	return !(status->msh_available_pages_below_critical
108 	       || status->msh_compressor_is_low_on_space
109 	       || status->msh_compressor_is_thrashing
110 	       || status->msh_filecache_is_thrashing
111 	       || status->msh_zone_map_is_exhausted);
112 #else /* CONFIG_JETSAM */
113 	return !status->msh_zone_map_is_exhausted;
114 #endif /* CONFIG_JETSAM */
115 }
116 
117 
118 #pragma mark Memorystatus Thread Actions
119 
120 /*
121  * This section picks the appropriate memorystatus_action & deploys it.
122  */
123 
124 /*
125  * Inspects the state of various resources in the system to see if
126  * the system is healthy. If the system is not healthy, picks a
127  * memorystatus_action_t to recover the system.
128  *
129  * Every time the memorystatus thread wakes up it calls into here
130  * to pick an action. It will continue performing memorystatus actions until this
131  * function returns MEMORYSTATUS_KILL_NONE. At that point the thread will block.
132  */
133 memorystatus_action_t
memorystatus_pick_action(struct jetsam_thread_state * jetsam_thread,uint32_t * kill_cause,bool highwater_remaining,bool suspended_swappable_apps_remaining,bool swappable_apps_remaining,int * jld_idle_kills)134 memorystatus_pick_action(struct jetsam_thread_state *jetsam_thread,
135     uint32_t *kill_cause,
136     bool highwater_remaining,
137     bool suspended_swappable_apps_remaining,
138     bool swappable_apps_remaining,
139     int *jld_idle_kills)
140 {
141 	memorystatus_system_health_t status;
142 	memorystatus_health_check(&status);
143 	memorystatus_log_system_health(&status);
144 	bool is_system_healthy = memorystatus_is_system_healthy(&status);
145 
146 #if CONFIG_JETSAM
147 	if (status.msh_available_pages_below_pressure || !is_system_healthy) {
148 		/*
149 		 * If swap is enabled, first check if we're running low or are out of swap space.
150 		 */
151 		if (memorystatus_swap_all_apps && jetsam_kill_on_low_swap) {
152 			if (swappable_apps_remaining && status.msh_swap_out_of_space) {
153 				*kill_cause = kMemorystatusKilledLowSwap;
154 				return MEMORYSTATUS_KILL_SWAPPABLE;
155 			} else if (suspended_swappable_apps_remaining && status.msh_swap_low_on_space) {
156 				*kill_cause = kMemorystatusKilledLowSwap;
157 				return MEMORYSTATUS_KILL_SUSPENDED_SWAPPABLE;
158 			}
159 		}
160 
161 		/*
162 		 * We're below the pressure level or the system is unhealthy,
163 		 * regardless of the system health let's check if we should be swapping
164 		 * and if there are high watermark kills left to do.
165 		 */
166 		if (memorystatus_swap_all_apps) {
167 			if (status.msh_swappable_compressor_segments_over_limit && !vm_swapout_thread_running && !os_atomic_load(&vm_swapout_wake_pending, relaxed)) {
168 				/*
169 				 * TODO: The swapper will keep running until it has drained the entire early swapout queue.
170 				 * That might be overly aggressive & we should look into tuning it.
171 				 * See rdar://84102304.
172 				 */
173 				return MEMORYSTATUS_WAKE_SWAPPER;
174 			} else if (status.msh_swapin_queue_over_limit) {
175 				return MEMORYSTATUS_PROCESS_SWAPIN_QUEUE;
176 			} else if (status.msh_swappable_compressor_segments_over_limit) {
177 				os_log_with_startup_serial(OS_LOG_DEFAULT, "memorystatus: Skipping swap wakeup because the swap thread is already running. vm_swapout_thread_running=%d, vm_swapout_wake_pending=%d\n", vm_swapout_thread_running, os_atomic_load(&vm_swapout_wake_pending, relaxed));
178 			}
179 		}
180 
181 		if (highwater_remaining) {
182 			*kill_cause = kMemorystatusKilledHiwat;
183 			os_log_with_startup_serial(OS_LOG_DEFAULT, "memorystatus: Looking for highwatermark kills.\n");
184 			return MEMORYSTATUS_KILL_HIWATER;
185 		}
186 	}
187 
188 	if (is_system_healthy) {
189 		*kill_cause = 0;
190 		return MEMORYSTATUS_KILL_NONE;
191 	}
192 
193 	/*
194 	 * At this point the system is unhealthy and there are no
195 	 * more highwatermark processes to kill.
196 	 */
197 
198 	if (!jetsam_thread->limit_to_low_bands) {
199 		if (memorystatus_check_aggressive_jetsam_needed(jld_idle_kills)) {
200 			os_log_with_startup_serial(OS_LOG_DEFAULT, "memorystatus: Starting aggressive jetsam.\n");
201 			*kill_cause = kMemorystatusKilledProcThrashing;
202 			return MEMORYSTATUS_KILL_AGGRESSIVE;
203 		}
204 	}
205 	/*
206 	 * The system is unhealthy and we either don't need aggressive jetsam
207 	 * or are not allowed to deploy it.
208 	 * Kill in priority order. We'll use LRU within every band except the
209 	 * FG (which will be sorted by coalition role).
210 	 */
211 	*kill_cause = memorystatus_pick_kill_cause(&status);
212 	return MEMORYSTATUS_KILL_TOP_PROCESS;
213 #else /* CONFIG_JETSAM */
214 	(void) jetsam_thread;
215 	(void) jld_idle_kills;
216 	(void) suspended_swappable_apps_remaining;
217 	(void) swappable_apps_remaining;
218 	/*
219 	 * Without CONFIG_JETSAM, we only kill if the system is unhealthy.
220 	 * There is no aggressive jetsam and no
221 	 * early highwatermark killing.
222 	 */
223 	if (is_system_healthy) {
224 		*kill_cause = 0;
225 		return MEMORYSTATUS_KILL_NONE;
226 	}
227 	if (highwater_remaining) {
228 		*kill_cause = kMemorystatusKilledHiwat;
229 		return MEMORYSTATUS_KILL_HIWATER;
230 	} else {
231 		*kill_cause = memorystatus_pick_kill_cause(&status);
232 		return MEMORYSTATUS_KILL_TOP_PROCESS;
233 	}
234 #endif /* CONFIG_JETSAM */
235 }
236 
237 #pragma mark Aggressive Jetsam
238 /*
239  * This section defines when we deploy aggressive jetsam.
240  * Aggressive jetsam kills everything up to the jld_priority_band_max band.
241  */
242 
243 #if CONFIG_JETSAM
244 
245 static bool
246 memorystatus_aggressive_jetsam_needed_sysproc_aging(__unused int jld_eval_aggressive_count, __unused int *jld_idle_kills, __unused int jld_idle_kill_candidates, int *total_candidates);
247 
248 /*
249  * kJetsamHighRelaunchCandidatesThreshold defines the percentage of candidates
250  * in the idle & deferred bands that need to be bad candidates in order to trigger
251  * aggressive jetsam.
252  */
253 #define kJetsamHighRelaunchCandidatesThreshold  (100)
254 
255 /* kJetsamMinCandidatesThreshold defines the minimum number of candidates in the
256  * idle/deferred bands to trigger aggressive jetsam. This value basically decides
257  * how much memory the system is ready to hold in the lower bands without triggering
258  * aggressive jetsam. This number should ideally be tuned based on the memory config
259  * of the device.
260  */
261 #define kJetsamMinCandidatesThreshold           (5)
262 
263 static bool
memorystatus_check_aggressive_jetsam_needed(int * jld_idle_kills)264 memorystatus_check_aggressive_jetsam_needed(int *jld_idle_kills)
265 {
266 	bool aggressive_jetsam_needed = false;
267 	int total_candidates = 0;
268 	/*
269 	 * The aggressive jetsam logic looks at the number of times it has been in the
270 	 * aggressive loop to determine the max priority band it should kill upto. The
271 	 * static variables below are used to track that property.
272 	 *
273 	 * To reset those values, the implementation checks if it has been
274 	 * memorystatus_jld_eval_period_msecs since the parameters were reset.
275 	 */
276 
277 	if (memorystatus_jld_enabled == FALSE) {
278 		/* If aggressive jetsam is disabled, nothing to do here */
279 		return FALSE;
280 	}
281 
282 	/* Get current timestamp (msecs only) */
283 	struct timeval  jld_now_tstamp = {0, 0};
284 	uint64_t        jld_now_msecs = 0;
285 	microuptime(&jld_now_tstamp);
286 	jld_now_msecs = (jld_now_tstamp.tv_sec * 1000);
287 
288 	/*
289 	 * Look at the number of candidates in the idle and deferred band and
290 	 * how many out of them are marked as high relaunch probability.
291 	 */
292 	aggressive_jetsam_needed = memorystatus_aggressive_jetsam_needed_sysproc_aging(jld_eval_aggressive_count,
293 	    jld_idle_kills, jld_idle_kill_candidates, &total_candidates);
294 
295 	/*
296 	 * Check if its been really long since the aggressive jetsam evaluation
297 	 * parameters have been refreshed. This logic also resets the jld_eval_aggressive_count
298 	 * counter to make sure we reset the aggressive jetsam severity.
299 	 */
300 	boolean_t param_reval = false;
301 
302 	if ((total_candidates == 0) ||
303 	    (jld_now_msecs > (jld_timestamp_msecs + memorystatus_jld_eval_period_msecs))) {
304 		jld_timestamp_msecs      = jld_now_msecs;
305 		jld_idle_kill_candidates = total_candidates;
306 		*jld_idle_kills          = 0;
307 		jld_eval_aggressive_count = 0;
308 		jld_priority_band_max   = JETSAM_PRIORITY_UI_SUPPORT;
309 		param_reval = true;
310 	}
311 
312 	/*
313 	 * It is also possible that the system is down to a very small number of processes in the candidate
314 	 * bands. In that case, the decisions made by the memorystatus_aggressive_jetsam_needed_* routines
315 	 * would not be useful. In that case, do not trigger aggressive jetsam.
316 	 */
317 	if (total_candidates < kJetsamMinCandidatesThreshold) {
318 #if DEVELOPMENT || DEBUG
319 		printf("memorystatus: aggressive: [FAILED] Low Candidate Count (current: %d, threshold: %d)\n", total_candidates, kJetsamMinCandidatesThreshold);
320 #endif /* DEVELOPMENT || DEBUG */
321 		aggressive_jetsam_needed = false;
322 	}
323 	return aggressive_jetsam_needed;
324 }
325 
326 static bool
memorystatus_aggressive_jetsam_needed_sysproc_aging(__unused int eval_aggressive_count,__unused int * idle_kills,__unused int idle_kill_candidates,int * total_candidates)327 memorystatus_aggressive_jetsam_needed_sysproc_aging(__unused int eval_aggressive_count, __unused int *idle_kills, __unused int idle_kill_candidates, int *total_candidates)
328 {
329 	bool aggressive_jetsam_needed = false;
330 
331 	/*
332 	 * For the kJetsamAgingPolicySysProcsReclaimedFirst aging policy, we maintain the jetsam
333 	 * relaunch behavior for all daemons. Also, daemons and apps are aged in deferred bands on
334 	 * every dirty->clean transition. For this aging policy, the best way to determine if
335 	 * aggressive jetsam is needed, is to see if the kill candidates are mostly bad candidates.
336 	 * If yes, then we need to go to higher bands to reclaim memory.
337 	 */
338 	proc_list_lock();
339 	/* Get total candidate counts for idle and idle deferred bands */
340 	*total_candidates = memstat_bucket[JETSAM_PRIORITY_IDLE].count + memstat_bucket[system_procs_aging_band].count;
341 	/* Get counts of bad kill candidates in idle and idle deferred bands */
342 	int bad_candidates = memstat_bucket[JETSAM_PRIORITY_IDLE].relaunch_high_count + memstat_bucket[system_procs_aging_band].relaunch_high_count;
343 
344 	proc_list_unlock();
345 
346 	/* Check if the number of bad candidates is greater than kJetsamHighRelaunchCandidatesThreshold % */
347 	aggressive_jetsam_needed = (((bad_candidates * 100) / *total_candidates) >= kJetsamHighRelaunchCandidatesThreshold);
348 
349 	/*
350 	 * Since the new aging policy bases the aggressive jetsam trigger on percentage of
351 	 * bad candidates, it is prone to being overly aggressive. In order to mitigate that,
352 	 * make sure the system is really under memory pressure before triggering aggressive
353 	 * jetsam.
354 	 */
355 	if (memorystatus_available_pages > memorystatus_sysproc_aging_aggr_pages) {
356 		aggressive_jetsam_needed = false;
357 	}
358 
359 #if DEVELOPMENT || DEBUG
360 	printf("memorystatus: aggressive%d: [%s] Bad Candidate Threshold Check (total: %d, bad: %d, threshold: %d %%); Memory Pressure Check (available_pgs: %llu, threshold_pgs: %llu)\n",
361 	    eval_aggressive_count, aggressive_jetsam_needed ? "PASSED" : "FAILED", *total_candidates, bad_candidates,
362 	    kJetsamHighRelaunchCandidatesThreshold, (uint64_t)MEMORYSTATUS_LOG_AVAILABLE_PAGES, (uint64_t)memorystatus_sysproc_aging_aggr_pages);
363 #endif /* DEVELOPMENT || DEBUG */
364 	return aggressive_jetsam_needed;
365 }
366 
367 #endif /* CONFIG_JETSAM */
368 
369 #pragma mark Freezer
370 #if CONFIG_FREEZE
371 /*
372  * Freezer policies
373  */
374 
375 /*
376  * These functions determine what is eligible for the freezer
377  * and the order that we consider freezing them
378  */
379 
380 /*
381  * Checks if the given process is eligible for the freezer.
382  * Processes can only be frozen if this returns true.
383  */
384 bool
memorystatus_is_process_eligible_for_freeze(proc_t p)385 memorystatus_is_process_eligible_for_freeze(proc_t p)
386 {
387 	/*
388 	 * Called with proc_list_lock held.
389 	 */
390 
391 	LCK_MTX_ASSERT(&proc_list_mlock, LCK_MTX_ASSERT_OWNED);
392 
393 	bool should_freeze = false;
394 	uint32_t state = 0, pages = 0;
395 	bool first_consideration = true;
396 	task_t task;
397 
398 	state = p->p_memstat_state;
399 
400 	if (state & (P_MEMSTAT_TERMINATED | P_MEMSTAT_LOCKED | P_MEMSTAT_FREEZE_DISABLED | P_MEMSTAT_FREEZE_IGNORE)) {
401 		if (state & P_MEMSTAT_FREEZE_DISABLED) {
402 			p->p_memstat_freeze_skip_reason = kMemorystatusFreezeSkipReasonDisabled;
403 		}
404 		goto out;
405 	}
406 
407 	task = proc_task(p);
408 
409 	if (isSysProc(p)) {
410 		/*
411 		 * Daemon:- We consider freezing it if:
412 		 * - it belongs to a coalition and the leader is frozen, and,
413 		 * - its role in the coalition is XPC service.
414 		 *
415 		 * We skip memory size requirements in this case.
416 		 */
417 		int task_role_in_coalition = 0;
418 		proc_t leader_proc = memorystatus_get_coalition_leader_and_role(p, &task_role_in_coalition);
419 		if (leader_proc == PROC_NULL || leader_proc == p) {
420 			/*
421 			 * Jetsam coalition is leaderless or the leader is not an app.
422 			 * Either way, don't freeze this proc.
423 			 */
424 			goto out;
425 		}
426 
427 		/* Leader must be frozen */
428 		if (!(leader_proc->p_memstat_state & P_MEMSTAT_FROZEN)) {
429 			goto out;
430 		}
431 		/* Only freeze XPC services */
432 		if (task_role_in_coalition == COALITION_TASKROLE_XPC) {
433 			should_freeze = true;
434 		}
435 
436 		goto out;
437 	} else {
438 		/*
439 		 * Application. Only freeze if it's suspended.
440 		 */
441 		if (!(state & P_MEMSTAT_SUSPENDED)) {
442 			goto out;
443 		}
444 	}
445 
446 	/*
447 	 * We're interested in tracking what percentage of
448 	 * eligible apps actually get frozen.
449 	 * To avoid skewing the metrics towards processes which
450 	 * are considered more frequently, we only track failures once
451 	 * per process.
452 	 */
453 	first_consideration = !(state & P_MEMSTAT_FREEZE_CONSIDERED);
454 
455 	if (first_consideration) {
456 		memorystatus_freezer_stats.mfs_process_considered_count++;
457 		p->p_memstat_state |= P_MEMSTAT_FREEZE_CONSIDERED;
458 	}
459 
460 	/* Only freeze applications meeting our minimum resident page criteria */
461 	memorystatus_get_task_page_counts(proc_task(p), &pages, NULL, NULL);
462 	if (pages < memorystatus_freeze_pages_min) {
463 		if (first_consideration) {
464 			memorystatus_freezer_stats.mfs_error_below_min_pages_count++;
465 		}
466 		p->p_memstat_freeze_skip_reason = kMemorystatusFreezeSkipReasonBelowMinPages;
467 		goto out;
468 	}
469 
470 	/* Don't freeze processes that are already exiting on core. It may have started exiting
471 	 * after we chose it for freeze, but before we obtained the proc_list_lock.
472 	 * NB: This is only possible if we're coming in from memorystatus_freeze_process_sync.
473 	 * memorystatus_freeze_top_process holds the proc_list_lock while it traverses the bands.
474 	 */
475 	if (proc_list_exited(p)) {
476 		if (first_consideration) {
477 			memorystatus_freezer_stats.mfs_error_other_count++;
478 		}
479 		p->p_memstat_freeze_skip_reason = kMemorystatusFreezeSkipReasonOther;
480 		goto out;
481 	}
482 
483 	if (!memorystatus_freezer_use_ordered_list) {
484 		/*
485 		 * We're not using the ordered list so we need to check
486 		 * that dasd recommended the process. Note that the ordered list
487 		 * algorithm only considers processes on the list in the first place
488 		 * so there's no need to double check here.
489 		 */
490 		if (!memorystatus_freeze_process_is_recommended(p)) {
491 			if (first_consideration) {
492 				memorystatus_freezer_stats.mfs_error_low_probability_of_use_count++;
493 			}
494 			p->p_memstat_freeze_skip_reason = kMemorystatusFreezeSkipReasonLowProbOfUse;
495 			goto out;
496 		}
497 	}
498 
499 	if (!(state & P_MEMSTAT_FROZEN) && p->p_memstat_effectivepriority > memorystatus_freeze_max_candidate_band) {
500 		/*
501 		 * Proc has been elevated by something else.
502 		 * Don't freeze it.
503 		 */
504 		if (first_consideration) {
505 			memorystatus_freezer_stats.mfs_error_elevated_count++;
506 		}
507 		p->p_memstat_freeze_skip_reason = kMemorystatusFreezeSkipReasonElevated;
508 		goto out;
509 	}
510 
511 	should_freeze = true;
512 out:
513 	if (should_freeze && !(state & P_MEMSTAT_FROZEN)) {
514 		/*
515 		 * Reset the skip reason. If it's killed before we manage to actually freeze it
516 		 * we failed to consider it early enough.
517 		 */
518 		p->p_memstat_freeze_skip_reason = kMemorystatusFreezeSkipReasonNone;
519 		if (!first_consideration) {
520 			/*
521 			 * We're freezing this for the first time and we previously considered it ineligible.
522 			 * Bump the considered count so that we track this as 1 failure
523 			 * and 1 success.
524 			 */
525 			memorystatus_freezer_stats.mfs_process_considered_count++;
526 		}
527 	}
528 	return should_freeze;
529 }
530 
531 bool
memorystatus_freeze_proc_is_refreeze_eligible(proc_t p)532 memorystatus_freeze_proc_is_refreeze_eligible(proc_t p)
533 {
534 	return (p->p_memstat_state & P_MEMSTAT_REFREEZE_ELIGIBLE) != 0;
535 }
536 
537 
538 static proc_t
memorystatus_freeze_pick_refreeze_process(proc_t last_p)539 memorystatus_freeze_pick_refreeze_process(proc_t last_p)
540 {
541 	proc_t p = PROC_NULL, next_p = PROC_NULL;
542 	unsigned int band = (unsigned int) memorystatus_freeze_jetsam_band;
543 	if (last_p == PROC_NULL) {
544 		next_p = memorystatus_get_first_proc_locked(&band, FALSE);
545 	} else {
546 		next_p = memorystatus_get_next_proc_locked(&band, last_p, FALSE);
547 	}
548 	while (next_p) {
549 		p = next_p;
550 		next_p = memorystatus_get_next_proc_locked(&band, p, FALSE);
551 		if ((p->p_memstat_state & P_MEMSTAT_FROZEN) && !memorystatus_freeze_proc_is_refreeze_eligible(p)) {
552 			/* Process is already frozen & hasn't been thawed. */
553 			continue;
554 		}
555 		/*
556 		 * Has to have been frozen once before.
557 		 */
558 		if (!(p->p_memstat_state & P_MEMSTAT_FROZEN)) {
559 			continue;
560 		}
561 
562 		/*
563 		 * Not currently being looked at for something.
564 		 */
565 		if (p->p_memstat_state & P_MEMSTAT_LOCKED) {
566 			continue;
567 		}
568 		/*
569 		 * Found it
570 		 */
571 		break;
572 	}
573 	return p;
574 }
575 
576 proc_t
memorystatus_freeze_pick_process(struct memorystatus_freeze_list_iterator * iterator)577 memorystatus_freeze_pick_process(struct memorystatus_freeze_list_iterator *iterator)
578 {
579 	proc_t p = PROC_NULL, next_p = PROC_NULL;
580 	unsigned int band = JETSAM_PRIORITY_IDLE;
581 
582 	LCK_MTX_ASSERT(&proc_list_mlock, LCK_MTX_ASSERT_OWNED);
583 	/*
584 	 * If the freezer is full, only consider refreezes.
585 	 */
586 	if (iterator->refreeze_only || memorystatus_frozen_count >= memorystatus_frozen_processes_max) {
587 		if (!iterator->refreeze_only) {
588 			/*
589 			 * The first time the iterator starts to return refreeze
590 			 * candidates, we need to reset the last pointer b/c it's pointing into the wrong band.
591 			 */
592 			iterator->last_p = PROC_NULL;
593 			iterator->refreeze_only = true;
594 		}
595 		iterator->last_p = memorystatus_freeze_pick_refreeze_process(iterator->last_p);
596 		return iterator->last_p;
597 	}
598 
599 	/*
600 	 * Search for the next freezer candidate.
601 	 */
602 	if (memorystatus_freezer_use_ordered_list) {
603 		next_p = memorystatus_freezer_candidate_list_get_proc(
604 			&memorystatus_global_freeze_list,
605 			(iterator->global_freeze_list_index)++,
606 			&memorystatus_freezer_stats.mfs_freeze_pid_mismatches);
607 	} else if (iterator->last_p == PROC_NULL) {
608 		next_p = memorystatus_get_first_proc_locked(&band, FALSE);
609 	} else {
610 		next_p = memorystatus_get_next_proc_locked(&band, iterator->last_p, FALSE);
611 	}
612 	while (next_p) {
613 		p = next_p;
614 		if (memorystatus_is_process_eligible_for_freeze(p)) {
615 			iterator->last_p = p;
616 			return iterator->last_p;
617 		} else {
618 			if (memorystatus_freezer_use_ordered_list) {
619 				next_p = memorystatus_freezer_candidate_list_get_proc(
620 					&memorystatus_global_freeze_list,
621 					(iterator->global_freeze_list_index)++,
622 					&memorystatus_freezer_stats.mfs_freeze_pid_mismatches);
623 			} else {
624 				next_p = memorystatus_get_next_proc_locked(&band, p, FALSE);
625 			}
626 		}
627 	}
628 
629 	/*
630 	 * Failed to find a new freezer candidate.
631 	 * Try to re-freeze.
632 	 */
633 	if (memorystatus_refreeze_eligible_count >= MIN_THAW_REFREEZE_THRESHOLD) {
634 		assert(!iterator->refreeze_only);
635 		iterator->refreeze_only = true;
636 		iterator->last_p = memorystatus_freeze_pick_refreeze_process(PROC_NULL);
637 		return iterator->last_p;
638 	}
639 	return PROC_NULL;
640 }
641 
642 /*
643  * memorystatus_pages_update calls this function whenever the number
644  * of available pages changes. It wakes the freezer thread iff the function returns
645  * true. The freezer thread will try to freeze (or refreeze) up to 1 process
646  * before blocking again.
647  *
648  * Note the freezer thread is also woken up by memorystatus_on_inactivity.
649  */
650 
651 bool
memorystatus_freeze_thread_should_run()652 memorystatus_freeze_thread_should_run()
653 {
654 	/*
655 	 * No freezer_mutex held here...see why near call-site
656 	 * within memorystatus_pages_update().
657 	 */
658 
659 	if (memorystatus_freeze_enabled == FALSE) {
660 		return false;
661 	}
662 
663 	if (memorystatus_available_pages > memorystatus_freeze_threshold) {
664 		return false;
665 	}
666 
667 	memorystatus_freezer_stats.mfs_below_threshold_count++;
668 
669 	if ((memorystatus_frozen_count >= memorystatus_frozen_processes_max)) {
670 		/*
671 		 * Consider this as a skip even if we wake up to refreeze because
672 		 * we won't freeze any new procs.
673 		 */
674 		memorystatus_freezer_stats.mfs_skipped_full_count++;
675 		if (memorystatus_refreeze_eligible_count < MIN_THAW_REFREEZE_THRESHOLD) {
676 			return false;
677 		}
678 	}
679 
680 	if (memorystatus_frozen_shared_mb_max && (memorystatus_frozen_shared_mb >= memorystatus_frozen_shared_mb_max)) {
681 		memorystatus_freezer_stats.mfs_skipped_shared_mb_high_count++;
682 		return false;
683 	}
684 
685 	uint64_t curr_time = mach_absolute_time();
686 
687 	if (curr_time < memorystatus_freezer_thread_next_run_ts) {
688 		return false;
689 	}
690 
691 	return true;
692 }
693 
694 size_t
memorystatus_pick_freeze_count_for_wakeup()695 memorystatus_pick_freeze_count_for_wakeup()
696 {
697 	size_t num_to_freeze = 0;
698 	if (!memorystatus_swap_all_apps) {
699 		num_to_freeze = 1;
700 	} else {
701 		/*
702 		 * When app swap is enabled, we want the freezer thread to aggressively freeze
703 		 * all candidates so we clear out space for the fg working set.
704 		 * But we still cap it to the current size of the candidate bands to avoid
705 		 * consuming excessive CPU if there's a lot of churn in the candidate band.
706 		 */
707 		proc_list_lock();
708 		for (unsigned int band = JETSAM_PRIORITY_IDLE; band <= memorystatus_freeze_max_candidate_band; band++) {
709 			num_to_freeze += memstat_bucket[band].count;
710 		}
711 		proc_list_unlock();
712 	}
713 
714 	return num_to_freeze;
715 }
716 
717 #endif /* CONFIG_FREEZE */
718