• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /macosx-10.9.5/xnu-2422.115.4/tools/tests/unit_tests/cpu_monitor_tests_11646922_src/mem_hog/
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
13static void
14dirty_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
25char *pname;
26
27void 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
38int 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}
222