]>
Commit | Line | Data |
---|---|---|
8459d725 | 1 | /* |
cf37c299 | 2 | * Copyright (c) 2009-2016 Apple Inc. All rights reserved. |
8459d725 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
cf37c299 | 5 | * |
8459d725 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. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
cf37c299 | 14 | * |
8459d725 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
cf37c299 | 17 | * |
8459d725 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
cf37c299 | 25 | * |
8459d725 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
1815bff5 A |
28 | /* |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
cf37c299 | 31 | /* |
1815bff5 A |
32 | * Mach Operating System |
33 | * Copyright (c) 1991,1990,1989 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
cf37c299 | 35 | * |
1815bff5 A |
36 | * Permission to use, copy, modify and distribute this software and its |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
cf37c299 A |
41 | * |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS | |
1815bff5 A |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
cf37c299 | 45 | * |
1815bff5 | 46 | * Carnegie Mellon requests users of this software to return to |
cf37c299 | 47 | * |
1815bff5 A |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
cf37c299 | 52 | * |
1815bff5 A |
53 | * any improvements or extensions that they make and grant Carnegie the |
54 | * rights to redistribute these changes. | |
55 | */ | |
56 | /* | |
57 | * zprint.c | |
58 | * | |
59 | * utility for printing out zone structures | |
60 | * | |
61 | * With no arguments, prints information on all zone structures. | |
62 | * With an argument, prints information only on those zones for | |
63 | * which the given name is a substring of the zone's name. | |
64 | * With a "-w" flag, calculates how much much space is allocated | |
65 | * to zones but not currently in use. | |
66 | */ | |
67 | ||
9726c137 | 68 | #include <vm_statistics.h> |
1815bff5 | 69 | #include <stdio.h> |
34d340d7 | 70 | #include <stdlib.h> |
1815bff5 A |
71 | #include <string.h> |
72 | #include <mach/mach.h> | |
73 | #include <mach_debug/mach_debug.h> | |
74 | #include <mach/mach_error.h> | |
ef8ad44b A |
75 | #include <libutil.h> |
76 | #include <errno.h> | |
9726c137 A |
77 | #include <sysexits.h> |
78 | #include <getopt.h> | |
79 | #include <malloc/malloc.h> | |
80 | #include <Kernel/IOKit/IOKitDebug.h> | |
81 | #include <Kernel/libkern/OSKextLibPrivate.h> | |
82 | #include <IOKit/IOKitLib.h> | |
83 | #include <IOKit/IOKitKeys.h> | |
84 | #include <IOKit/kext/OSKext.h> | |
85 | #include <CoreFoundation/CoreFoundation.h> | |
86 | #include <CoreSymbolication/CoreSymbolication.h> | |
87 | ||
1815bff5 A |
88 | #define streql(a, b) (strcmp((a), (b)) == 0) |
89 | #define strneql(a, b, n) (strncmp((a), (b), (n)) == 0) | |
9726c137 A |
90 | #define PRINTK(fmt, value) \ |
91 | printf(fmt "K", (value) / 1024 ) /* ick */ | |
1815bff5 | 92 | |
8459d725 A |
93 | static void usage(void); |
94 | static void printzone(mach_zone_name_t *, task_zone_info_t *); | |
95 | static void colprintzone(mach_zone_name_t *, task_zone_info_t *); | |
96 | static int find_deltas(mach_zone_name_t *, task_zone_info_t *, task_zone_info_t *, char *, int, int); | |
97 | static void colprintzoneheader(void); | |
9726c137 A |
98 | static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen); |
99 | ||
100 | static int SortName(const void * left, const void * right); | |
101 | static int SortSize(const void * left, const void * right); | |
102 | static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, int (*func)(const void *, const void *), boolean_t column); | |
1815bff5 A |
103 | |
104 | static char *program; | |
105 | ||
8459d725 A |
106 | static pid_t pid = 0; |
107 | static task_t task = TASK_NULL; | |
108 | static boolean_t ShowPid = FALSE; | |
109 | ||
110 | static boolean_t ShowDeltas = FALSE; | |
1815bff5 | 111 | static boolean_t ShowWasted = FALSE; |
8459d725 | 112 | static boolean_t ShowTotal = FALSE; |
9726c137 | 113 | static boolean_t ShowLarge = TRUE; |
1815bff5 A |
114 | static boolean_t SortZones = FALSE; |
115 | static boolean_t ColFormat = TRUE; | |
116 | static boolean_t PrintHeader = TRUE; | |
117 | ||
8459d725 A |
118 | static unsigned long long totalsize = 0; |
119 | static unsigned long long totalused = 0; | |
120 | static unsigned long long totalsum = 0; | |
121 | static unsigned long long pidsum = 0; | |
122 | ||
123 | static int last_time = 0; | |
124 | ||
125 | static char *zname = NULL; | |
9726c137 | 126 | static size_t znamelen = 0; |
8459d725 A |
127 | |
128 | static void | |
129 | sigintr(__unused int signum) | |
130 | { | |
131 | last_time = 1; | |
132 | } | |
1815bff5 A |
133 | |
134 | static void | |
8459d725 | 135 | usage(void) |
1815bff5 | 136 | { |
cf37c299 | 137 | fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p <pid>] [name]\n", program); |
1815bff5 A |
138 | exit(1); |
139 | } | |
140 | ||
34d340d7 | 141 | int |
8459d725 | 142 | main(int argc, char **argv) |
1815bff5 | 143 | { |
8459d725 A |
144 | mach_zone_name_t *name = NULL; |
145 | unsigned int nameCnt = 0; | |
146 | task_zone_info_t *info = NULL; | |
147 | unsigned int infoCnt = 0; | |
9726c137 A |
148 | mach_memory_info_t *wiredInfo = NULL; |
149 | unsigned int wiredInfoCnt = 0; | |
8459d725 A |
150 | task_zone_info_t *max_info = NULL; |
151 | char *deltas = NULL; | |
1815bff5 A |
152 | |
153 | kern_return_t kr; | |
154 | int i, j; | |
8459d725 A |
155 | int first_time = 1; |
156 | int must_print = 1; | |
157 | int interval = 1; | |
1815bff5 | 158 | |
8459d725 | 159 | signal(SIGINT, sigintr); |
ef8ad44b | 160 | |
1815bff5 A |
161 | program = strrchr(argv[0], '/'); |
162 | if (program == NULL) | |
163 | program = argv[0]; | |
164 | else | |
165 | program++; | |
166 | ||
167 | for (i = 1; i < argc; i++) { | |
8459d725 A |
168 | if (streql(argv[i], "-d")) |
169 | ShowDeltas = TRUE; | |
170 | else if (streql(argv[i], "-t")) | |
171 | ShowTotal = TRUE; | |
172 | else if (streql(argv[i], "-T")) | |
173 | ShowTotal = FALSE; | |
174 | else if (streql(argv[i], "-w")) | |
1815bff5 A |
175 | ShowWasted = TRUE; |
176 | else if (streql(argv[i], "-W")) | |
177 | ShowWasted = FALSE; | |
9726c137 A |
178 | else if (streql(argv[i], "-l")) |
179 | ShowLarge = TRUE; | |
180 | else if (streql(argv[i], "-L")) | |
181 | ShowLarge = FALSE; | |
1815bff5 A |
182 | else if (streql(argv[i], "-s")) |
183 | SortZones = TRUE; | |
184 | else if (streql(argv[i], "-S")) | |
185 | SortZones = FALSE; | |
186 | else if (streql(argv[i], "-c")) | |
187 | ColFormat = TRUE; | |
188 | else if (streql(argv[i], "-C")) | |
189 | ColFormat = FALSE; | |
190 | else if (streql(argv[i], "-H")) | |
191 | PrintHeader = FALSE; | |
8459d725 A |
192 | else if (streql(argv[i], "-p")) { |
193 | ShowPid = TRUE; | |
194 | if (i < argc - 1) { | |
195 | pid = atoi(argv[i+1]); | |
196 | i++; | |
197 | } else | |
198 | usage(); | |
199 | } else if (streql(argv[i], "--")) { | |
1815bff5 A |
200 | i++; |
201 | break; | |
202 | } else if (argv[i][0] == '-') | |
203 | usage(); | |
204 | else | |
205 | break; | |
206 | } | |
207 | ||
208 | switch (argc - i) { | |
209 | case 0: | |
210 | zname = ""; | |
211 | znamelen = 0; | |
212 | break; | |
213 | ||
214 | case 1: | |
215 | zname = argv[i]; | |
216 | znamelen = strlen(zname); | |
217 | break; | |
218 | ||
219 | default: | |
220 | usage(); | |
221 | } | |
222 | ||
8459d725 A |
223 | if (ShowDeltas) { |
224 | SortZones = FALSE; | |
225 | ColFormat = TRUE; | |
226 | PrintHeader = TRUE; | |
227 | } | |
228 | ||
229 | if (ShowPid) { | |
230 | kr = task_for_pid(mach_task_self(), pid, &task); | |
231 | if (kr != KERN_SUCCESS) { | |
cf37c299 | 232 | fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n", |
8459d725 A |
233 | program, pid, mach_error_string(kr)); |
234 | exit(1); | |
235 | } | |
236 | } | |
237 | ||
238 | for (;;) { | |
239 | if (ShowPid) { | |
240 | kr = task_zone_info(task, &name, &nameCnt, &info, &infoCnt); | |
241 | if (kr != KERN_SUCCESS) { | |
242 | fprintf(stderr, "%s: task_zone_info: %s\n", | |
243 | program, mach_error_string(kr)); | |
1815bff5 | 244 | exit(1); |
8459d725 A |
245 | } |
246 | } else { | |
247 | mach_zone_info_t *zinfo = NULL; | |
248 | ||
9726c137 A |
249 | kr = mach_memory_info(mach_host_self(), |
250 | &name, &nameCnt, &zinfo, &infoCnt, | |
251 | &wiredInfo, &wiredInfoCnt); | |
8459d725 A |
252 | if (kr != KERN_SUCCESS) { |
253 | fprintf(stderr, "%s: mach_zone_info: %s\n", | |
254 | program, mach_error_string(kr)); | |
255 | exit(1); | |
256 | } | |
9726c137 | 257 | |
8459d725 A |
258 | kr = vm_allocate(mach_task_self(), (vm_address_t *)&info, |
259 | infoCnt * sizeof *info, VM_FLAGS_ANYWHERE); | |
260 | if (kr != KERN_SUCCESS) { | |
261 | fprintf(stderr, "%s vm_allocate: %s\n", | |
262 | program, mach_error_string(kr)); | |
263 | exit(1); | |
264 | } | |
265 | for (i = 0; i < infoCnt; i++) { | |
266 | *(mach_zone_info_t *)(info + i) = zinfo[i]; | |
267 | info[i].tzi_caller_acct = 0; | |
268 | info[i].tzi_task_alloc = 0; | |
269 | info[i].tzi_task_free = 0; | |
270 | } | |
271 | kr = vm_deallocate(mach_task_self(), (vm_address_t) zinfo, | |
272 | (vm_size_t) (infoCnt * sizeof *zinfo)); | |
273 | if (kr != KERN_SUCCESS) { | |
274 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
275 | program, mach_error_string(kr)); | |
276 | exit(1); | |
277 | } | |
1815bff5 | 278 | } |
8459d725 A |
279 | |
280 | if (nameCnt != infoCnt) { | |
281 | fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n", | |
1815bff5 A |
282 | program); |
283 | exit(1); | |
284 | } | |
285 | ||
8459d725 A |
286 | if (first_time) { |
287 | deltas = (char *)malloc(infoCnt); | |
288 | max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info)); | |
289 | } | |
290 | ||
1815bff5 A |
291 | if (SortZones) { |
292 | for (i = 0; i < nameCnt-1; i++) | |
293 | for (j = i+1; j < nameCnt; j++) { | |
9726c137 | 294 | unsigned long long wastei, wastej; |
1815bff5 | 295 | |
8459d725 A |
296 | wastei = (info[i].tzi_cur_size - |
297 | (info[i].tzi_elem_size * | |
298 | info[i].tzi_count)); | |
299 | wastej = (info[j].tzi_cur_size - | |
300 | (info[j].tzi_elem_size * | |
301 | info[j].tzi_count)); | |
1815bff5 A |
302 | |
303 | if (wastej > wastei) { | |
8459d725 A |
304 | task_zone_info_t tinfo; |
305 | mach_zone_name_t tname; | |
1815bff5 A |
306 | |
307 | tinfo = info[i]; | |
308 | info[i] = info[j]; | |
309 | info[j] = tinfo; | |
310 | ||
311 | tname = name[i]; | |
312 | name[i] = name[j]; | |
313 | name[j] = tname; | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
8459d725 A |
318 | must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time); |
319 | if (must_print) { | |
320 | if (ColFormat) { | |
321 | if (!first_time) | |
322 | printf("\n"); | |
323 | colprintzoneheader(); | |
324 | } | |
325 | for (i = 0; i < nameCnt; i++) { | |
326 | if (deltas[i]) { | |
327 | if (ColFormat) | |
328 | colprintzone(&name[i], &info[i]); | |
329 | else | |
330 | printzone(&name[i], &info[i]); | |
331 | } | |
332 | } | |
cf37c299 | 333 | } |
9726c137 | 334 | |
cf37c299 A |
335 | if (ShowLarge && first_time) { |
336 | PrintLarge(wiredInfo, wiredInfoCnt, | |
337 | SortZones ? &SortSize : &SortName, ColFormat); | |
1815bff5 | 338 | } |
8459d725 A |
339 | |
340 | first_time = 0; | |
341 | ||
342 | if ((name != NULL) && (nameCnt != 0)) { | |
1815bff5 A |
343 | kr = vm_deallocate(mach_task_self(), (vm_address_t) name, |
344 | (vm_size_t) (nameCnt * sizeof *name)); | |
345 | if (kr != KERN_SUCCESS) { | |
346 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
347 | program, mach_error_string(kr)); | |
348 | exit(1); | |
349 | } | |
350 | } | |
351 | ||
8459d725 | 352 | if ((info != NULL) && (infoCnt != 0)) { |
1815bff5 A |
353 | kr = vm_deallocate(mach_task_self(), (vm_address_t) info, |
354 | (vm_size_t) (infoCnt * sizeof *info)); | |
355 | if (kr != KERN_SUCCESS) { | |
356 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
357 | program, mach_error_string(kr)); | |
358 | exit(1); | |
359 | } | |
360 | } | |
361 | ||
9726c137 A |
362 | if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) { |
363 | kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo, | |
364 | (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo)); | |
365 | if (kr != KERN_SUCCESS) { | |
366 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
367 | program, mach_error_string(kr)); | |
368 | exit(1); | |
369 | } | |
370 | } | |
371 | ||
8459d725 A |
372 | if ((ShowWasted||ShowTotal) && PrintHeader && !ShowDeltas) { |
373 | printf("TOTAL SIZE = %llu\n", totalsize); | |
374 | printf("TOTAL USED = %llu\n", totalused); | |
375 | if (ShowWasted) | |
376 | printf("TOTAL WASTED = %llu\n", totalsize - totalused); | |
377 | if (ShowTotal) | |
378 | printf("TOTAL ALLOCS = %llu\n", totalsum); | |
1815bff5 A |
379 | } |
380 | ||
8459d725 A |
381 | if (ShowDeltas == FALSE || last_time) |
382 | break; | |
1815bff5 | 383 | |
8459d725 A |
384 | sleep(interval); |
385 | } | |
386 | exit(0); | |
1815bff5 A |
387 | } |
388 | ||
389 | static boolean_t | |
9726c137 | 390 | substr(const char *a, size_t alen, const char *b, size_t blen) |
1815bff5 A |
391 | { |
392 | int i; | |
393 | ||
cf37c299 A |
394 | if (alen > blen) return FALSE; |
395 | ||
1815bff5 A |
396 | for (i = 0; i <= blen - alen; i++) |
397 | if (strneql(a, b+i, alen)) | |
398 | return TRUE; | |
399 | ||
400 | return FALSE; | |
401 | } | |
402 | ||
403 | static void | |
8459d725 | 404 | printzone(mach_zone_name_t *name, task_zone_info_t *info) |
1815bff5 | 405 | { |
8459d725 A |
406 | unsigned long long used, size; |
407 | ||
408 | printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name); | |
409 | printf("\tcur_size: %lluK bytes (%llu elements)\n", | |
410 | info->tzi_cur_size/1024, | |
411 | (info->tzi_elem_size == 0) ? 0 : | |
412 | info->tzi_cur_size/info->tzi_elem_size); | |
413 | printf("\tmax_size: %lluK bytes (%llu elements)\n", | |
414 | info->tzi_max_size/1024, | |
415 | (info->tzi_elem_size == 0) ? 0 : | |
416 | info->tzi_max_size/info->tzi_elem_size); | |
417 | printf("\telem_size: %llu bytes\n", | |
418 | info->tzi_elem_size); | |
419 | printf("\t# of elems: %llu\n", | |
420 | info->tzi_count); | |
421 | printf("\talloc_size: %lluK bytes (%llu elements)\n", | |
422 | info->tzi_alloc_size/1024, | |
423 | (info->tzi_elem_size == 0) ? 0 : | |
424 | info->tzi_alloc_size/info->tzi_elem_size); | |
425 | if (info->tzi_exhaustible) | |
426 | printf("\tEXHAUSTIBLE\n"); | |
427 | if (info->tzi_collectable) | |
1815bff5 | 428 | printf("\tCOLLECTABLE\n"); |
8459d725 A |
429 | if (ShowPid && info->tzi_caller_acct) |
430 | printf("\tCALLER ACCOUNTED\n"); | |
431 | if (ShowPid) { | |
432 | pidsum += info->tzi_task_alloc - info->tzi_task_free; | |
433 | printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n", | |
434 | (int)((info->tzi_task_alloc - info->tzi_task_free)/1024), | |
435 | (info->tzi_elem_size == 0) ? 0 : | |
436 | (info->tzi_task_alloc - info->tzi_task_free)/info->tzi_elem_size); | |
437 | } | |
1815bff5 | 438 | if (ShowWasted) { |
8459d725 A |
439 | totalused += used = info->tzi_elem_size * info->tzi_count; |
440 | totalsize += size = info->tzi_cur_size; | |
441 | printf("\t\t\t\t\tWASTED: %llu\n", size - used); | |
442 | } | |
443 | if (ShowTotal) { | |
444 | totalsum += info->tzi_sum_size; | |
445 | printf("\t\t\t\t\tTOTAL: %llu\n", totalsum); | |
446 | if (ShowPid) | |
447 | printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum); | |
1815bff5 A |
448 | } |
449 | } | |
450 | ||
1815bff5 | 451 | static void |
8459d725 | 452 | colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info) |
1815bff5 | 453 | { |
8459d725 | 454 | char *name = zone_name->mzn_name; |
34d340d7 | 455 | int j, namewidth; |
8459d725 | 456 | unsigned long long used, size; |
1815bff5 A |
457 | |
458 | namewidth = 25; | |
8459d725 | 459 | if (ShowWasted || ShowTotal) { |
1815bff5 A |
460 | namewidth -= 7; |
461 | } | |
462 | for (j = 0; j < namewidth - 1 && name[j]; j++) { | |
463 | if (name[j] == ' ') { | |
464 | putchar('.'); | |
465 | } else { | |
466 | putchar(name[j]); | |
467 | } | |
468 | } | |
469 | if (j == namewidth - 1) { | |
470 | if (name[j]) { | |
471 | putchar('$'); | |
472 | } else { | |
473 | putchar(' '); | |
474 | } | |
475 | } else { | |
476 | for (; j < namewidth; j++) { | |
477 | putchar(' '); | |
478 | } | |
479 | } | |
aaff5f01 A |
480 | printf(" %6llu", info->tzi_elem_size); |
481 | PRINTK(" %10llu", info->tzi_cur_size); | |
8459d725 | 482 | if (info->tzi_max_size / 1024 > 9999999) { |
aaff5f01 | 483 | printf(" --------"); |
1815bff5 | 484 | } else { |
aaff5f01 | 485 | PRINTK(" %10llu", info->tzi_max_size); |
1815bff5 | 486 | } |
aaff5f01 | 487 | printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size); |
8459d725 | 488 | if (info->tzi_max_size / 1024 >= 999999999) { |
aaff5f01 | 489 | printf(" ----------"); |
1815bff5 | 490 | } else { |
aaff5f01 | 491 | printf(" %11llu", info->tzi_max_size / info->tzi_elem_size); |
1815bff5 | 492 | } |
aaff5f01 A |
493 | printf(" %11llu", info->tzi_count); |
494 | PRINTK(" %5llu", info->tzi_alloc_size); | |
495 | printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size); | |
8459d725 A |
496 | |
497 | totalused += used = info->tzi_elem_size * info->tzi_count; | |
498 | totalsize += size = info->tzi_cur_size; | |
499 | totalsum += info->tzi_sum_size; | |
500 | ||
501 | printf(" %c%c%c", | |
502 | (info->tzi_exhaustible ? 'X' : ' '), | |
503 | (info->tzi_caller_acct ? 'A' : ' '), | |
504 | (info->tzi_collectable ? 'C' : ' ')); | |
1815bff5 | 505 | if (ShowWasted) { |
aaff5f01 | 506 | PRINTK(" %8llu", size - used); |
1815bff5 | 507 | } |
8459d725 A |
508 | if (ShowPid) { |
509 | printf("%8dK", (int)((info->tzi_task_alloc - info->tzi_task_free)/1024)); | |
510 | } | |
511 | if (ShowTotal) { | |
512 | if (info->tzi_sum_size < 1024) | |
aaff5f01 | 513 | printf(" %16lluB", info->tzi_sum_size); |
8459d725 | 514 | else |
aaff5f01 | 515 | PRINTK(" %16llu", info->tzi_sum_size); |
8459d725 A |
516 | } |
517 | printf("\n"); | |
1815bff5 A |
518 | } |
519 | ||
520 | static void | |
8459d725 | 521 | colprintzoneheader(void) |
1815bff5 A |
522 | { |
523 | if (! PrintHeader) { | |
524 | return; | |
525 | } | |
aaff5f01 A |
526 | printf("%s elem cur max cur max" |
527 | " cur alloc alloc %s%s\n", | |
528 | (ShowWasted||ShowTotal)? "" : " ", | |
529 | (ShowWasted)? " ":"", | |
530 | (ShowPid) ? " PID" : "" ); | |
531 | printf("zone name%s size size size #elts #elts" | |
532 | " inuse size count ", (ShowWasted||ShowTotal)? " " : " " ); | |
8459d725 | 533 | if (ShowWasted) |
aaff5f01 | 534 | printf(" wasted"); |
8459d725 | 535 | if (ShowPid) |
aaff5f01 | 536 | printf(" Allocs"); |
8459d725 | 537 | if (ShowTotal) |
aaff5f01 A |
538 | printf(" Total Allocs"); |
539 | printf("\n%s-------------------------------------------------------" | |
540 | "-----------------------------------------------", | |
8459d725 A |
541 | (ShowWasted||ShowTotal)? "" : "-------"); |
542 | if (ShowWasted) | |
8459d725 | 543 | printf("----------"); |
aaff5f01 A |
544 | if (ShowPid) |
545 | printf("---------"); | |
8459d725 | 546 | if (ShowTotal) |
aaff5f01 | 547 | printf("------------------"); |
8459d725 A |
548 | printf("\n"); |
549 | } | |
550 | ||
551 | int | |
552 | find_deltas(mach_zone_name_t *name, task_zone_info_t *info, task_zone_info_t *max_info, | |
553 | char *deltas, int cnt, int first_time) | |
554 | { | |
555 | int i; | |
556 | int found_one = 0; | |
557 | ||
558 | for (i = 0; i < cnt; i++) { | |
559 | deltas[i] = 0; | |
560 | if (substr(zname, znamelen, name[i].mzn_name, | |
561 | strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) { | |
562 | if (first_time || info->tzi_cur_size > max_info->tzi_cur_size || | |
563 | (ShowTotal && ((info->tzi_sum_size >> 1) > max_info->tzi_sum_size))) { | |
564 | max_info->tzi_cur_size = info->tzi_cur_size; | |
565 | max_info->tzi_sum_size = info->tzi_sum_size; | |
566 | deltas[i] = 1; | |
567 | found_one = 1; | |
568 | } | |
569 | } | |
570 | info++; | |
571 | max_info++; | |
572 | } | |
573 | return(found_one); | |
1815bff5 | 574 | } |
9726c137 A |
575 | |
576 | /********************************************************************* | |
577 | *********************************************************************/ | |
578 | ||
579 | static char * | |
580 | kern_vm_tag_name(uint64_t tag) | |
581 | { | |
582 | char * result; | |
583 | const char * name; | |
584 | switch (tag) | |
585 | { | |
586 | case (VM_KERN_MEMORY_NONE): name = "VM_KERN_MEMORY_NONE"; break; | |
587 | case (VM_KERN_MEMORY_OSFMK): name = "VM_KERN_MEMORY_OSFMK"; break; | |
588 | case (VM_KERN_MEMORY_BSD): name = "VM_KERN_MEMORY_BSD"; break; | |
589 | case (VM_KERN_MEMORY_IOKIT): name = "VM_KERN_MEMORY_IOKIT"; break; | |
590 | case (VM_KERN_MEMORY_LIBKERN): name = "VM_KERN_MEMORY_LIBKERN"; break; | |
591 | case (VM_KERN_MEMORY_OSKEXT): name = "VM_KERN_MEMORY_OSKEXT"; break; | |
592 | case (VM_KERN_MEMORY_KEXT): name = "VM_KERN_MEMORY_KEXT"; break; | |
593 | case (VM_KERN_MEMORY_IPC): name = "VM_KERN_MEMORY_IPC"; break; | |
594 | case (VM_KERN_MEMORY_STACK): name = "VM_KERN_MEMORY_STACK"; break; | |
595 | case (VM_KERN_MEMORY_CPU): name = "VM_KERN_MEMORY_CPU"; break; | |
596 | case (VM_KERN_MEMORY_PMAP): name = "VM_KERN_MEMORY_PMAP"; break; | |
597 | case (VM_KERN_MEMORY_PTE): name = "VM_KERN_MEMORY_PTE"; break; | |
598 | case (VM_KERN_MEMORY_ZONE): name = "VM_KERN_MEMORY_ZONE"; break; | |
599 | case (VM_KERN_MEMORY_KALLOC): name = "VM_KERN_MEMORY_KALLOC"; break; | |
600 | case (VM_KERN_MEMORY_COMPRESSOR): name = "VM_KERN_MEMORY_COMPRESSOR"; break; | |
601 | case (VM_KERN_MEMORY_COMPRESSED_DATA): name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break; | |
602 | case (VM_KERN_MEMORY_PHANTOM_CACHE): name = "VM_KERN_MEMORY_PHANTOM_CACHE"; break; | |
603 | case (VM_KERN_MEMORY_WAITQ): name = "VM_KERN_MEMORY_WAITQ"; break; | |
604 | case (VM_KERN_MEMORY_DIAG): name = "VM_KERN_MEMORY_DIAG"; break; | |
605 | case (VM_KERN_MEMORY_LOG): name = "VM_KERN_MEMORY_LOG"; break; | |
606 | case (VM_KERN_MEMORY_FILE): name = "VM_KERN_MEMORY_FILE"; break; | |
607 | case (VM_KERN_MEMORY_MBUF): name = "VM_KERN_MEMORY_MBUF"; break; | |
608 | case (VM_KERN_MEMORY_UBC): name = "VM_KERN_MEMORY_UBC"; break; | |
609 | case (VM_KERN_MEMORY_SECURITY): name = "VM_KERN_MEMORY_SECURITY"; break; | |
610 | case (VM_KERN_MEMORY_MLOCK): name = "VM_KERN_MEMORY_MLOCK"; break; | |
cf37c299 A |
611 | case (VM_KERN_MEMORY_REASON): name = "VM_KERN_MEMORY_REASON"; break; |
612 | case (VM_KERN_MEMORY_SKYWALK): name = "VM_KERN_MEMORY_SKYWALK"; break; | |
613 | case (VM_KERN_MEMORY_LTABLE): name = "VM_KERN_MEMORY_LTABLE"; break; | |
9726c137 A |
614 | case (VM_KERN_MEMORY_ANY): name = "VM_KERN_MEMORY_ANY"; break; |
615 | default: name = NULL; break; | |
616 | } | |
617 | if (name) asprintf(&result, "%s", name); | |
618 | else asprintf(&result, "VM_KERN_MEMORY_%lld", tag); | |
619 | return (result); | |
620 | } | |
621 | ||
cf37c299 | 622 | static char * |
9726c137 A |
623 | kern_vm_counter_name(uint64_t tag) |
624 | { | |
625 | char * result; | |
626 | const char * name; | |
627 | switch (tag) | |
628 | { | |
629 | case (VM_KERN_COUNT_MANAGED): name = "VM_KERN_COUNT_MANAGED"; break; | |
630 | case (VM_KERN_COUNT_RESERVED): name = "VM_KERN_COUNT_RESERVED"; break; | |
631 | case (VM_KERN_COUNT_WIRED): name = "VM_KERN_COUNT_WIRED"; break; | |
632 | case (VM_KERN_COUNT_WIRED_MANAGED): name = "VM_KERN_COUNT_WIRED_MANAGED"; break; | |
633 | case (VM_KERN_COUNT_STOLEN): name = "VM_KERN_COUNT_STOLEN"; break; | |
634 | case (VM_KERN_COUNT_LOPAGE): name = "VM_KERN_COUNT_LOPAGE"; break; | |
635 | case (VM_KERN_COUNT_MAP_KERNEL): name = "VM_KERN_COUNT_MAP_KERNEL"; break; | |
636 | case (VM_KERN_COUNT_MAP_ZONE): name = "VM_KERN_COUNT_MAP_ZONE"; break; | |
637 | case (VM_KERN_COUNT_MAP_KALLOC): name = "VM_KERN_COUNT_MAP_KALLOC"; break; | |
638 | default: name = NULL; break; | |
639 | } | |
640 | if (name) asprintf(&result, "%s", name); | |
641 | else asprintf(&result, "VM_KERN_COUNT_%lld", tag); | |
642 | return (result); | |
643 | } | |
644 | ||
645 | static void | |
646 | MakeLoadTagKeys(const void * key, const void * value, void * context) | |
647 | { | |
648 | CFMutableDictionaryRef newDict = context; | |
649 | CFDictionaryRef kextInfo = value; | |
650 | CFNumberRef loadTag; | |
651 | uint32_t loadTagValue; | |
652 | ||
653 | loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey)); | |
654 | CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue); | |
655 | key = (const void *)(uintptr_t) loadTagValue; | |
656 | CFDictionarySetValue(newDict, key, value); | |
657 | } | |
658 | ||
cf37c299 | 659 | static CSSymbolicatorRef gSym; |
9726c137 A |
660 | static CFMutableDictionaryRef gTagDict; |
661 | static mach_memory_info_t * gSites; | |
662 | ||
cf37c299 | 663 | static char * |
9726c137 A |
664 | GetSiteName(int siteIdx) |
665 | { | |
666 | const char * name; | |
667 | char * result; | |
668 | mach_vm_address_t addr; | |
669 | CFDictionaryRef kextInfo; | |
670 | CFStringRef bundleID; | |
671 | uint32_t type; | |
672 | ||
673 | const mach_memory_info_t * site; | |
674 | const char * fileName; | |
675 | CSSymbolRef symbol; | |
676 | const char * symbolName; | |
677 | CSSourceInfoRef sourceInfo; | |
678 | ||
679 | name = NULL; | |
680 | result = NULL; | |
681 | site = &gSites[siteIdx]; | |
682 | addr = site->site; | |
683 | type = (VM_KERN_SITE_TYPE & site->flags); | |
684 | switch (type) | |
685 | { | |
686 | case VM_KERN_SITE_TAG: | |
687 | result = kern_vm_tag_name(addr); | |
688 | break; | |
689 | ||
690 | case VM_KERN_SITE_COUNTER: | |
691 | result = kern_vm_counter_name(addr); | |
692 | break; | |
693 | ||
694 | case VM_KERN_SITE_KMOD: | |
695 | kextInfo = CFDictionaryGetValue(gTagDict, (const void *)(uintptr_t) addr); | |
cf37c299 | 696 | if (kextInfo) |
9726c137 A |
697 | { |
698 | bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey); | |
699 | name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8); | |
700 | // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey)); | |
701 | } | |
702 | asprintf(&result, "%-64s%3lld", name ? name : "(unknown kmod)", addr); | |
703 | break; | |
704 | ||
705 | case VM_KERN_SITE_KERNEL: | |
706 | symbolName = NULL; | |
707 | if (addr) | |
708 | { | |
709 | symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow); | |
710 | symbolName = CSSymbolGetName(symbol); | |
711 | } | |
712 | if (symbolName) | |
713 | { | |
714 | asprintf(&result, "%s", symbolName); | |
715 | sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow); | |
716 | fileName = CSSourceInfoGetPath(sourceInfo); | |
717 | if (fileName) printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo)); | |
718 | } | |
719 | else | |
720 | { | |
721 | asprintf(&result, "site 0x%qx", addr); | |
722 | } | |
723 | break; | |
724 | default: | |
725 | asprintf(&result, ""); | |
726 | break; | |
727 | } | |
728 | ||
729 | return (result); | |
730 | } | |
731 | ||
cf37c299 | 732 | static int |
9726c137 A |
733 | SortName(const void * left, const void * right) |
734 | { | |
735 | const int * idxL; | |
736 | const int * idxR; | |
737 | char * l; | |
738 | char * r; | |
739 | int result; | |
740 | ||
741 | idxL = (typeof(idxL)) left; | |
742 | idxR = (typeof(idxR)) right; | |
743 | l = GetSiteName(*idxL); | |
744 | r = GetSiteName(*idxR); | |
745 | ||
746 | result = strcmp(l, r); | |
747 | free(l); | |
748 | free(r); | |
749 | ||
750 | return (result); | |
751 | } | |
752 | ||
cf37c299 | 753 | static int |
9726c137 A |
754 | SortSize(const void * left, const void * right) |
755 | { | |
756 | const mach_memory_info_t * siteL; | |
757 | const mach_memory_info_t * siteR; | |
758 | const int * idxL; | |
759 | const int * idxR; | |
760 | ||
761 | idxL = (typeof(idxL)) left; | |
762 | idxR = (typeof(idxR)) right; | |
763 | siteL = &gSites[*idxL]; | |
764 | siteR = &gSites[*idxR]; | |
765 | ||
766 | if (siteL->size > siteR->size) return (-1); | |
767 | else if (siteL->size < siteR->size) return (1); | |
768 | return (0); | |
769 | } | |
770 | ||
771 | ||
772 | static void | |
773 | PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, | |
774 | int (*func)(const void *, const void *), boolean_t column) | |
775 | { | |
776 | uint64_t zonetotal; | |
777 | uint64_t top_wired; | |
778 | ||
779 | CFDictionaryRef allKexts; | |
780 | unsigned int idx, site, first; | |
781 | int sorted[wiredInfoCnt]; | |
782 | char totalstr[40]; | |
783 | char * name; | |
cf37c299 | 784 | bool headerPrinted; |
9726c137 A |
785 | |
786 | zonetotal = totalsize; | |
787 | ||
788 | gSites = wiredInfo; | |
789 | ||
790 | gSym = CSSymbolicatorCreateWithMachKernel(); | |
cf37c299 | 791 | |
9726c137 | 792 | allKexts = OSKextCopyLoadedKextInfo(NULL, NULL); |
cf37c299 | 793 | gTagDict = CFDictionaryCreateMutable( |
9726c137 A |
794 | kCFAllocatorDefault, (CFIndex) 0, |
795 | (CFDictionaryKeyCallBacks *) 0, | |
796 | &kCFTypeDictionaryValueCallBacks); | |
797 | ||
798 | CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict); | |
799 | CFRelease(allKexts); | |
800 | ||
801 | top_wired = 0; | |
802 | ||
803 | for (idx = 0; idx < wiredInfoCnt; idx++) sorted[idx] = idx; | |
804 | first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC | |
805 | qsort(&sorted[first], | |
cf37c299 A |
806 | wiredInfoCnt - first, |
807 | sizeof(sorted[0]), | |
9726c137 A |
808 | func); |
809 | ||
cf37c299 | 810 | for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) |
9726c137 A |
811 | { |
812 | site = sorted[idx]; | |
813 | if (!gSites[site].size) continue; | |
814 | if (VM_KERN_COUNT_WIRED == gSites[site].site) top_wired = gSites[site].size; | |
815 | if (VM_KERN_SITE_HIDE & gSites[site].flags) continue; | |
816 | if (!(VM_KERN_SITE_WIRED & gSites[site].flags)) continue; | |
817 | ||
818 | name = GetSiteName(site); | |
cf37c299 A |
819 | if (!substr(zname, znamelen, name, strlen(name))) continue; |
820 | if (!headerPrinted) | |
821 | { | |
822 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
823 | printf(" kmod vm cur\n"); | |
824 | printf("wired memory id tag size\n"); | |
825 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
826 | headerPrinted = true; | |
827 | } | |
9726c137 A |
828 | printf("%-67s", name); |
829 | free(name); | |
830 | printf("%12d", site); | |
831 | ||
832 | printf(" %11s", ""); | |
833 | PRINTK(" %12llu", gSites[site].size); | |
834 | totalsize += gSites[site].size; | |
835 | ||
836 | printf("\n"); | |
837 | } | |
838 | ||
cf37c299 A |
839 | if (!znamelen) |
840 | { | |
841 | printf("%-67s", "zones"); | |
842 | printf("%12s", ""); | |
843 | printf(" %11s", ""); | |
844 | PRINTK(" %12llu", zonetotal); | |
845 | printf("\n"); | |
846 | } | |
847 | if (headerPrinted) | |
848 | { | |
849 | snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0); | |
850 | printf("total%100s\n", totalstr); | |
851 | } | |
852 | for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) | |
9726c137 A |
853 | { |
854 | site = sorted[idx]; | |
855 | if (!gSites[site].size) continue; | |
856 | if (VM_KERN_SITE_HIDE & gSites[site].flags) continue; | |
857 | if (VM_KERN_SITE_WIRED & gSites[site].flags) continue; | |
858 | ||
859 | name = GetSiteName(site); | |
cf37c299 A |
860 | if (!substr(zname, znamelen, name, strlen(name))) continue; |
861 | if (!headerPrinted) | |
862 | { | |
863 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
864 | printf(" largest\n"); | |
865 | printf("maps free free size\n"); | |
866 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
867 | headerPrinted = true; | |
868 | } | |
9726c137 A |
869 | printf("%-67s", name); |
870 | free(name); | |
871 | ||
872 | PRINTK(" %10llu", gSites[site].free); | |
873 | PRINTK(" %10llu", gSites[site].largest); | |
874 | PRINTK(" %12llu", gSites[site].size); | |
875 | ||
876 | printf("\n"); | |
877 | } | |
878 | } |