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