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 long 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 read_sysctl_long_long(const char* name
)
119 var_size
= sizeof(var
);
120 error
= sysctlbyname(name
, &var
, &var_size
, NULL
, 0);
129 get_percent_free(unsigned int* level
)
133 error
= memorystatus_get_level((user_addr_t
) level
);
136 perror("memorystatus_get_level failed:");
143 print_vm_statistics(void)
145 unsigned int count
= HOST_VM_INFO64_COUNT
;
146 kern_return_t ret
= 0;
147 vm_statistics64_data_t vm_stat
;;
149 if (quiet_mode_on
== TRUE
) {
153 if ((ret
= host_statistics64(mach_host_self(), HOST_VM_INFO64
, (host_info64_t
)&vm_stat
, &count
) != KERN_SUCCESS
)) {
154 fprintf(stderr
, "Failed to get statistics. Error %d\n", ret
);
156 printf("\nStats: \n");
157 printf("Pages free: %llu \n", (uint64_t) (vm_stat
.free_count
- vm_stat
.speculative_count
));
158 printf("Pages purgeable: %llu \n", (uint64_t) (vm_stat
.purgeable_count
));
159 printf("Pages purged: %llu \n",(uint64_t) (vm_stat
.purges
));
161 printf("\nSwap I/O:\n");
162 printf("Swapins: %llu \n", (uint64_t) (vm_stat
.swapins
));
163 printf("Swapouts: %llu \n", (uint64_t) (vm_stat
.swapouts
));
165 printf("\nPage Q counts:\n");
166 printf("Pages active: %llu \n", (uint64_t) (vm_stat
.active_count
));
167 printf("Pages inactive: %llu \n", (uint64_t) (vm_stat
.inactive_count
));
168 printf("Pages speculative: %llu \n", (uint64_t) (vm_stat
.speculative_count
));
169 printf("Pages throttled: %llu \n", (uint64_t) (vm_stat
.throttled_count
));
170 printf("Pages wired down: %llu \n", (uint64_t) (vm_stat
.wire_count
));
172 printf("\nCompressor Stats:\n");
173 printf("Pages used by compressor: %llu \n", (uint64_t) (vm_stat
.compressor_page_count
));
174 printf("Pages decompressed: %llu \n", (uint64_t) (vm_stat
.decompressions
));
175 printf("Pages compressed: %llu \n", (uint64_t) (vm_stat
.compressions
));
177 printf("\nFile I/O:\n");
178 printf("Pageins: %llu \n", (uint64_t) (vm_stat
.pageins
));
179 printf("Pageouts: %llu \n", (uint64_t) (vm_stat
.pageouts
));
182 printf("\"Translation faults\": %llu \n", (uint64_t) (vm_stat
.faults
));
183 printf("Pages copy-on-write: %llu \n", (uint64_t) (vm_stat
.cow_faults
));
184 printf("Pages zero filled: %llu \n", (uint64_t) (vm_stat
.zero_fill_count
));
185 printf("Pages reactivated: %llu \n", (uint64_t) (vm_stat
.reactivations
));
192 this will work for up to 64 TB of RAM -- beyond that we exceed Intel's max for VRAM (48 bits of addressable space).
193 By the time we get there Intel probably will have increased this
195 static unsigned long long
198 unsigned long long the_max_range_size
= MAX_RANGE_SIZE
;
200 if (phys_mem
* 4 > the_max_range_size
) {
201 the_max_range_size
= phys_mem
* 4;
204 return the_max_range_size
;
208 reached_or_bypassed_desired_result(void)
210 if (tool_mode
== TOOL_MODE_FOR_LEVEL
) {
212 unsigned int current_level
= 0;
214 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
216 if (desired_level
> 0 && current_level
>= desired_level
) {
223 if (tool_mode
== TOOL_MODE_FOR_PERCENT
) {
225 unsigned int current_percent
= 0;
227 get_percent_free(¤t_percent
);
229 if (desired_percent
> 0 && current_percent
<= desired_percent
) {
240 reference_pages(int level
)
246 error
= pthread_mutex_lock(&reference_pages_mutex
);
247 addr
= range_start_addr
;
249 while(start_referencing_pages
== 0) {
250 error
= pthread_cond_wait(&reference_pages_condvar
, &reference_pages_mutex
);
253 start_allocing_pages
= 0;
254 pthread_mutex_unlock(&reference_pages_mutex
);
257 for(; addr
< range_current_addr
;) {
261 if (reached_or_bypassed_desired_result()) {
262 //printf("stopped referencing after %d pages\n", num_pages);
273 // printf("Referenced %d\n", num_pages);
275 error
= pthread_mutex_lock(&reference_pages_mutex
);
276 start_referencing_pages
= 0;
277 start_allocing_pages
= 1;
283 process_pages(int num_pages
, int page_op
)
287 int error
= 0, i
= 0;
288 size_t size
= num_pages
* PAGE_SIZE
;
290 if (page_op
== PAGE_OP_ALLOC
) {
292 if (tool_mode
== TOOL_MODE_FOR_PERCENT
&& USE_WIRED_PAGES_FOR_PERCENT_MODE
) {
293 error
= mlock(range_current_addr
, size
);
295 perror("Failed to lock memory!");
299 memset(range_current_addr
, 0xFF, size
);
300 range_current_addr
+= size
;
304 pthread_mutex_lock(&reference_pages_mutex
);
305 while (start_allocing_pages
== 0) {
306 pthread_mutex_unlock(&reference_pages_mutex
);
308 pthread_mutex_lock(&reference_pages_mutex
);
310 pthread_mutex_unlock(&reference_pages_mutex
);
312 for (i
=0; i
< num_pages
; i
++) {
314 if (reached_or_bypassed_desired_result()) {
315 //printf("stopped faulting after %d pages\n", i);
318 if ((uintptr_t)range_current_addr
< get_max_range_size()) {
319 memcpy(range_current_addr
, random_data
, PAGE_SIZE
);
320 range_current_addr
+= PAGE_SIZE
;
322 printf("\nRun out of allocable memory\n");
327 pthread_mutex_lock(&reference_pages_mutex
);
328 start_referencing_pages
= 1;
329 pthread_cond_signal(&reference_pages_condvar
);
330 pthread_mutex_unlock(&reference_pages_mutex
);
333 if (tool_mode
== TOOL_MODE_FOR_PERCENT
&& USE_WIRED_PAGES_FOR_PERCENT_MODE
) {
334 error
= munlock(range_current_addr
, size
);
336 perror("Failed to unlock memory!");
340 error
= madvise(range_current_addr
, size
, MADV_FREE
);
342 perror("Failed to madv_free memory!");
346 range_current_addr
-= size
;
349 pthread_mutex_lock(&reference_pages_mutex
);
350 while (start_referencing_pages
== 1) {
351 pthread_mutex_unlock(&reference_pages_mutex
);
353 pthread_mutex_lock(&reference_pages_mutex
);
356 error
= madvise(range_current_addr
, size
, MADV_FREE
);
358 perror("Failed to madv_free memory!");
361 range_current_addr
-= size
;
362 start_referencing_pages
= 1;
363 pthread_cond_signal(&reference_pages_condvar
);
364 pthread_mutex_unlock(&reference_pages_mutex
);
371 munch_for_level(unsigned int sleep_seconds
, unsigned int print_vm_stats
)
374 unsigned int current_level
= 0;
375 unsigned int desired_percent
= 0;
376 unsigned int current_percent
= 0;
377 unsigned int page_op
= PAGE_OP_ALLOC
;
378 unsigned int previous_page_op
= PAGE_OP_ALLOC
;
379 unsigned int pages_to_process
= 0;
380 unsigned int stabilized_percentage
= 0;
381 boolean_t print_vm_stats_on_page_processing
= FALSE
;
382 boolean_t ok_to_print_stablity_message
= TRUE
;
384 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
386 if (current_level
>= desired_level
) {
390 get_percent_free(¤t_percent
);
392 if (print_vm_stats
) {
393 print_vm_stats_on_page_processing
= TRUE
;
396 page_op
= PAGE_OP_ALLOC
;
397 previous_page_op
= 0;
401 if (current_percent
> percent_for_level
) {
402 desired_percent
= current_percent
- percent_for_level
;
407 pages_to_process
= (desired_percent
* phys_pages
) / 100;
409 page_op
= PAGE_OP_ALLOC
;
411 if (previous_page_op
!= page_op
) {
412 //printf("%s %d pages.\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process);
413 printf("\nCMD: %s pages to go from level: %d to level: %d", (page_op
== PAGE_OP_ALLOC
) ? "Allocating" : "Freeing", current_level
, desired_level
);
414 previous_page_op
= page_op
;
421 if (print_vm_stats_on_page_processing
== TRUE
) {
422 print_vm_statistics();
424 process_pages(pages_to_process
, page_op
);
425 ok_to_print_stablity_message
= TRUE
;
427 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
429 if (current_level
>= desired_level
) {
432 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
433 if (current_level
< desired_level
) {
437 if (current_level
> desired_level
) {
438 page_op
= PAGE_OP_FREE
;
440 get_percent_free(¤t_percent
);
442 if (stabilized_percentage
> current_percent
) {
443 pages_to_process
= ((stabilized_percentage
- current_percent
) * phys_pages
) / 100;
445 if (previous_page_op
!= page_op
) {
446 printf("\nCMD: %s pages to go from %d to %d level", (page_op
== PAGE_OP_ALLOC
) ? "Allocating" : "Freeing", current_level
, desired_level
);
447 previous_page_op
= page_op
;
454 if (print_vm_stats_on_page_processing
== TRUE
) {
455 print_vm_statistics();
457 process_pages(pages_to_process
, page_op
);
458 ok_to_print_stablity_message
= TRUE
;
462 while (current_level
== desired_level
) {
463 get_percent_free(¤t_percent
);
464 if (ok_to_print_stablity_message
== TRUE
) {
465 print_vm_statistics();
466 printf("\nStabilizing at Percent: %d Level: %d", current_percent
, current_level
);
468 ok_to_print_stablity_message
= FALSE
;
469 previous_page_op
= 0;
475 stabilized_percentage
= current_percent
;
476 sleep(sleep_seconds
);
477 current_level
= read_sysctl_int("kern.memorystatus_vm_pressure_level");
482 get_percent_free(¤t_percent
);
483 //printf("Percent: %d Level: %d\n", current_percent, current_level);
486 if (print_vm_stats
) {
487 print_vm_stats_on_page_processing
= TRUE
;
494 munch_for_percentage(unsigned int sleep_seconds
, unsigned int wait_percent_free
, unsigned int print_vm_stats
)
497 int total_pages_allocated
= 0;
498 int current_stable_timer
= 0; /* in seconds */
499 unsigned int current_percent
= 0;
500 boolean_t page_op
= PAGE_OP_FREE
;
501 unsigned int pages_to_process
= 0;
502 boolean_t print_vm_stats_on_page_processing
= FALSE
;
503 boolean_t previous_page_op
= 0;
504 boolean_t ok_to_print_stablity_message
= TRUE
;
506 /* Allocate until memory level is hit. */
508 get_percent_free(¤t_percent
);
511 * "wait" mode doesn't alloc, it just waits and exits. This is used
512 * while waiting for *other* processes to allocate memory.
514 if (wait_percent_free
) {
515 while (current_percent
> wait_percent_free
) {
516 sleep(sleep_seconds
);
517 get_percent_free (¤t_percent
);
522 page_op
= PAGE_OP_ALLOC
;
523 previous_page_op
= 0;
527 if (current_percent
> desired_percent
) {
528 pages_to_process
= ((current_percent
- desired_percent
) * phys_pages
) / 100;
529 page_op
= PAGE_OP_ALLOC
;
531 pages_to_process
= ((desired_percent
- current_percent
) * phys_pages
) / 100;
532 page_op
= PAGE_OP_FREE
;
535 if (pages_to_process
> 0) {
537 if (page_op
!= previous_page_op
) {
538 //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);
539 printf("\nCMD: %s pages to go from %d%% to %d%% percent free", (page_op
== PAGE_OP_ALLOC
) ? "Allocating" : "Freeing", current_percent
, desired_percent
);
541 previous_page_op
= page_op
;
547 if (page_op
== PAGE_OP_ALLOC
) {
548 total_pages_allocated
+= pages_to_process
;
549 process_pages(pages_to_process
, page_op
);
550 ok_to_print_stablity_message
= TRUE
;
553 if (total_pages_allocated
>= pages_to_process
) {
554 total_pages_allocated
-= pages_to_process
;
555 process_pages(pages_to_process
, page_op
);
556 ok_to_print_stablity_message
= TRUE
;
558 get_percent_free(¤t_percent
);
559 if (ok_to_print_stablity_message
== TRUE
) {
560 printf("\nDesired Percent: %d, Current Percent: %d. No pages to free so waiting", desired_percent
, current_percent
);
562 ok_to_print_stablity_message
= FALSE
;
567 //printf("kernel memorystatus: %d%% free, allocated %d pages total. Requested: %d\n", current_percent, total_pages_allocated, desired_percent);
568 if (print_vm_stats
) {
569 print_vm_stats_on_page_processing
= TRUE
;
572 if (ok_to_print_stablity_message
== TRUE
) {
573 print_vm_statistics();
574 printf("\nStable at percent free: %d", current_percent
);
576 ok_to_print_stablity_message
= FALSE
;
582 /* Stability has been reached; Increment current_stable_timer by sleep_seconds */
584 if (current_stable_timer
<= requested_hysteresis_seconds
){
585 current_stable_timer
+= sleep_seconds
;
587 /* printf("\n Percentage Free stable for %d seconds", current_stable_timer); */
589 printf ("\n Maintained memory pressure to %d percent free for more than %d seconds. Stopping pressure now.", current_percent
, requested_hysteresis_seconds
);
593 print_vm_stats_on_page_processing
= FALSE
;
596 if (print_vm_stats_on_page_processing
) {
598 print_vm_statistics();
600 if (print_vm_stats_on_page_processing
== TRUE
) {
601 print_vm_stats_on_page_processing
= FALSE
;
605 sleep(sleep_seconds
);
607 get_percent_free(¤t_percent
);
612 main(int argc
, char * const argv
[])
615 unsigned int wait_percent_free
= 0;
616 unsigned int current_percent
= 0;
617 unsigned int print_vm_stats
= 0;
620 while ((opt
= getopt(argc
, argv
, "hl:p:s:w:y:vQS")) != -1) {
626 strlcpy(level
, optarg
, 9);
628 if (strncasecmp(level
, "normal", 6) == 0) {
629 desired_level
= DISPATCH_MEMORYPRESSURE_NORMAL
;
630 percent_for_level
= 90;
631 } else if (strncasecmp(level
, "warn", 4) == 0) {
632 desired_level
= DISPATCH_MEMORYPRESSURE_WARN
;
633 percent_for_level
= 60;
635 } else if (strncasecmp(level
, "critical", 8) == 0) {
636 desired_level
= DISPATCH_MEMORYPRESSURE_CRITICAL
;
637 percent_for_level
= 30;
640 printf("Incorrect level. Allowed \"normal\" or \"warn\" or \"critical\". Specified: %s\n", level
);
645 desired_percent
= atoi(optarg
);
648 sleep_seconds
= atoi(optarg
);
651 wait_percent_free
= atoi(optarg
);
654 requested_hysteresis_seconds
= atoi(optarg
);
660 quiet_mode_on
= TRUE
;
663 simulate_mode_on
= TRUE
;
670 if (simulate_mode_on
== TRUE
&& desired_level
== 0) {
671 printf("Expected level with -l along with \"simulated\" mode.\n");
675 if (requested_hysteresis_seconds
> 0) {
676 if (desired_percent
== 0) {
677 printf("Hysteresis time may only be specified in conjunction with a non-zero value for the -p option. \n");
682 phys_mem
= read_sysctl_long_long("hw.memsize");
683 phys_pages
= (unsigned int) (phys_mem
/ PAGE_SIZE
);
685 printf("The system has %lld (%d pages with a page size of %lu).\n", phys_mem
, phys_pages
, PAGE_SIZE
);
687 print_vm_statistics();
689 get_percent_free(¤t_percent
);
690 printf("System-wide memory free percentage: %d%%\n", current_percent
);
692 if (desired_percent
== 0 && wait_percent_free
== 0 && desired_level
== 0) {
696 if (simulate_mode_on
== TRUE
) {
699 We use the sysctl "kern.memorypressure_manual_trigger" for this mode. Here's a blurb:
701 Supported behaviors when using the manual trigger tests.
703 #define TEST_LOW_MEMORY_TRIGGER_ONE 1 most suitable app is notified
704 #define TEST_LOW_MEMORY_TRIGGER_ALL 2 all apps are notified
705 #define TEST_PURGEABLE_TRIGGER_ONE 3
706 #define TEST_PURGEABLE_TRIGGER_ALL 4
707 #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ONE 5
708 #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
710 So, for example, to simulate one app getting a poke when the "pressure" reaches critical levels: "sudo sysctl -w kern.memorypressure_manual_trigger = level"
711 where level is calculated as: ((TEST_LOW_MEMORY_TRIGGER_ONE << 16) | NOTE_MEMORYSTATUS_PRESSURE_CRITICAL), which will be "65540".
713 For this tool, currently, we only support the "TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL" options.
716 #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
718 unsigned int var
= 0;
722 var_size
= sizeof(var
);
724 var
= ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL
<< 16) | desired_level
);
726 error
= sysctlbyname("kern.memorypressure_manual_trigger", NULL
, 0, &var
, var_size
);
729 perror("sysctl: kern.memorypressure_manual_trigger failed ");
733 printf("Waiting %d seconds before resetting system state\n", sleep_seconds
);
735 sleep(sleep_seconds
);
737 var_size
= sizeof(var
);
739 var
= ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL
<< 16) | DISPATCH_MEMORYPRESSURE_NORMAL
);
741 error
= sysctlbyname("kern.memorypressure_manual_trigger", NULL
, 0, &var
, var_size
);
744 perror("sysctl: kern.memorypressure_manual_trigger failed ");
748 printf("Reset system state\n");
751 range_start_addr
= mmap(NULL
, get_max_range_size(), PROT_READ
| PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
, 0, 0);
753 if (range_start_addr
== MAP_FAILED
) {
754 perror("mmap failed");
758 pthread_t thread
= NULL
;
760 error
= pthread_create(&thread
, NULL
, (void*) reference_pages
, NULL
);
762 range_current_addr
= range_start_addr
;
763 range_end_addr
= range_start_addr
+ get_max_range_size();
764 start_allocing_pages
= 1;
767 tool_mode
= TOOL_MODE_FOR_LEVEL
;
768 munch_for_level(sleep_seconds
, print_vm_stats
);
770 tool_mode
= TOOL_MODE_FOR_PERCENT
;
771 munch_for_percentage(sleep_seconds
, wait_percent_free
, print_vm_stats
);