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