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