]>
Commit | Line | Data |
---|---|---|
fc6d9e4b | 1 | /* |
cf37c299 | 2 | * Copyright (c) 2013-2016 Apple Inc. All rights reserved. |
fc6d9e4b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
cf37c299 | 5 | * |
fc6d9e4b A |
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 | |
11 | * file. | |
cf37c299 | 12 | * |
fc6d9e4b A |
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. | |
cf37c299 | 20 | * |
fc6d9e4b A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | #include <stdio.h> | |
25 | #include <stdlib.h> | |
26 | #include <errno.h> | |
27 | #include <getopt.h> | |
28 | #include <string.h> | |
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> | |
36 | #include <sys/mman.h> | |
37 | #include <pthread.h> | |
38 | #include <assert.h> | |
39 | #include <dispatch/private.h> | |
40 | ||
c0bbac3a | 41 | long long phys_mem = 0; /* amount of physical memory in bytes */ |
fc6d9e4b A |
42 | unsigned int phys_pages = 0; /* number of physical memory pages */ |
43 | int sleep_seconds = 1; | |
530d02b6 | 44 | int requested_hysteresis_seconds = 0; |
fc6d9e4b A |
45 | boolean_t quiet_mode_on = FALSE; |
46 | boolean_t simulate_mode_on = FALSE; | |
47 | ||
48 | void *range_start_addr = NULL; | |
49 | void *range_end_addr = NULL; | |
50 | void *range_current_addr = NULL; | |
51 | ||
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; | |
58 | int tool_mode = 0; | |
59 | ||
60 | #define TOOL_MODE_FOR_PERCENT 1 | |
61 | #define TOOL_MODE_FOR_LEVEL 2 | |
62 | ||
63 | ||
64 | char random_data[] = "ffd8ffe000104a46494600010101002400240000ffe100744578696600004d4d002a000000080004011a0005000000010000003e011b0005000000010000004601280003000000010002000087690004000000010000004e00000000000000240000000100000024000000010002a002000400000001000003c0a003000400000001000001ff00000000ffdb00430002020202020102020202020202030306040303030307050504060807080808070808090a0d0b09090c0a08080b0f0b0c0d0e0e0e0e090b10110f0e110d0e0e0effdb004301020202030303060404060e0908090e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0effc000110801ff03c003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f9e74fbd37baa2db99e6506391f28371f9519ba67fd9fcabd46cbc1315de8d6776752d7419e049084b152a37283c1dfc8e6bc02db4af18d9df79c9e1bd59a40ae9b65b1761f32953c63ae09c7a1c57656fe24f8896da7c16c9e0bb3748a358d5a4d04b31006324f73c75a00935f7fec9f165ee98b7372e2ddc05795763f2a0f20138ebeb590bac3e70d2b6e1fed1ac6d4ecbc65aa6b973a85c7867528a6998168edec1a38c1c01c2f61c550fec1f16ff00d0bdade4f5ff00447ff0a00eaffb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe66b4f45fed1f1078bb4cd0f4bdf3ea37f7296f6d1ee3f33b1c0cfb7a9f4ae0bfb07c5bff42f6b7ff808ff00e15a9a1c5e3bf0f78c74bd774cd0f5a8751d3ee52e2ddcd9be03a9c8cfb7623d2803d5bc6fe0df11780e0d3ae354bab1bdb1bd678e1bab1b8f36312c6079b112380cac4ae3b9535e7ffdaedff3d5ff00335b3e3af177c4af1f5be9b6da8f8567d36c2c59e486d74fd35e28ccb260c92b003966605b3db71af3cfec1f16ff00d0bdadff00e023ff0085007acf83743d57c6baddd59e9d7062fb3c68d248519c0324ab120c2f3cb38c9ec013dab95b8d427b5bfb8b59a4759a195a3917278652411f98ad9f86fe30f88bf0cb57d56f348f095f5ebdfc2914ab716b200a118918c0ff0068d709a9d878cb55f12ea3aa4fe1cd6127bdba92e2455b47c06772c40e3a64d007d13f09fe1d37c41d135ad7b52d52ef4fd074eba86cff00d1537cd7171310123504e0751927d6be8ed17f65bf0aebde19b4d5ac7c5fe2236b700eddf12060558ab03ee1948fc2be41f84bf123e20fc2d1acd87fc20d77e24f0eeabb1af74cbcb4902974fbb22b0190c3fa0f4afa1748fdad3c51a1691fd9fa57c10b8b4b212bc8b0ac931542c7240c8e067271ef401e9bff000c89a07fd0dbafff00dfb4a3fe191340ff00a1b75fff00bf695c2ffc366f8e7fe88c5cff00df72ff00851ff0d9be39ff00a23173ff007dcbfe1401dd7fc322681ff436ebff00f7ed28ff008644d03fe86dd7ff00efda570bff000d9be39ffa23173ff7dcbfe147fc366f8e7fe88c5cff00df72ff008500775ff0c89a07fd0dbaff00fdfb4a3fe191340ffa1b75ff00fbf695c2ff00c366f8e7fe88c5cffdf72ff851ff000d9be39ffa23173ff7dcbfe1401dd7fc322681ff00436ebfff007ed2be52f8d1f0eeff00e11fc42b2d325d49f51d3afedccf637046d6215b6b2b0f5071f98af733fb6678eb071f062e73fefcbfe15f2a7c5af1cfc4bf8bff001262d7758f0bea76515bc1f67b1b1b7b490a4099c9edcb13c93f4a00fe891bc2fe1c672cda1e96589c92"; | |
65 | ||
66 | #define PAGE_OP_ALLOC 0x1 | |
67 | #define PAGE_OP_FREE 0x2 | |
68 | ||
69 | #define USE_WIRED_PAGES_FOR_PERCENT_MODE FALSE | |
70 | ||
71 | #define MAX_RANGE_SIZE 64 * 1024 * 1024 * 1024ULL | |
72 | ||
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); | |
76 | ||
cf37c299 | 77 | static void |
fc6d9e4b A |
78 | usage(void) |
79 | { | |
80 | fprintf(stderr, "Usage: memory_pressure [options] [<pages>]\n" | |
81 | " Allocate memory and wait forever.\n" | |
82 | " Options include:\n" | |
cf37c299 | 83 | " -l <level> - allocate memory until a low memory notification is received (warn OR critical)\n" |
fc6d9e4b A |
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" | |
530d02b6 | 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" |
fc6d9e4b | 88 | " -v <print VM stats> - print VM statistics every sampling interval\n" |
cf37c299 | 89 | " -Q <quiet mode> - reduces the tool's output\n" |
fc6d9e4b A |
90 | " -S - simulate the system's memory pressure level without applying any real pressure\n" |
91 | " \n" | |
92 | ); | |
93 | exit(0); | |
94 | } | |
95 | ||
96 | static unsigned int | |
cf37c299 | 97 | read_sysctl_int(const char* name) |
fc6d9e4b A |
98 | { |
99 | unsigned int var; | |
100 | size_t var_size; | |
101 | int error; | |
102 | ||
103 | var_size = sizeof(var); | |
104 | error = sysctlbyname(name, &var, &var_size, NULL, 0); | |
105 | if( error ) { | |
106 | perror(name); | |
107 | exit(-1); | |
108 | } | |
109 | return var; | |
110 | } | |
111 | ||
c0bbac3a A |
112 | static long long |
113 | read_sysctl_long_long(const char* name) | |
114 | { | |
115 | long long var; | |
116 | size_t var_size; | |
117 | int error; | |
118 | ||
119 | var_size = sizeof(var); | |
120 | error = sysctlbyname(name, &var, &var_size, NULL, 0); | |
121 | if( error ) { | |
122 | perror(name); | |
123 | exit(-1); | |
124 | } | |
125 | return var; | |
126 | } | |
127 | ||
fc6d9e4b | 128 | static int |
cf37c299 | 129 | get_percent_free(unsigned int* level) |
fc6d9e4b A |
130 | { |
131 | int error; | |
132 | ||
133 | error = memorystatus_get_level((user_addr_t) level); | |
134 | ||
135 | if( error ) { | |
136 | perror("memorystatus_get_level failed:"); | |
137 | exit(-1); | |
138 | } | |
139 | return error; | |
140 | } | |
141 | ||
142 | void | |
143 | print_vm_statistics(void) | |
144 | { | |
145 | unsigned int count = HOST_VM_INFO64_COUNT; | |
146 | kern_return_t ret = 0; | |
147 | vm_statistics64_data_t vm_stat;; | |
148 | ||
149 | if (quiet_mode_on == TRUE) { | |
150 | return; | |
151 | } | |
152 | ||
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); | |
155 | } else { | |
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)); | |
160 | ||
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)); | |
164 | ||
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)); | |
cf37c299 | 171 | |
fc6d9e4b A |
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)); | |
176 | ||
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)); | |
180 | ||
181 | #if 0 | |
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)); | |
186 | #endif | |
187 | printf("\n"); | |
188 | } | |
189 | } | |
190 | ||
c0bbac3a A |
191 | /* |
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 | |
194 | */ | |
195 | static unsigned long long | |
196 | get_max_range_size() | |
197 | { | |
198 | unsigned long long the_max_range_size = MAX_RANGE_SIZE; | |
199 | ||
200 | if (phys_mem * 4 > the_max_range_size) { | |
201 | the_max_range_size = phys_mem * 4; | |
202 | } | |
203 | ||
204 | return the_max_range_size; | |
205 | } | |
206 | ||
fc6d9e4b A |
207 | static int |
208 | reached_or_bypassed_desired_result(void) | |
209 | { | |
210 | if (tool_mode == TOOL_MODE_FOR_LEVEL) { | |
211 | ||
212 | unsigned int current_level = 0; | |
213 | ||
214 | current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level"); | |
215 | ||
216 | if (desired_level > 0 && current_level >= desired_level) { | |
217 | return 1; | |
218 | } | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | if (tool_mode == TOOL_MODE_FOR_PERCENT) { | |
cf37c299 | 224 | |
fc6d9e4b A |
225 | unsigned int current_percent = 0; |
226 | ||
227 | get_percent_free(¤t_percent); | |
228 | ||
229 | if (desired_percent > 0 && current_percent <= desired_percent) { | |
230 | return 1; | |
231 | } | |
232 | ||
233 | return 0; | |
234 | } | |
235 | ||
236 | return 0; | |
237 | } | |
238 | ||
239 | static void | |
240 | reference_pages(int level) | |
241 | { | |
242 | int error; | |
243 | void *addr = NULL; | |
244 | int num_pages = 0; | |
245 | ||
246 | error = pthread_mutex_lock(&reference_pages_mutex); | |
247 | addr = range_start_addr; | |
248 | again: | |
cf37c299 | 249 | while(start_referencing_pages == 0) { |
fc6d9e4b A |
250 | error = pthread_cond_wait(&reference_pages_condvar, &reference_pages_mutex); |
251 | } | |
252 | ||
253 | start_allocing_pages = 0; | |
254 | pthread_mutex_unlock(&reference_pages_mutex); | |
cf37c299 | 255 | |
fc6d9e4b A |
256 | num_pages = 0; |
257 | for(; addr < range_current_addr;) { | |
cf37c299 | 258 | |
fc6d9e4b | 259 | char p; |
cf37c299 | 260 | |
fc6d9e4b A |
261 | if (reached_or_bypassed_desired_result()) { |
262 | //printf("stopped referencing after %d pages\n", num_pages); | |
263 | break; | |
264 | } | |
265 | ||
266 | p = *(char*) addr; | |
267 | addr += PAGE_SIZE; | |
268 | num_pages++; | |
cf37c299 | 269 | |
fc6d9e4b | 270 | } |
cf37c299 | 271 | |
fc6d9e4b A |
272 | //if (num_pages) { |
273 | // printf("Referenced %d\n", num_pages); | |
274 | //} | |
275 | error = pthread_mutex_lock(&reference_pages_mutex); | |
276 | start_referencing_pages = 0; | |
277 | start_allocing_pages = 1; | |
278 | ||
cf37c299 | 279 | goto again; |
fc6d9e4b A |
280 | } |
281 | ||
282 | static void | |
cf37c299 | 283 | process_pages(int num_pages, int page_op) |
fc6d9e4b A |
284 | { |
285 | if (num_pages > 0) { | |
cf37c299 A |
286 | |
287 | int error = 0, i = 0; | |
fc6d9e4b A |
288 | size_t size = num_pages * PAGE_SIZE; |
289 | ||
290 | if (page_op == PAGE_OP_ALLOC) { | |
291 | ||
292 | if (tool_mode == TOOL_MODE_FOR_PERCENT && USE_WIRED_PAGES_FOR_PERCENT_MODE) { | |
293 | error = mlock(range_current_addr, size); | |
294 | if (error == -1) { | |
295 | perror("Failed to lock memory!"); | |
296 | exit(-1); | |
cf37c299 | 297 | } |
fc6d9e4b A |
298 | |
299 | memset(range_current_addr, 0xFF, size); | |
300 | range_current_addr += size; | |
301 | ||
302 | } else { | |
303 | ||
304 | pthread_mutex_lock(&reference_pages_mutex); | |
305 | while (start_allocing_pages == 0) { | |
306 | pthread_mutex_unlock(&reference_pages_mutex); | |
307 | sleep(1); | |
308 | pthread_mutex_lock(&reference_pages_mutex); | |
309 | } | |
310 | pthread_mutex_unlock(&reference_pages_mutex); | |
311 | ||
312 | for (i=0; i < num_pages; i++) { | |
cf37c299 | 313 | |
fc6d9e4b A |
314 | if (reached_or_bypassed_desired_result()) { |
315 | //printf("stopped faulting after %d pages\n", i); | |
316 | break; | |
317 | } | |
c0bbac3a A |
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; | |
321 | } else { | |
322 | printf("\nRun out of allocable memory\n"); | |
323 | exit(0); | |
324 | } | |
fc6d9e4b A |
325 | } |
326 | ||
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); | |
331 | } | |
332 | } else { | |
333 | if (tool_mode == TOOL_MODE_FOR_PERCENT && USE_WIRED_PAGES_FOR_PERCENT_MODE) { | |
334 | error = munlock(range_current_addr, size); | |
335 | if (error == -1) { | |
336 | perror("Failed to unlock memory!"); | |
337 | exit(-1); | |
cf37c299 A |
338 | } |
339 | ||
fc6d9e4b A |
340 | error = madvise(range_current_addr, size, MADV_FREE); |
341 | if (error == -1) { | |
342 | perror("Failed to madv_free memory!"); | |
343 | exit(-1); | |
344 | } | |
345 | ||
346 | range_current_addr -= size; | |
347 | ||
348 | } else { | |
349 | pthread_mutex_lock(&reference_pages_mutex); | |
350 | while (start_referencing_pages == 1) { | |
351 | pthread_mutex_unlock(&reference_pages_mutex); | |
352 | sleep(1); | |
353 | pthread_mutex_lock(&reference_pages_mutex); | |
354 | } | |
cf37c299 | 355 | |
fc6d9e4b A |
356 | error = madvise(range_current_addr, size, MADV_FREE); |
357 | if (error == -1) { | |
358 | perror("Failed to madv_free memory!"); | |
359 | exit(-1); | |
360 | } | |
361 | range_current_addr -= size; | |
362 | start_referencing_pages = 1; | |
363 | pthread_cond_signal(&reference_pages_condvar); | |
364 | pthread_mutex_unlock(&reference_pages_mutex); | |
365 | } | |
366 | } | |
367 | } | |
368 | } | |
369 | ||
370 | void | |
cf37c299 | 371 | munch_for_level(unsigned int sleep_seconds, unsigned int print_vm_stats) |
fc6d9e4b A |
372 | { |
373 | ||
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; | |
383 | ||
384 | current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level"); | |
385 | ||
386 | if (current_level >= desired_level) { | |
387 | return; | |
388 | } | |
389 | ||
390 | get_percent_free(¤t_percent); | |
cf37c299 | 391 | |
fc6d9e4b A |
392 | if (print_vm_stats) { |
393 | print_vm_stats_on_page_processing = TRUE; | |
394 | } | |
395 | ||
396 | page_op = PAGE_OP_ALLOC; | |
397 | previous_page_op = 0; | |
398 | ||
399 | while (1) { | |
400 | ||
401 | if (current_percent > percent_for_level) { | |
402 | desired_percent = current_percent - percent_for_level; | |
403 | } else { | |
404 | desired_percent = 1; | |
405 | } | |
cf37c299 | 406 | |
fc6d9e4b A |
407 | pages_to_process = (desired_percent * phys_pages) / 100; |
408 | ||
409 | page_op = PAGE_OP_ALLOC; | |
410 | ||
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; | |
415 | fflush(stdout); | |
416 | } else { | |
417 | printf("."); | |
418 | fflush(stdout); | |
419 | } | |
cf37c299 | 420 | |
fc6d9e4b A |
421 | if (print_vm_stats_on_page_processing == TRUE) { |
422 | print_vm_statistics(); | |
423 | } | |
424 | process_pages(pages_to_process, page_op); | |
425 | ok_to_print_stablity_message = TRUE; | |
426 | ||
427 | current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level"); | |
428 | ||
429 | if (current_level >= desired_level) { | |
cf37c299 | 430 | |
fc6d9e4b A |
431 | while(1) { |
432 | current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level"); | |
433 | if (current_level < desired_level) { | |
434 | break; | |
435 | } | |
cf37c299 | 436 | |
fc6d9e4b A |
437 | if (current_level > desired_level) { |
438 | page_op = PAGE_OP_FREE; | |
cf37c299 | 439 | |
fc6d9e4b A |
440 | get_percent_free(¤t_percent); |
441 | ||
442 | if (stabilized_percentage > current_percent) { | |
443 | pages_to_process = ((stabilized_percentage - current_percent) * phys_pages) / 100; | |
cf37c299 | 444 | |
fc6d9e4b A |
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; | |
448 | fflush(stdout); | |
449 | } else { | |
450 | printf("."); | |
451 | fflush(stdout); | |
452 | } | |
453 | ||
454 | if (print_vm_stats_on_page_processing == TRUE) { | |
455 | print_vm_statistics(); | |
456 | } | |
457 | process_pages(pages_to_process, page_op); | |
458 | ok_to_print_stablity_message = TRUE; | |
459 | } | |
460 | } | |
461 | ||
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); | |
467 | fflush(stdout); | |
468 | ok_to_print_stablity_message = FALSE; | |
469 | previous_page_op = 0; | |
470 | } else { | |
471 | printf("."); | |
472 | fflush(stdout); | |
473 | } | |
474 | ||
475 | stabilized_percentage = current_percent; | |
476 | sleep(sleep_seconds); | |
477 | current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level"); | |
478 | } | |
479 | } | |
480 | } | |
481 | ||
482 | get_percent_free(¤t_percent); | |
483 | //printf("Percent: %d Level: %d\n", current_percent, current_level); | |
484 | sleep(1); | |
cf37c299 | 485 | |
fc6d9e4b A |
486 | if (print_vm_stats) { |
487 | print_vm_stats_on_page_processing = TRUE; | |
488 | } | |
489 | ||
490 | } /* while */ | |
491 | } | |
492 | ||
cf37c299 A |
493 | void |
494 | munch_for_percentage(unsigned int sleep_seconds, unsigned int wait_percent_free, unsigned int print_vm_stats) | |
fc6d9e4b A |
495 | { |
496 | ||
497 | int total_pages_allocated = 0; | |
530d02b6 | 498 | int current_stable_timer = 0; /* in seconds */ |
fc6d9e4b A |
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; | |
505 | ||
506 | /* Allocate until memory level is hit. */ | |
cf37c299 | 507 | |
fc6d9e4b A |
508 | get_percent_free(¤t_percent); |
509 | ||
cf37c299 | 510 | /* |
fc6d9e4b A |
511 | * "wait" mode doesn't alloc, it just waits and exits. This is used |
512 | * while waiting for *other* processes to allocate memory. | |
513 | */ | |
514 | if (wait_percent_free) { | |
515 | while (current_percent > wait_percent_free) { | |
516 | sleep(sleep_seconds); | |
517 | get_percent_free (¤t_percent); | |
518 | } | |
519 | return; | |
520 | } | |
521 | ||
522 | page_op = PAGE_OP_ALLOC; | |
523 | previous_page_op = 0; | |
524 | ||
525 | while (1) { | |
526 | ||
527 | if (current_percent > desired_percent) { | |
528 | pages_to_process = ((current_percent - desired_percent) * phys_pages) / 100; | |
529 | page_op = PAGE_OP_ALLOC; | |
530 | } else { | |
531 | pages_to_process = ((desired_percent - current_percent) * phys_pages) / 100; | |
532 | page_op = PAGE_OP_FREE; | |
533 | } | |
534 | ||
535 | if (pages_to_process > 0) { | |
536 | ||
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); | |
540 | fflush(stdout); | |
541 | previous_page_op = page_op; | |
542 | } else { | |
543 | printf("."); | |
544 | fflush(stdout); | |
545 | } | |
546 | ||
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; | |
551 | } else { | |
cf37c299 | 552 | |
fc6d9e4b A |
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; | |
557 | } else { | |
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); | |
561 | fflush(stdout); | |
562 | ok_to_print_stablity_message = FALSE; | |
563 | } | |
564 | } | |
565 | } | |
cf37c299 | 566 | |
fc6d9e4b A |
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; | |
570 | } | |
571 | } else { | |
572 | if (ok_to_print_stablity_message == TRUE) { | |
573 | print_vm_statistics(); | |
574 | printf("\nStable at percent free: %d", current_percent); | |
575 | fflush(stdout); | |
576 | ok_to_print_stablity_message = FALSE; | |
577 | } else { | |
578 | printf("."); | |
579 | fflush(stdout); | |
580 | } | |
530d02b6 A |
581 | |
582 | /* Stability has been reached; Increment current_stable_timer by sleep_seconds */ | |
583 | ||
584 | if (current_stable_timer <= requested_hysteresis_seconds){ | |
585 | current_stable_timer += sleep_seconds; | |
586 | /* Debug only */ | |
587 | /* printf("\n Percentage Free stable for %d seconds", current_stable_timer); */ | |
588 | } else { | |
589 | printf ("\n Maintained memory pressure to %d percent free for more than %d seconds. Stopping pressure now.", current_percent, requested_hysteresis_seconds); | |
590 | return; | |
591 | } | |
592 | ||
fc6d9e4b A |
593 | print_vm_stats_on_page_processing = FALSE; |
594 | } | |
595 | ||
596 | if (print_vm_stats_on_page_processing) { | |
cf37c299 | 597 | |
fc6d9e4b A |
598 | print_vm_statistics(); |
599 | ||
600 | if (print_vm_stats_on_page_processing == TRUE) { | |
601 | print_vm_stats_on_page_processing = FALSE; | |
602 | } | |
603 | } | |
cf37c299 | 604 | |
fc6d9e4b A |
605 | sleep(sleep_seconds); |
606 | ||
607 | get_percent_free(¤t_percent); | |
608 | } /* while */ | |
609 | } | |
610 | ||
cf37c299 | 611 | int |
fc6d9e4b A |
612 | main(int argc, char * const argv[]) |
613 | { | |
614 | int opt; | |
615 | unsigned int wait_percent_free = 0; | |
616 | unsigned int current_percent = 0; | |
617 | unsigned int print_vm_stats = 0; | |
618 | char level[10]; | |
619 | ||
530d02b6 | 620 | while ((opt = getopt(argc, argv, "hl:p:s:w:y:vQS")) != -1) { |
fc6d9e4b A |
621 | switch (opt) { |
622 | case 'h': | |
623 | usage(); | |
624 | break; | |
625 | case 'l': | |
626 | strlcpy(level, optarg, 9); | |
627 | ||
628 | if (strncasecmp(level, "normal", 6) == 0) { | |
cf37c299 | 629 | desired_level = DISPATCH_MEMORYPRESSURE_NORMAL; |
fc6d9e4b A |
630 | percent_for_level = 90; |
631 | } else if (strncasecmp(level, "warn", 4) == 0) { | |
cf37c299 | 632 | desired_level = DISPATCH_MEMORYPRESSURE_WARN; |
fc6d9e4b A |
633 | percent_for_level = 60; |
634 | ||
635 | } else if (strncasecmp(level, "critical", 8) == 0) { | |
cf37c299 | 636 | desired_level = DISPATCH_MEMORYPRESSURE_CRITICAL; |
fc6d9e4b A |
637 | percent_for_level = 30; |
638 | ||
639 | } else { | |
640 | printf("Incorrect level. Allowed \"normal\" or \"warn\" or \"critical\". Specified: %s\n", level); | |
641 | exit(0); | |
642 | } | |
643 | break; | |
644 | case 'p': | |
645 | desired_percent = atoi(optarg); | |
646 | break; | |
647 | case 's': | |
648 | sleep_seconds = atoi(optarg); | |
649 | break; | |
650 | case 'w': | |
651 | wait_percent_free = atoi(optarg); | |
652 | break; | |
530d02b6 A |
653 | case 'y': |
654 | requested_hysteresis_seconds = atoi(optarg); | |
655 | break; | |
fc6d9e4b A |
656 | case 'v': |
657 | print_vm_stats = 1; | |
cf37c299 | 658 | break; |
fc6d9e4b A |
659 | case 'Q': |
660 | quiet_mode_on = TRUE; | |
661 | break; | |
662 | case 'S': | |
663 | simulate_mode_on = TRUE; | |
664 | break; | |
665 | default: | |
666 | usage(); | |
667 | } | |
668 | } | |
669 | ||
670 | if (simulate_mode_on == TRUE && desired_level == 0) { | |
671 | printf("Expected level with -l along with \"simulated\" mode.\n"); | |
672 | return 0; | |
673 | } | |
674 | ||
530d02b6 A |
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"); | |
678 | usage(); | |
679 | } | |
680 | } | |
681 | ||
c0bbac3a | 682 | phys_mem = read_sysctl_long_long("hw.memsize"); |
fc6d9e4b A |
683 | phys_pages = (unsigned int) (phys_mem / PAGE_SIZE); |
684 | ||
c0bbac3a | 685 | printf("The system has %lld (%d pages with a page size of %lu).\n", phys_mem, phys_pages, PAGE_SIZE); |
fc6d9e4b A |
686 | |
687 | print_vm_statistics(); | |
cf37c299 | 688 | |
fc6d9e4b A |
689 | get_percent_free(¤t_percent); |
690 | printf("System-wide memory free percentage: %d%%\n", current_percent); | |
691 | ||
692 | if (desired_percent == 0 && wait_percent_free == 0 && desired_level == 0) { | |
693 | return 0; | |
694 | } | |
cf37c299 | 695 | |
fc6d9e4b A |
696 | if (simulate_mode_on == TRUE) { |
697 | ||
cf37c299 | 698 | /* |
fc6d9e4b | 699 | We use the sysctl "kern.memorypressure_manual_trigger" for this mode. Here's a blurb: |
cf37c299 | 700 | |
fc6d9e4b A |
701 | Supported behaviors when using the manual trigger tests. |
702 | ||
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 | |
709 | ||
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". | |
712 | ||
713 | For this tool, currently, we only support the "TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL" options. | |
714 | */ | |
715 | ||
716 | #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6 | |
cf37c299 | 717 | |
fc6d9e4b A |
718 | unsigned int var = 0; |
719 | size_t var_size = 0; | |
720 | int error = 0; | |
721 | ||
722 | var_size = sizeof(var); | |
723 | ||
724 | var = ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL << 16) | desired_level); | |
725 | ||
726 | error = sysctlbyname("kern.memorypressure_manual_trigger", NULL, 0, &var, var_size); | |
cf37c299 | 727 | |
fc6d9e4b A |
728 | if(error) { |
729 | perror("sysctl: kern.memorypressure_manual_trigger failed "); | |
730 | exit(-1); | |
731 | } | |
cf37c299 | 732 | |
fc6d9e4b A |
733 | printf("Waiting %d seconds before resetting system state\n", sleep_seconds); |
734 | ||
735 | sleep(sleep_seconds); | |
736 | ||
737 | var_size = sizeof(var); | |
738 | ||
cf37c299 | 739 | var = ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL << 16) | DISPATCH_MEMORYPRESSURE_NORMAL); |
fc6d9e4b A |
740 | |
741 | error = sysctlbyname("kern.memorypressure_manual_trigger", NULL, 0, &var, var_size); | |
cf37c299 | 742 | |
fc6d9e4b A |
743 | if(error) { |
744 | perror("sysctl: kern.memorypressure_manual_trigger failed "); | |
745 | exit(-1); | |
746 | } | |
747 | ||
748 | printf("Reset system state\n"); | |
749 | ||
750 | } else { | |
c0bbac3a | 751 | range_start_addr = mmap(NULL, get_max_range_size(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0); |
cf37c299 | 752 | |
fc6d9e4b A |
753 | if (range_start_addr == MAP_FAILED) { |
754 | perror("mmap failed"); | |
755 | } else { | |
756 | ||
757 | int error = 0; | |
758 | pthread_t thread = NULL; | |
759 | ||
760 | error = pthread_create(&thread, NULL, (void*) reference_pages, NULL); | |
761 | ||
762 | range_current_addr = range_start_addr; | |
c0bbac3a | 763 | range_end_addr = range_start_addr + get_max_range_size(); |
fc6d9e4b A |
764 | start_allocing_pages = 1; |
765 | ||
766 | if (desired_level) { | |
767 | tool_mode = TOOL_MODE_FOR_LEVEL; | |
768 | munch_for_level(sleep_seconds, print_vm_stats); | |
769 | } else { | |
770 | tool_mode = TOOL_MODE_FOR_PERCENT; | |
771 | munch_for_percentage(sleep_seconds, wait_percent_free, print_vm_stats); | |
772 | } | |
773 | } | |
774 | } | |
775 | ||
776 | return 0; | |
777 | } |