2 * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
29 #include <mach/i386/vm_param.h>
30 #include <sys/kern_memorystatus.h>
31 #include <sys/sysctl.h>
32 #include <mach/mach.h>
33 #include <mach/task.h>
34 #include <mach/thread_act.h>
35 #include <mach/thread_policy.h>
39 #include <dispatch/private.h>
41 unsigned long phys_mem
= 0; /* amount of physical memory in bytes */
42 unsigned int phys_pages
= 0; /* number of physical memory pages */
43 int sleep_seconds
= 1;
44 int requested_hysteresis_seconds
= 0;
45 boolean_t quiet_mode_on
= FALSE
;
46 boolean_t simulate_mode_on
= FALSE
;
48 void *range_start_addr
= NULL
;
49 void *range_end_addr
= NULL
;
50 void *range_current_addr
= NULL
;
52 int start_referencing_pages
= 0;
53 int start_allocing_pages
= 0;
54 pthread_cond_t reference_pages_condvar
= PTHREAD_COND_INITIALIZER
;
55 pthread_mutex_t reference_pages_mutex
= PTHREAD_MUTEX_INITIALIZER
;
56 unsigned int desired_level
= 0, desired_percent
= 0;
57 unsigned int percent_for_level
= 0;
60 #define TOOL_MODE_FOR_PERCENT 1
61 #define TOOL_MODE_FOR_LEVEL 2
64 char random_data
[] = "ffd8ffe000104a46494600010101002400240000ffe100744578696600004d4d002a000000080004011a0005000000010000003e011b0005000000010000004601280003000000010002000087690004000000010000004e00000000000000240000000100000024000000010002a002000400000001000003c0a003000400000001000001ff00000000ffdb00430002020202020102020202020202030306040303030307050504060807080808070808090a0d0b09090c0a08080b0f0b0c0d0e0e0e0e090b10110f0e110d0e0e0effdb004301020202030303060404060e0908090e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0effc000110801ff03c003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f9e74fbd37baa2db99e6506391f28371f9519ba67fd9fcabd46cbc1315de8d6776752d7419e049084b152a37283c1dfc8e6bc02db4af18d9df79c9e1bd59a40ae9b65b1761f32953c63ae09c7a1c57656fe24f8896da7c16c9e0bb3748a358d5a4d04b31006324f73c75a00935f7fec9f165ee98b7372e2ddc05795763f2a0f20138ebeb590bac3e70d2b6e1fed1ac6d4ecbc65aa6b973a85c7867528a6998168edec1a38c1c01c2f61c550fec1f16ff00d0bdade4f5ff00447ff0a00eaffb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe66b4f45fed1f1078bb4cd0f4bdf3ea37f7296f6d1ee3f33b1c0cfb7a9f4ae0bfb07c5bff42f6b7ff808ff00e15a9a1c5e3bf0f78c74bd774cd0f5a8751d3ee52e2ddcd9be03a9c8cfb7623d2803d5bc6fe0df11780e0d3ae354bab1bdb1bd678e1bab1b8f36312c6079b112380cac4ae3b9535e7ffdaedff3d5ff00335b3e3af177c4af1f5be9b6da8f8567d36c2c59e486d74fd35e28ccb260c92b003966605b3db71af3cfec1f16ff00d0bdadff00e023ff0085007acf83743d57c6baddd59e9d7062fb3c68d248519c0324ab120c2f3cb38c9ec013dab95b8d427b5bfb8b59a4759a195a3917278652411f98ad9f86fe30f88bf0cb57d56f348f095f5ebdfc2914ab716b200a118918c0ff0068d709a9d878cb55f12ea3aa4fe1cd6127bdba92e2455b47c06772c40e3a64d007d13f09fe1d37c41d135ad7b52d52ef4fd074eba86cff00d1537cd7171310123504e0751927d6be8ed17f65bf0aebde19b4d5ac7c5fe2236b700eddf12060558ab03ee1948fc2be41f84bf123e20fc2d1acd87fc20d77e24f0eeabb1af74cbcb4902974fbb22b0190c3fa0f4afa1748fdad3c51a1691fd9fa57c10b8b4b212bc8b0ac931542c7240c8e067271ef401e9bff000c89a07fd0dbafff00dfb4a3fe191340ff00a1b75fff00bf695c2ffc366f8e7fe88c5cff00df72ff00851ff0d9be39ff00a23173ff007dcbfe1401dd7fc322681ff436ebff00f7ed28ff008644d03fe86dd7ff00efda570bff000d9be39ffa23173ff7dcbfe147fc366f8e7fe88c5cff00df72ff008500775ff0c89a07fd0dbaff00fdfb4a3fe191340ffa1b75ff00fbf695c2ff00c366f8e7fe88c5cffdf72ff851ff000d9be39ffa23173ff7dcbfe1401dd7fc322681ff00436ebfff007ed2be52f8d1f0eeff00e11fc42b2d325d49f51d3afedccf637046d6215b6b2b0f5071f98af733fb6678eb071f062e73fefcbfe15f2a7c5af1cfc4bf8bff001262d7758f0bea76515bc1f67b1b1b7b490a4099c9edcb13c93f4a00fe891bc2fe1c672cda1e96589c92";
66 #define PAGE_OP_ALLOC 0x1
67 #define PAGE_OP_FREE 0x2
69 #define USE_WIRED_PAGES_FOR_PERCENT_MODE FALSE
71 #define MAX_RANGE_SIZE 64 * 1024 * 1024 * 1024ULL
73 void print_vm_statistics(void);
74 void munch_for_level(unsigned int, unsigned int);
75 void munch_for_percentage(unsigned int, unsigned int, unsigned int);
80 fprintf(stderr
, "Usage: memory_pressure [options] [<pages>]\n"
81 " Allocate memory and wait forever.\n"
83 " -l <level> - allocate memory until a low memory notification is received (warn OR critical)\n"
84 " -p <percent-free> - allocate memory until percent free is this (or less)\n"
85 " -s <seconds> - how long to sleep between checking for a set percent level\n"
86 " -w <percent-free> - don't allocate, just wait until percent free is this then exit\n"
87 " -y <seconds> - Hysteresis Interval: how long to wait after requested percntage free is reached, before exiting program. Requires the usage of the -p option\n"
88 " -v <print VM stats> - print VM statistics every sampling interval\n"
89 " -Q <quiet mode> - reduces the tool's output\n"
90 " -S - simulate the system's memory pressure level without applying any real pressure\n"
97 read_sysctl_int(const char* name
)
103 var_size
= sizeof(var
);
104 error
= sysctlbyname(name
, &var
, &var_size
, NULL
, 0);
113 get_percent_free(unsigned int* level
)
117 error
= memorystatus_get_level((user_addr_t
) level
);
120 perror("memorystatus_get_level failed:");
127 print_vm_statistics(void)
129 unsigned int count
= HOST_VM_INFO64_COUNT
;
130 kern_return_t ret
= 0;
131 vm_statistics64_data_t vm_stat
;;
133 if (quiet_mode_on
== TRUE
) {
137 if ((ret
= host_statistics64(mach_host_self(), HOST_VM_INFO64
, (host_info64_t
)&vm_stat
, &count
) != KERN_SUCCESS
)) {
138 fprintf(stderr
, "Failed to get statistics. Error %d\n", ret
);
140 printf("\nStats: \n");
141 printf("Pages free: %llu \n", (uint64_t) (vm_stat
.free_count
- vm_stat
.speculative_count
));
142 printf("Pages purgeable: %llu \n", (uint64_t) (vm_stat
.purgeable_count
));
143 printf("Pages purged: %llu \n",(uint64_t) (vm_stat
.purges
));
145 printf("\nSwap I/O:\n");
146 printf("Swapins: %llu \n", (uint64_t) (vm_stat
.swapins
));
147 printf("Swapouts: %llu \n", (uint64_t) (vm_stat
.swapouts
));
149 printf("\nPage Q counts:\n");
150 printf("Pages active: %llu \n", (uint64_t) (vm_stat
.active_count
));
151 printf("Pages inactive: %llu \n", (uint64_t) (vm_stat
.inactive_count
));
152 printf("Pages speculative: %llu \n", (uint64_t) (vm_stat
.speculative_count
));
153 printf("Pages throttled: %llu \n", (uint64_t) (vm_stat
.throttled_count
));
154 printf("Pages wired down: %llu \n", (uint64_t) (vm_stat
.wire_count
));
156 printf("\nCompressor Stats:\n");
157 printf("Pages used by compressor: %llu \n", (uint64_t) (vm_stat
.compressor_page_count
));
158 printf("Pages decompressed: %llu \n", (uint64_t) (vm_stat
.decompressions
));
159 printf("Pages compressed: %llu \n", (uint64_t) (vm_stat
.compressions
));
161 printf("\nFile I/O:\n");
162 printf("Pageins: %llu \n", (uint64_t) (vm_stat
.pageins
));
163 printf("Pageouts: %llu \n", (uint64_t) (vm_stat
.pageouts
));
166 printf("\"Translation faults\": %llu \n", (uint64_t) (vm_stat
.faults
));
167 printf("Pages copy-on-write: %llu \n", (uint64_t) (vm_stat
.cow_faults
));
168 printf("Pages zero filled: %llu \n", (uint64_t) (vm_stat
.zero_fill_count
));
169 printf("Pages reactivated: %llu \n", (uint64_t) (vm_stat
.reactivations
));
176 reached_or_bypassed_desired_result(void)
178 if (tool_mode
== TOOL_MODE_FOR_LEVEL
) {
180 unsigned int current_level
= 0;
182 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
184 if (desired_level
> 0 && current_level
>= desired_level
) {
191 if (tool_mode
== TOOL_MODE_FOR_PERCENT
) {
193 unsigned int current_percent
= 0;
195 get_percent_free(¤t_percent
);
197 if (desired_percent
> 0 && current_percent
<= desired_percent
) {
208 reference_pages(int level
)
214 error
= pthread_mutex_lock(&reference_pages_mutex
);
215 addr
= range_start_addr
;
217 while(start_referencing_pages
== 0) {
218 error
= pthread_cond_wait(&reference_pages_condvar
, &reference_pages_mutex
);
221 start_allocing_pages
= 0;
222 pthread_mutex_unlock(&reference_pages_mutex
);
225 for(; addr
< range_current_addr
;) {
229 if (reached_or_bypassed_desired_result()) {
230 //printf("stopped referencing after %d pages\n", num_pages);
241 // printf("Referenced %d\n", num_pages);
243 error
= pthread_mutex_lock(&reference_pages_mutex
);
244 start_referencing_pages
= 0;
245 start_allocing_pages
= 1;
251 process_pages(int num_pages
, int page_op
)
255 int error
= 0, i
= 0;
256 size_t size
= num_pages
* PAGE_SIZE
;
258 if (page_op
== PAGE_OP_ALLOC
) {
260 if (tool_mode
== TOOL_MODE_FOR_PERCENT
&& USE_WIRED_PAGES_FOR_PERCENT_MODE
) {
261 error
= mlock(range_current_addr
, size
);
263 perror("Failed to lock memory!");
267 memset(range_current_addr
, 0xFF, size
);
268 range_current_addr
+= size
;
272 pthread_mutex_lock(&reference_pages_mutex
);
273 while (start_allocing_pages
== 0) {
274 pthread_mutex_unlock(&reference_pages_mutex
);
276 pthread_mutex_lock(&reference_pages_mutex
);
278 pthread_mutex_unlock(&reference_pages_mutex
);
280 for (i
=0; i
< num_pages
; i
++) {
282 if (reached_or_bypassed_desired_result()) {
283 //printf("stopped faulting after %d pages\n", i);
287 memcpy(range_current_addr
, random_data
, PAGE_SIZE
);
288 range_current_addr
+= PAGE_SIZE
;
291 pthread_mutex_lock(&reference_pages_mutex
);
292 start_referencing_pages
= 1;
293 pthread_cond_signal(&reference_pages_condvar
);
294 pthread_mutex_unlock(&reference_pages_mutex
);
297 if (tool_mode
== TOOL_MODE_FOR_PERCENT
&& USE_WIRED_PAGES_FOR_PERCENT_MODE
) {
298 error
= munlock(range_current_addr
, size
);
300 perror("Failed to unlock memory!");
304 error
= madvise(range_current_addr
, size
, MADV_FREE
);
306 perror("Failed to madv_free memory!");
310 range_current_addr
-= size
;
313 pthread_mutex_lock(&reference_pages_mutex
);
314 while (start_referencing_pages
== 1) {
315 pthread_mutex_unlock(&reference_pages_mutex
);
317 pthread_mutex_lock(&reference_pages_mutex
);
320 error
= madvise(range_current_addr
, size
, MADV_FREE
);
322 perror("Failed to madv_free memory!");
325 range_current_addr
-= size
;
326 start_referencing_pages
= 1;
327 pthread_cond_signal(&reference_pages_condvar
);
328 pthread_mutex_unlock(&reference_pages_mutex
);
335 munch_for_level(unsigned int sleep_seconds
, unsigned int print_vm_stats
)
338 unsigned int current_level
= 0;
339 unsigned int desired_percent
= 0;
340 unsigned int current_percent
= 0;
341 unsigned int page_op
= PAGE_OP_ALLOC
;
342 unsigned int previous_page_op
= PAGE_OP_ALLOC
;
343 unsigned int pages_to_process
= 0;
344 unsigned int stabilized_percentage
= 0;
345 boolean_t print_vm_stats_on_page_processing
= FALSE
;
346 boolean_t ok_to_print_stablity_message
= TRUE
;
348 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
350 if (current_level
>= desired_level
) {
354 get_percent_free(¤t_percent
);
356 if (print_vm_stats
) {
357 print_vm_stats_on_page_processing
= TRUE
;
360 page_op
= PAGE_OP_ALLOC
;
361 previous_page_op
= 0;
365 if (current_percent
> percent_for_level
) {
366 desired_percent
= current_percent
- percent_for_level
;
371 pages_to_process
= (desired_percent
* phys_pages
) / 100;
373 page_op
= PAGE_OP_ALLOC
;
375 if (previous_page_op
!= page_op
) {
376 //printf("%s %d pages.\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process);
377 printf("\nCMD: %s pages to go from level: %d to level: %d", (page_op
== PAGE_OP_ALLOC
) ? "Allocating" : "Freeing", current_level
, desired_level
);
378 previous_page_op
= page_op
;
385 if (print_vm_stats_on_page_processing
== TRUE
) {
386 print_vm_statistics();
388 process_pages(pages_to_process
, page_op
);
389 ok_to_print_stablity_message
= TRUE
;
391 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
393 if (current_level
>= desired_level
) {
396 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
397 if (current_level
< desired_level
) {
401 if (current_level
> desired_level
) {
402 page_op
= PAGE_OP_FREE
;
404 get_percent_free(¤t_percent
);
406 if (stabilized_percentage
> current_percent
) {
407 pages_to_process
= ((stabilized_percentage
- current_percent
) * phys_pages
) / 100;
409 if (previous_page_op
!= page_op
) {
410 printf("\nCMD: %s pages to go from %d to %d level", (page_op
== PAGE_OP_ALLOC
) ? "Allocating" : "Freeing", current_level
, desired_level
);
411 previous_page_op
= page_op
;
418 if (print_vm_stats_on_page_processing
== TRUE
) {
419 print_vm_statistics();
421 process_pages(pages_to_process
, page_op
);
422 ok_to_print_stablity_message
= TRUE
;
426 while (current_level
== desired_level
) {
427 get_percent_free(¤t_percent
);
428 if (ok_to_print_stablity_message
== TRUE
) {
429 print_vm_statistics();
430 printf("\nStabilizing at Percent: %d Level: %d", current_percent
, current_level
);
432 ok_to_print_stablity_message
= FALSE
;
433 previous_page_op
= 0;
439 stabilized_percentage
= current_percent
;
440 sleep(sleep_seconds
);
441 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
446 get_percent_free(¤t_percent
);
447 //printf("Percent: %d Level: %d\n", current_percent, current_level);
450 if (print_vm_stats
) {
451 print_vm_stats_on_page_processing
= TRUE
;
458 munch_for_percentage(unsigned int sleep_seconds
, unsigned int wait_percent_free
, unsigned int print_vm_stats
)
461 int total_pages_allocated
= 0;
462 int current_stable_timer
= 0; /* in seconds */
463 unsigned int current_percent
= 0;
464 boolean_t page_op
= PAGE_OP_FREE
;
465 unsigned int pages_to_process
= 0;
466 boolean_t print_vm_stats_on_page_processing
= FALSE
;
467 boolean_t previous_page_op
= 0;
468 boolean_t ok_to_print_stablity_message
= TRUE
;
470 /* Allocate until memory level is hit. */
472 get_percent_free(¤t_percent
);
475 * "wait" mode doesn't alloc, it just waits and exits. This is used
476 * while waiting for *other* processes to allocate memory.
478 if (wait_percent_free
) {
479 while (current_percent
> wait_percent_free
) {
480 sleep(sleep_seconds
);
481 get_percent_free (¤t_percent
);
486 page_op
= PAGE_OP_ALLOC
;
487 previous_page_op
= 0;
491 if (current_percent
> desired_percent
) {
492 pages_to_process
= ((current_percent
- desired_percent
) * phys_pages
) / 100;
493 page_op
= PAGE_OP_ALLOC
;
495 pages_to_process
= ((desired_percent
- current_percent
) * phys_pages
) / 100;
496 page_op
= PAGE_OP_FREE
;
499 if (pages_to_process
> 0) {
501 if (page_op
!= previous_page_op
) {
502 //printf("\n%s %d pages to go from %d%% to %d%% pages free\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process, current_percent, desired_percent);
503 printf("\nCMD: %s pages to go from %d%% to %d%% percent free", (page_op
== PAGE_OP_ALLOC
) ? "Allocating" : "Freeing", current_percent
, desired_percent
);
505 previous_page_op
= page_op
;
511 if (page_op
== PAGE_OP_ALLOC
) {
512 total_pages_allocated
+= pages_to_process
;
513 process_pages(pages_to_process
, page_op
);
514 ok_to_print_stablity_message
= TRUE
;
517 if (total_pages_allocated
>= pages_to_process
) {
518 total_pages_allocated
-= pages_to_process
;
519 process_pages(pages_to_process
, page_op
);
520 ok_to_print_stablity_message
= TRUE
;
522 get_percent_free(¤t_percent
);
523 if (ok_to_print_stablity_message
== TRUE
) {
524 printf("\nDesired Percent: %d, Current Percent: %d. No pages to free so waiting", desired_percent
, current_percent
);
526 ok_to_print_stablity_message
= FALSE
;
531 //printf("kernel memorystatus: %d%% free, allocated %d pages total. Requested: %d\n", current_percent, total_pages_allocated, desired_percent);
532 if (print_vm_stats
) {
533 print_vm_stats_on_page_processing
= TRUE
;
536 if (ok_to_print_stablity_message
== TRUE
) {
537 print_vm_statistics();
538 printf("\nStable at percent free: %d", current_percent
);
540 ok_to_print_stablity_message
= FALSE
;
546 /* Stability has been reached; Increment current_stable_timer by sleep_seconds */
548 if (current_stable_timer
<= requested_hysteresis_seconds
){
549 current_stable_timer
+= sleep_seconds
;
551 /* printf("\n Percentage Free stable for %d seconds", current_stable_timer); */
553 printf ("\n Maintained memory pressure to %d percent free for more than %d seconds. Stopping pressure now.", current_percent
, requested_hysteresis_seconds
);
557 print_vm_stats_on_page_processing
= FALSE
;
560 if (print_vm_stats_on_page_processing
) {
562 print_vm_statistics();
564 if (print_vm_stats_on_page_processing
== TRUE
) {
565 print_vm_stats_on_page_processing
= FALSE
;
569 sleep(sleep_seconds
);
571 get_percent_free(¤t_percent
);
576 main(int argc
, char * const argv
[])
579 unsigned int wait_percent_free
= 0;
580 unsigned int current_percent
= 0;
581 unsigned int print_vm_stats
= 0;
584 while ((opt
= getopt(argc
, argv
, "hl:p:s:w:y:vQS")) != -1) {
590 strlcpy(level
, optarg
, 9);
592 if (strncasecmp(level
, "normal", 6) == 0) {
593 desired_level
= DISPATCH_MEMORYPRESSURE_NORMAL
;
594 percent_for_level
= 90;
595 } else if (strncasecmp(level
, "warn", 4) == 0) {
596 desired_level
= DISPATCH_MEMORYPRESSURE_WARN
;
597 percent_for_level
= 60;
599 } else if (strncasecmp(level
, "critical", 8) == 0) {
600 desired_level
= DISPATCH_MEMORYPRESSURE_CRITICAL
;
601 percent_for_level
= 30;
604 printf("Incorrect level. Allowed \"normal\" or \"warn\" or \"critical\". Specified: %s\n", level
);
609 desired_percent
= atoi(optarg
);
612 sleep_seconds
= atoi(optarg
);
615 wait_percent_free
= atoi(optarg
);
618 requested_hysteresis_seconds
= atoi(optarg
);
624 quiet_mode_on
= TRUE
;
627 simulate_mode_on
= TRUE
;
634 if (simulate_mode_on
== TRUE
&& desired_level
== 0) {
635 printf("Expected level with -l along with \"simulated\" mode.\n");
639 if (requested_hysteresis_seconds
> 0) {
640 if (desired_percent
== 0) {
641 printf("Hysteresis time may only be specified in conjunction with a non-zero value for the -p option. \n");
646 phys_mem
= read_sysctl_int("hw.physmem");
647 phys_pages
= (unsigned int) (phys_mem
/ PAGE_SIZE
);
649 printf("The system has %lu (%d pages with a page size of %d).\n", phys_mem
, phys_pages
, PAGE_SIZE
);
651 print_vm_statistics();
653 get_percent_free(¤t_percent
);
654 printf("System-wide memory free percentage: %d%%\n", current_percent
);
656 if (desired_percent
== 0 && wait_percent_free
== 0 && desired_level
== 0) {
660 if (simulate_mode_on
== TRUE
) {
663 We use the sysctl "kern.memorypressure_manual_trigger" for this mode. Here's a blurb:
665 Supported behaviors when using the manual trigger tests.
667 #define TEST_LOW_MEMORY_TRIGGER_ONE 1 most suitable app is notified
668 #define TEST_LOW_MEMORY_TRIGGER_ALL 2 all apps are notified
669 #define TEST_PURGEABLE_TRIGGER_ONE 3
670 #define TEST_PURGEABLE_TRIGGER_ALL 4
671 #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ONE 5
672 #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
674 So, for example, to simulate one app getting a poke when the "pressure" reaches critical levels: "sudo sysctl -w kern.memorypressure_manual_trigger = level"
675 where level is calculated as: ((TEST_LOW_MEMORY_TRIGGER_ONE << 16) | NOTE_MEMORYSTATUS_PRESSURE_CRITICAL), which will be "65540".
677 For this tool, currently, we only support the "TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL" options.
680 #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
682 unsigned int var
= 0;
686 var_size
= sizeof(var
);
688 var
= ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL
<< 16) | desired_level
);
690 error
= sysctlbyname("kern.memorypressure_manual_trigger", NULL
, 0, &var
, var_size
);
693 perror("sysctl: kern.memorypressure_manual_trigger failed ");
697 printf("Waiting %d seconds before resetting system state\n", sleep_seconds
);
699 sleep(sleep_seconds
);
701 var_size
= sizeof(var
);
703 var
= ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL
<< 16) | DISPATCH_MEMORYPRESSURE_NORMAL
);
705 error
= sysctlbyname("kern.memorypressure_manual_trigger", NULL
, 0, &var
, var_size
);
708 perror("sysctl: kern.memorypressure_manual_trigger failed ");
712 printf("Reset system state\n");
715 range_start_addr
= mmap(NULL
, MAX_RANGE_SIZE
, PROT_READ
| PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
, 0, 0);
717 if (range_start_addr
== MAP_FAILED
) {
718 perror("mmap failed");
722 pthread_t thread
= NULL
;
724 error
= pthread_create(&thread
, NULL
, (void*) reference_pages
, NULL
);
726 range_current_addr
= range_start_addr
;
727 range_end_addr
= range_start_addr
+ MAX_RANGE_SIZE
;
728 start_allocing_pages
= 1;
731 tool_mode
= TOOL_MODE_FOR_LEVEL
;
732 munch_for_level(sleep_seconds
, print_vm_stats
);
734 tool_mode
= TOOL_MODE_FOR_PERCENT
;
735 munch_for_percentage(sleep_seconds
, wait_percent_free
, print_vm_stats
);