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