1 | /* |
2 | * Copyright (c) 2006-2018 Apple Computer, 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 | #ifndef SYS_MEMORYSTATUS_FREEZE_H |
30 | #define SYS_MEMORYSTATUS_FREEZE_H |
31 | |
32 | #include <stdint.h> |
33 | #include <sys/time.h> |
34 | #include <sys/proc.h> |
35 | #include <sys/param.h> |
36 | #include <sys/kern_memorystatus.h> |
37 | #include <mach/resource_monitors.h> // command/proc_name_t |
38 | #include <uuid/uuid.h> |
39 | |
40 | typedef struct memorystatus_freeze_entry { |
41 | int32_t pid; |
42 | uint32_t flags; |
43 | uint32_t pages; |
44 | } memorystatus_freeze_entry_t; |
45 | |
46 | #ifdef PRIVATE |
47 | #define FREEZE_PROCESSES_MAX 20 |
48 | #define FREEZE_PROCESSES_MAX_SWAP_ENABLED 36 |
49 | #endif /* PRIVATE */ |
50 | |
51 | #ifdef XNU_KERNEL_PRIVATE |
52 | |
53 | extern unsigned long freeze_threshold_percentage; |
54 | extern unsigned int memorystatus_frozen_count; /* # of processes that are currently frozen. */ |
55 | extern unsigned int memorystatus_frozen_count_webcontent; /* # of webcontent processes that are currently frozen. */ |
56 | extern unsigned int memorystatus_frozen_count_xpc_service; /* # of xpc services that are currently frozen. */ |
57 | extern unsigned int memorystatus_frozen_processes_max; |
58 | extern unsigned int memorystatus_frozen_shared_mb; |
59 | extern unsigned int memorystatus_frozen_shared_mb_max; |
60 | extern unsigned int memorystatus_freeze_shared_mb_per_process_max; /* Max. MB allowed per process to be freezer-eligible. */ |
61 | extern unsigned int memorystatus_freeze_private_shared_pages_ratio; /* Ratio of private:shared pages for a process to be freezer-eligible. */ |
62 | extern unsigned int memorystatus_suspended_count; |
63 | extern unsigned int memorystatus_thaw_count; /* # of processes that have been thawed in the current interval. */ |
64 | extern unsigned int memorystatus_refreeze_eligible_count; /* # of processes currently thawed i.e. have state on disk & in-memory */ |
65 | extern unsigned int memorystatus_freeze_max_candidate_band; |
66 | extern uint32_t memorystatus_freeze_current_interval; /* Monotonically increasing interval id. */ |
67 | |
68 | void memorystatus_freeze_init(void); |
69 | extern int memorystatus_freeze_process_sync(proc_t p); |
70 | |
71 | #ifdef CONFIG_FREEZE |
72 | extern int memorystatus_entitled_max_task_footprint_mb; |
73 | |
74 | #if XNU_TARGET_OS_WATCH |
75 | #define FREEZE_PAGES_MIN ( 2 * 1024 * 1024 / PAGE_SIZE) |
76 | #else |
77 | #define FREEZE_PAGES_MIN ( 8 * 1024 * 1024 / PAGE_SIZE) |
78 | #endif |
79 | #define FREEZE_PAGES_MAX (max_task_footprint_mb == 0 ? INT_MAX : (max_task_footprint_mb << (20 - PAGE_SHIFT))) |
80 | #define FREEZE_PAGES_MAX_SWAP_ENABLED \ |
81 | (memorystatus_entitled_max_task_footprint_mb == 0 ? INT_MAX : (memorystatus_entitled_max_task_footprint_mb << (20 - PAGE_SHIFT))) |
82 | |
83 | #if XNU_TARGET_OS_WATCH |
84 | #define FREEZE_SUSPENDED_THRESHOLD_DEFAULT 0 |
85 | #else |
86 | #define FREEZE_SUSPENDED_THRESHOLD_DEFAULT 4 |
87 | #endif |
88 | |
89 | #define FREEZE_DAILY_MB_MAX_DEFAULT 1024 |
90 | #define FREEZE_DEGRADATION_BUDGET_THRESHOLD 25 //degraded perf. when the daily budget left falls below this threshold percentage |
91 | |
92 | #define MAX_FROZEN_SHARED_MB_PERCENT 10 |
93 | #define MAX_FROZEN_PROCESS_DEMOTIONS 2 |
94 | #define MAX_FROZEN_PROCESS_DEMOTIONS_SWAP_ENABLED 4 |
95 | #define MIN_THAW_DEMOTION_THRESHOLD 5 |
96 | |
97 | #if XNU_TARGET_OS_WATCH |
98 | #define MIN_THAW_REFREEZE_THRESHOLD 0 |
99 | #else |
100 | #define MIN_THAW_REFREEZE_THRESHOLD 3 |
101 | #endif |
102 | |
103 | #if XNU_TARGET_OS_WATCH |
104 | #define FREEZE_MAX_CANDIDATE_BAND JETSAM_PRIORITY_ELEVATED_INACTIVE |
105 | #else |
106 | #define FREEZE_MAX_CANDIDATE_BAND JETSAM_PRIORITY_AGING_BAND2 |
107 | #endif |
108 | |
109 | |
110 | typedef struct throttle_interval_t { |
111 | uint32_t mins; |
112 | uint32_t burst_multiple; |
113 | uint32_t pageouts; |
114 | uint32_t max_pageouts; |
115 | mach_timespec_t ts; |
116 | } throttle_interval_t; |
117 | |
118 | extern bool memorystatus_freeze_enabled; |
119 | extern int memorystatus_freeze_wakeup; |
120 | |
121 | /* Thresholds */ |
122 | extern unsigned int memorystatus_freeze_threshold; |
123 | extern unsigned int memorystatus_freeze_pages_min; |
124 | extern unsigned int memorystatus_freeze_pages_max; |
125 | extern unsigned int memorystatus_freeze_suspended_threshold; |
126 | extern unsigned int memorystatus_freeze_daily_mb_max; |
127 | extern uint64_t memorystatus_freeze_budget_pages_remaining; //remaining # of pages that can be frozen to disk |
128 | extern boolean_t memorystatus_freeze_degradation; //protected by the freezer mutex. Signals we are in a degraded freeze mode. |
129 | |
130 | extern unsigned int memorystatus_max_frozen_demotions_daily; |
131 | extern unsigned int memorystatus_thaw_count_demotion_threshold; |
132 | extern unsigned int memorystatus_min_thaw_refreeze_threshold; |
133 | |
134 | #if DEVELOPMENT || DEBUG |
135 | #define FREEZER_CONTROL_GET_STATUS (1) |
136 | #endif /* DEVELOPMENT || DEBUG */ |
137 | |
138 | extern int memorystatus_freeze_jetsam_band; /* the jetsam band which will contain P_MEMSTAT_FROZEN processes */ |
139 | |
140 | bool memorystatus_freeze_thread_should_run(void); |
141 | int memorystatus_set_process_is_freezable(pid_t pid, boolean_t is_freezable); |
142 | int memorystatus_get_process_is_freezable(pid_t pid, int *is_freezable); |
143 | int memorystatus_freezer_control(int32_t flags, user_addr_t buffer, size_t buffer_size, int32_t *retval); |
144 | void memorystatus_freeze_init_proc(proc_t p); |
145 | errno_t memorystatus_get_process_is_frozen(pid_t pid, int *is_freezable); |
146 | errno_t memorystatus_cmd_grp_set_freeze_list(user_addr_t buffer, size_t buffer_size); |
147 | errno_t memorystatus_cmd_grp_set_demote_list(user_addr_t buffer, size_t buffer_size); |
148 | |
149 | /* Freezer counters collected for telemtry */ |
150 | struct memorystatus_freezer_stats_t { |
151 | /* |
152 | * # of processes that we've considered freezing. |
153 | * Used to normalize the error reasons below. |
154 | */ |
155 | uint64_t mfs_process_considered_count; |
156 | |
157 | /* |
158 | * The following counters track how many times we've failed to freeze |
159 | * a process because of a specific FREEZER_ERROR. |
160 | */ |
161 | /* EXCESS_SHARED_MEMORY */ |
162 | uint64_t mfs_error_excess_shared_memory_count; |
163 | /* LOW_PRIVATE_SHARED_RATIO */ |
164 | uint64_t mfs_error_low_private_shared_ratio_count; |
165 | /* NO_COMPRESSOR_SPACE */ |
166 | uint64_t mfs_error_no_compressor_space_count; |
167 | /* NO_SWAP_SPACE */ |
168 | uint64_t mfs_error_no_swap_space_count; |
169 | /* pages < memorystatus_freeze_pages_min */ |
170 | uint64_t mfs_error_below_min_pages_count; |
171 | /* dasd determined it was unlikely to be relaunched. */ |
172 | uint64_t mfs_error_low_probability_of_use_count; |
173 | /* not in idle bands */ |
174 | uint64_t mfs_error_elevated_count; |
175 | /* transient reasons (like inability to acquire a lock). */ |
176 | uint64_t mfs_error_other_count; |
177 | |
178 | /* |
179 | * # of times that we saw memorystatus_available_pages <= memorystatus_freeze_threshold. |
180 | * Used to normalize skipped_full_count and shared_mb_high_count. |
181 | */ |
182 | uint64_t mfs_below_threshold_count; |
183 | |
184 | /* Skipped running the freezer because we were out of slots */ |
185 | uint64_t mfs_skipped_full_count; |
186 | |
187 | /* Skipped running the freezer because we were over the shared mb limit*/ |
188 | uint64_t mfs_skipped_shared_mb_high_count; |
189 | |
190 | /* |
191 | * How many pages have not been sent to swap because they were in a shared object? |
192 | * This is being used to gather telemtry so we can understand the impact we'd have |
193 | * on our NAND budget if we did swap out these pages. |
194 | */ |
195 | uint64_t mfs_shared_pages_skipped; |
196 | |
197 | /* |
198 | * A running sum of the total number of bytes sent to NAND during |
199 | * refreeze operations since boot. |
200 | */ |
201 | uint64_t mfs_bytes_refrozen; |
202 | /* The number of refreeze operations since boot */ |
203 | uint64_t mfs_refreeze_count; |
204 | |
205 | /* The number of proceses which have been frozen at least once in the current interval. */ |
206 | uint64_t mfs_processes_frozen; |
207 | /* The number of processes which have been thawed at least once in the current interval. */ |
208 | uint64_t mfs_processes_thawed; |
209 | |
210 | /* |
211 | * Telemetry shows that the majority of freezer usage is attributed to webcontent |
212 | * so we track some specific webcontent telemetry here to get more visibility. |
213 | */ |
214 | |
215 | /* The number of webcontent processes which have been frozen at least once in the current interval. */ |
216 | uint64_t mfs_processes_frozen_webcontent; |
217 | /* The number of webcontent processes which have been thawed at least once in the current interval. */ |
218 | uint64_t mfs_processes_thawed_webcontent; |
219 | |
220 | /* The number of xpc service processes which have been frozen at least once in the current interval. */ |
221 | uint64_t mfs_processes_frozen_xpc_service; |
222 | |
223 | /* The number of fg thaws in the current interval. */ |
224 | uint64_t mfs_processes_thawed_fg; |
225 | /* The number of fg xpc service thaws in the current interval. */ |
226 | uint64_t mfs_processes_thawed_fg_xpc_service; |
227 | |
228 | /* |
229 | * Counts the number of incorrect pids provided via |
230 | * MEMORYSTATUS_FLAGS_GRP_SET_FREEZE_PRIORITY in the current interval. |
231 | * A high value means dasd should be updating the list more |
232 | * frequently. |
233 | */ |
234 | uint64_t mfs_freeze_pid_mismatches; |
235 | /* |
236 | * Counts the number of incorrect pids provided via |
237 | * MEMORYSTATUS_FLAGS_GRP_SET_DEMOTE_PRIORITY in the current interval. |
238 | * A high value means dasd should be updating the list more |
239 | * frequently. |
240 | */ |
241 | uint64_t mfs_demote_pid_mismatches; |
242 | |
243 | /* |
244 | * When we run out of budget, this records how much time is left in the current |
245 | * interval. 0 means we have not run out of budget. |
246 | */ |
247 | uint64_t mfs_budget_exhaustion_duration_remaining; |
248 | |
249 | /* The number of visible resumes in this interval. Mostly used to filter out idle devices. */ |
250 | uint64_t mfs_processes_fg_resumed; |
251 | }; |
252 | extern struct memorystatus_freezer_stats_t memorystatus_freezer_stats; |
253 | |
254 | /* |
255 | * Called by kern_resource when a process gets a UI priority |
256 | */ |
257 | void memorystatus_freezer_mark_ui_transition(proc_t p); |
258 | |
259 | #endif /* CONFIG_FREEZE */ |
260 | |
261 | #endif /* XNU_KERNEL_PRIVATE */ |
262 | |
263 | #ifdef PRIVATE |
264 | /* Lists all the processes that are currently in the freezer. */ |
265 | #define FREEZER_CONTROL_GET_PROCS (2) |
266 | |
267 | #define FREEZER_CONTROL_GET_PROCS_MAX_COUNT (FREEZE_PROCESSES_MAX * 2) |
268 | |
269 | typedef struct _global_frozen_procs { |
270 | uint64_t gfp_num_frozen; |
271 | |
272 | struct { |
273 | pid_t fp_pid; |
274 | proc_name_t fp_name; |
275 | } gfp_procs[FREEZER_CONTROL_GET_PROCS_MAX_COUNT]; |
276 | } global_frozen_procs_t; |
277 | |
278 | /* Set the dasd trial identifiers */ |
279 | #define FREEZER_CONTROL_SET_DASD_TRIAL_IDENTIFIERS (3) |
280 | |
281 | typedef struct _memorystatus_freezer_trial_identifiers_v1 { |
282 | int version; /* Must be set to 1 */ |
283 | uuid_string_t treatment_id; |
284 | uuid_string_t experiment_id; |
285 | int deployment_id; |
286 | } memorystatus_freezer_trial_identifiers_v1; |
287 | |
288 | /* |
289 | * Destructively reset the freezer state in order to perform a policy change. |
290 | * Note that this could result in multiple suspended apps getting killed, |
291 | * so it should only be used when the device is idle. |
292 | */ |
293 | #define FREEZER_CONTROL_RESET_STATE (4) |
294 | |
295 | #endif /* PRIVATE */ |
296 | |
297 | #endif /* SYS_MEMORYSTATUS_FREEZE_H */ |
298 | |