]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/unit_tests/cpu_monitor_tests_11646922_src/mem_hog/mem_hog.c
4579161d413bd19ea296f6520ac97cc8cdcff4d2
[apple/xnu.git] / tools / tests / unit_tests / cpu_monitor_tests_11646922_src / mem_hog / mem_hog.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <mach/mach.h>
5 #include <mach/task.h>
6 #include <sys/kern_memorystatus.h>
7
8 #define PAGESIZE 4096
9
10 /* Trigger forced jetsam */
11 #define MEMORYSTATUS_CMD_TEST_JETSAM 1000
12
13 static void
14 dirty_chunk(void *chunk, int chunk_size)
15 {
16 int i;
17 char *p;
18
19 // Dirty every word in the chunk.
20 for (p = chunk; p < (char *)chunk + (chunk_size * 1024 * 1024); p += 4) {
21 *p = 'Z';
22 }
23 }
24
25 char *pname;
26
27 void usage(void) {
28 printf("usage: %s [-re] [-l MB] [-w MB] [-m MB] [-o num] [-k pid] <chunk_size in MB> <interval in milliseconds>\n", pname);
29 printf("\t-r: after reaching max, re-dirty it all when the user prompts to do so.\n");
30 printf("\t-l: program the task's physical footprint limit to this value (in MB).\n");
31 printf("\t-w: program the task's jetsam high watermark to this value (in MB).\n");
32 printf("\t-m: dirty no more than this amount (in MB).\n");
33 printf("\t-e: exit after reaching -m max dirty.\n");
34 printf("\t-o: oscillate at the max this number of times and then continue on up.\n");
35 printf("\t-k: trigger explicit jetsam kill of this pid (and then exit).\n");
36 }
37
38 int main(int argc, char *argv[])
39 {
40 int ch;
41 void **chunks;
42 int nchunks;
43 int max_chunks;
44 int oscillations = -1;
45 int tot_mb = 0;
46 int chunk_size;
47 int interval;
48 int max = -1;
49 int limit = -2;
50 int high_watermark = -1;
51 int victim = -1;
52 int old_limit;
53 boolean_t redirty = FALSE;
54 boolean_t exit_after_max = FALSE;
55
56 int oscillation_cnt = 0;
57
58 pname = argv[0];
59
60 printf("pid: %d\n", getpid());
61
62 while ((ch = getopt(argc, argv, "rem:l:w:k:o:")) != -1) {
63 switch (ch) {
64 case 'm':
65 max = atoi(optarg);
66 break;
67 case 'l':
68 limit = atoi(optarg);
69 break;
70 case 'w':
71 high_watermark = atoi(optarg);
72 break;
73 case 'o':
74 oscillations = atoi(optarg);
75 break;
76 case 'r':
77 redirty = TRUE;
78 break;
79 case 'e':
80 exit_after_max = TRUE;
81 break;
82 case 'k':
83 victim = atoi(optarg);
84 break;
85 case 'h':
86 default:
87 usage();
88 exit(1);
89 }
90 }
91
92 argc -= optind;
93 argv += optind;
94
95 if (victim != -1) {
96 int r;
97 /*
98 * int memorystatus_control(uint32_t command, int32_t pid, uint32_t flags, user_addr_t buffer, size_t buffersize);
99 */
100 if ((r = memorystatus_control(MEMORYSTATUS_CMD_TEST_JETSAM, victim, 0, 0, 0)) != 0) {
101 perror("memorystatus_control");
102 exit(1);
103 }
104 printf("killed process %d\n", victim);
105
106 }
107
108 if (argc != 2) {
109 usage();
110 exit(1);
111 }
112
113 chunk_size = atoi(argv[0]);
114 interval = atoi(argv[1]);
115
116 if (limit != -2) {
117 kern_return_t kr;
118 if ((kr = task_set_phys_footprint_limit(mach_task_self(), limit, &old_limit)) != KERN_SUCCESS) {
119 fprintf(stderr, "task_set_phys_footprint_limit() failed: %s\n", mach_error_string(kr));
120 exit(1);
121 }
122 printf("phys footprint limit set to %d MB (was: %d MB)\n", limit, old_limit);
123 }
124
125 if (high_watermark != -1) {
126 int r;
127 /*
128 * int memorystatus_control(uint32_t command, int32_t pid, uint32_t flags, user_addr_t buffer, size_t buffersize);
129 */
130 if ((r = memorystatus_control(MEMORYSTATUS_CMD_SET_JETSAM_HIGH_WATER_MARK, getpid(), high_watermark, 0, 0)) != 0) {
131 perror("memorystatus_control");
132 exit(1);
133 }
134 printf("high watermark set to %d MB\n", high_watermark);
135 }
136
137 printf("consuming memory in chunks of %d MB every %d milliseconds.\n", chunk_size, interval);
138
139 printf("total consumed: ");
140 fflush(stdout);
141
142 /*
143 * Estimate max number of chunks possible, using 4GB as absolute max amount of memory
144 * we could ever use.
145 */
146 max_chunks = 4000 / chunk_size;
147 if ((chunks = calloc(max_chunks, sizeof (*chunks))) == NULL) {
148 perror("malloc");
149 exit(1);
150 }
151 nchunks = 0;
152
153 while (1) {
154 if ((chunks[nchunks] = malloc(chunk_size * 1024 * 1024)) == NULL) {
155 perror("malloc");
156 exit(1);
157 }
158
159 tot_mb += chunk_size;
160
161 dirty_chunk(chunks[nchunks], chunk_size);
162
163 nchunks++;
164
165 putchar(0x8); putchar(0x8); putchar(0x8); putchar(0x8);
166 printf("%4d", tot_mb);
167 fflush(stdout);
168
169 if ((max != -1) && (tot_mb > max)) {
170 printf("\nMax reached.\n");
171
172 if (exit_after_max) {
173 exit(0);
174 }
175
176 if ((oscillations == -1) || (oscillation_cnt < oscillations)) {
177 if (redirty) {
178 while (1) {
179 int i, ch;
180
181 printf("Press any key to re-dirty ('q' to quit)...");
182 fflush(stdout);
183 if ((ch = getchar()) == 'q') {
184 exit(0);
185 }
186
187 for (i = 0; i < nchunks; i++) {
188 dirty_chunk(chunks[i], chunk_size);
189 }
190 }
191 }
192
193 /*
194 * We've broken the limit of what we should be consuming; free the
195 * most recent three chunks and go round again.
196 */
197 nchunks--;
198 free(chunks[nchunks]);
199 chunks[nchunks] = NULL;
200 tot_mb -= chunk_size;
201
202 if (nchunks > 1) {
203 nchunks--;
204 free(chunks[nchunks]);
205 chunks[nchunks] = NULL;
206 tot_mb -= chunk_size;
207 nchunks--;
208 free(chunks[nchunks]);
209 chunks[nchunks] = NULL;
210 tot_mb -= chunk_size;
211 }
212
213 oscillation_cnt++;
214 }
215 }
216
217 usleep(interval * 1000);
218 }
219
220 return (1);
221 }