]>
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 | ||
c0bbac3a A |
88 | #ifndef VM_KERN_SITE_ZONE_VIEW |
89 | #define VM_KERN_SITE_ZONE_VIEW 0x00001000 | |
90 | #endif | |
91 | ||
92 | #define streql(a, b) (strcmp((a), (b)) == 0) | |
93 | #define strneql(a, b, n) (strncmp((a), (b), (n)) == 0) | |
94 | #define PRINTK(fmt, value) \ | |
95 | printf(fmt "K", (value) / 1024 ) /* ick */ | |
1815bff5 | 96 | |
639dadd6 A |
97 | static void usage(FILE *stream); |
98 | static void printzone(mach_zone_name_t *, mach_zone_info_t *); | |
99 | static void colprintzone(mach_zone_name_t *, mach_zone_info_t *); | |
100 | static int find_deltas(mach_zone_name_t *, mach_zone_info_t *, mach_zone_info_t *, char *, int, int); | |
8459d725 | 101 | static void colprintzoneheader(void); |
9726c137 A |
102 | static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen); |
103 | ||
887d5eed A |
104 | static int SortName(void * thunk, const void * left, const void * right); |
105 | static int SortSize(void * thunk, const void * left, const void * right); | |
106 | static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, | |
c0bbac3a A |
107 | mach_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames, |
108 | unsigned int zoneCnt, uint64_t zoneElements, | |
109 | int (*func)(void *, const void *, const void *), boolean_t column); | |
1815bff5 A |
110 | |
111 | static char *program; | |
112 | ||
8459d725 | 113 | static boolean_t ShowDeltas = FALSE; |
1815bff5 | 114 | static boolean_t ShowWasted = FALSE; |
8459d725 | 115 | static boolean_t ShowTotal = FALSE; |
9726c137 | 116 | static boolean_t ShowLarge = TRUE; |
1815bff5 A |
117 | static boolean_t SortZones = FALSE; |
118 | static boolean_t ColFormat = TRUE; | |
119 | static boolean_t PrintHeader = TRUE; | |
120 | ||
8459d725 A |
121 | static unsigned long long totalsize = 0; |
122 | static unsigned long long totalused = 0; | |
123 | static unsigned long long totalsum = 0; | |
639dadd6 A |
124 | static unsigned long long totalfragmented = 0; |
125 | static unsigned long long totalcollectable = 0; | |
8459d725 A |
126 | |
127 | static int last_time = 0; | |
128 | ||
c0bbac3a A |
129 | static char *zname = NULL; |
130 | static size_t znamelen = 0; | |
8459d725 | 131 | |
639dadd6 A |
132 | #define LEFTALIGN -1 |
133 | #define RIGHTALIGN 1 | |
134 | ||
135 | typedef struct { | |
136 | char *line1; | |
137 | char *line2; | |
138 | int colwidth; | |
139 | int alignment; | |
140 | bool visible; | |
141 | } column_format; | |
142 | ||
143 | enum { | |
144 | COL_ZONE_NAME, | |
145 | COL_ELEM_SIZE, | |
146 | COL_CUR_SIZE, | |
147 | COL_MAX_SIZE, | |
148 | COL_CUR_ELTS, | |
149 | COL_MAX_ELTS, | |
150 | COL_CUR_INUSE, | |
151 | COL_ALLOC_SIZE, | |
152 | COL_ALLOC_COUNT, | |
153 | COL_ZONE_FLAGS, | |
154 | COL_FRAG_SIZE, | |
155 | COL_FREE_SIZE, | |
156 | COL_TOTAL_ALLOCS, | |
157 | COL_MAX | |
158 | }; | |
159 | ||
160 | /* | |
161 | * The order in which the columns appear below should match | |
162 | * the order in which the values are printed in colprintzone(). | |
163 | */ | |
164 | static column_format columns[] = { | |
c0bbac3a A |
165 | [COL_ZONE_NAME] = { "", "zone name", 25, LEFTALIGN, true }, |
166 | [COL_ELEM_SIZE] = { "elem", "size", 6, RIGHTALIGN, true }, | |
167 | [COL_CUR_SIZE] = { "cur", "size", 11, RIGHTALIGN, true }, | |
168 | [COL_MAX_SIZE] = { "max", "size", 11, RIGHTALIGN, true }, | |
169 | [COL_CUR_ELTS] = { "cur", "#elts", 10, RIGHTALIGN, true }, | |
170 | [COL_MAX_ELTS] = { "max", "#elts", 11, RIGHTALIGN, true }, | |
171 | [COL_CUR_INUSE] = { "cur", "inuse", 11, RIGHTALIGN, true }, | |
172 | [COL_ALLOC_SIZE] = { "alloc", "size", 6, RIGHTALIGN, true }, | |
173 | [COL_ALLOC_COUNT] = { "alloc", "count", 6, RIGHTALIGN, true }, | |
174 | [COL_ZONE_FLAGS] = { "", "", 2, RIGHTALIGN, true }, | |
175 | /* additional columns for special flags, not visible by default */ | |
176 | [COL_FRAG_SIZE] = { "frag", "size", 9, RIGHTALIGN, false }, | |
177 | [COL_FREE_SIZE] = { "free", "size", 9, RIGHTALIGN, false }, | |
178 | [COL_TOTAL_ALLOCS] = { "total", "allocs", 17, RIGHTALIGN, false } | |
639dadd6 A |
179 | }; |
180 | ||
8459d725 A |
181 | static void |
182 | sigintr(__unused int signum) | |
183 | { | |
184 | last_time = 1; | |
185 | } | |
1815bff5 A |
186 | |
187 | static void | |
639dadd6 | 188 | usage(FILE *stream) |
1815bff5 | 189 | { |
639dadd6 A |
190 | fprintf(stream, "usage: %s [-w] [-s] [-c] [-h] [-H] [-t] [-d] [-l] [-L] [name]\n\n", program); |
191 | fprintf(stream, "\t-w\tshow wasted memory for each zone\n"); | |
192 | fprintf(stream, "\t-s\tsort zones by wasted memory\n"); | |
193 | fprintf(stream, "\t-c\t(default) display output formatted in columns\n"); | |
194 | fprintf(stream, "\t-h\tdisplay this help message\n"); | |
195 | fprintf(stream, "\t-H\thide column names\n"); | |
196 | fprintf(stream, "\t-t\tdisplay the total size of allocations over the life of the zone\n"); | |
197 | fprintf(stream, "\t-d\tdisplay deltas over time\n"); | |
198 | fprintf(stream, "\t-l\t(default) display wired memory info after zone info\n"); | |
199 | fprintf(stream, "\t-L\tdo not show wired memory info, only show zone info\n"); | |
200 | fprintf(stream, "\nAny option (including default options) can be overridden by specifying the option in upper-case.\n\n"); | |
201 | exit(stream != stdout); | |
1815bff5 A |
202 | } |
203 | ||
34d340d7 | 204 | int |
8459d725 | 205 | main(int argc, char **argv) |
1815bff5 | 206 | { |
8459d725 A |
207 | mach_zone_name_t *name = NULL; |
208 | unsigned int nameCnt = 0; | |
639dadd6 | 209 | mach_zone_info_t *info = NULL; |
8459d725 | 210 | unsigned int infoCnt = 0; |
9726c137 A |
211 | mach_memory_info_t *wiredInfo = NULL; |
212 | unsigned int wiredInfoCnt = 0; | |
639dadd6 | 213 | mach_zone_info_t *max_info = NULL; |
c0bbac3a | 214 | char *deltas = NULL; |
887d5eed | 215 | uint64_t zoneElements; |
1815bff5 | 216 | |
c0bbac3a A |
217 | kern_return_t kr; |
218 | int i, j; | |
219 | int first_time = 1; | |
220 | int must_print = 1; | |
221 | int interval = 1; | |
1815bff5 | 222 | |
8459d725 | 223 | signal(SIGINT, sigintr); |
ef8ad44b | 224 | |
1815bff5 | 225 | program = strrchr(argv[0], '/'); |
c0bbac3a | 226 | if (program == NULL) { |
1815bff5 | 227 | program = argv[0]; |
c0bbac3a | 228 | } else { |
1815bff5 | 229 | program++; |
c0bbac3a | 230 | } |
1815bff5 A |
231 | |
232 | for (i = 1; i < argc; i++) { | |
c0bbac3a | 233 | if (streql(argv[i], "-d")) { |
8459d725 | 234 | ShowDeltas = TRUE; |
c0bbac3a | 235 | } else if (streql(argv[i], "-t")) { |
8459d725 | 236 | ShowTotal = TRUE; |
c0bbac3a | 237 | } else if (streql(argv[i], "-T")) { |
8459d725 | 238 | ShowTotal = FALSE; |
c0bbac3a | 239 | } else if (streql(argv[i], "-w")) { |
1815bff5 | 240 | ShowWasted = TRUE; |
c0bbac3a | 241 | } else if (streql(argv[i], "-W")) { |
1815bff5 | 242 | ShowWasted = FALSE; |
c0bbac3a | 243 | } else if (streql(argv[i], "-l")) { |
9726c137 | 244 | ShowLarge = TRUE; |
c0bbac3a | 245 | } else if (streql(argv[i], "-L")) { |
9726c137 | 246 | ShowLarge = FALSE; |
c0bbac3a | 247 | } else if (streql(argv[i], "-s")) { |
1815bff5 | 248 | SortZones = TRUE; |
c0bbac3a | 249 | } else if (streql(argv[i], "-S")) { |
1815bff5 | 250 | SortZones = FALSE; |
c0bbac3a | 251 | } else if (streql(argv[i], "-c")) { |
1815bff5 | 252 | ColFormat = TRUE; |
c0bbac3a | 253 | } else if (streql(argv[i], "-C")) { |
1815bff5 | 254 | ColFormat = FALSE; |
c0bbac3a | 255 | } else if (streql(argv[i], "-h")) { |
639dadd6 | 256 | usage(stdout); |
c0bbac3a | 257 | } else if (streql(argv[i], "-H")) { |
1815bff5 | 258 | PrintHeader = FALSE; |
c0bbac3a | 259 | } else if (streql(argv[i], "--")) { |
1815bff5 A |
260 | i++; |
261 | break; | |
c0bbac3a | 262 | } else if (argv[i][0] == '-') { |
639dadd6 | 263 | usage(stderr); |
c0bbac3a | 264 | } else { |
1815bff5 | 265 | break; |
c0bbac3a | 266 | } |
1815bff5 A |
267 | } |
268 | ||
269 | switch (argc - i) { | |
c0bbac3a | 270 | case 0: |
1815bff5 A |
271 | zname = ""; |
272 | znamelen = 0; | |
273 | break; | |
274 | ||
c0bbac3a | 275 | case 1: |
1815bff5 A |
276 | zname = argv[i]; |
277 | znamelen = strlen(zname); | |
278 | break; | |
279 | ||
c0bbac3a | 280 | default: |
639dadd6 | 281 | usage(stderr); |
1815bff5 A |
282 | } |
283 | ||
8459d725 A |
284 | if (ShowDeltas) { |
285 | SortZones = FALSE; | |
286 | ColFormat = TRUE; | |
287 | PrintHeader = TRUE; | |
288 | } | |
289 | ||
639dadd6 A |
290 | if (ShowWasted) { |
291 | columns[COL_FRAG_SIZE].visible = true; | |
292 | columns[COL_FREE_SIZE].visible = true; | |
293 | } | |
294 | if (ShowTotal) { | |
295 | columns[COL_TOTAL_ALLOCS].visible = true; | |
8459d725 A |
296 | } |
297 | ||
639dadd6 A |
298 | for (;;) { |
299 | kr = mach_memory_info(mach_host_self(), | |
c0bbac3a A |
300 | &name, &nameCnt, &info, &infoCnt, |
301 | &wiredInfo, &wiredInfoCnt); | |
639dadd6 | 302 | if (kr != KERN_SUCCESS) { |
530d02b6 | 303 | fprintf(stderr, "%s: mach_memory_info: %s (try running as root)\n", |
c0bbac3a | 304 | program, mach_error_string(kr)); |
639dadd6 A |
305 | exit(1); |
306 | } | |
8459d725 | 307 | |
639dadd6 A |
308 | if (nameCnt != infoCnt) { |
309 | fprintf(stderr, "%s: mach_zone_name/ mach_zone_info: counts not equal?\n", | |
c0bbac3a | 310 | program); |
639dadd6 A |
311 | exit(1); |
312 | } | |
1815bff5 | 313 | |
639dadd6 A |
314 | if (first_time) { |
315 | deltas = (char *)malloc(infoCnt); | |
316 | max_info = (mach_zone_info_t *)malloc((infoCnt * sizeof *info)); | |
317 | } | |
8459d725 | 318 | |
639dadd6 | 319 | if (SortZones) { |
c0bbac3a A |
320 | for (i = 0; i < nameCnt - 1; i++) { |
321 | for (j = i + 1; j < nameCnt; j++) { | |
639dadd6 A |
322 | unsigned long long wastei, wastej; |
323 | ||
324 | wastei = (info[i].mzi_cur_size - | |
c0bbac3a A |
325 | (info[i].mzi_elem_size * |
326 | info[i].mzi_count)); | |
639dadd6 | 327 | wastej = (info[j].mzi_cur_size - |
c0bbac3a A |
328 | (info[j].mzi_elem_size * |
329 | info[j].mzi_count)); | |
639dadd6 A |
330 | |
331 | if (wastej > wastei) { | |
332 | mach_zone_info_t tinfo; | |
333 | mach_zone_name_t tname; | |
334 | ||
335 | tinfo = info[i]; | |
336 | info[i] = info[j]; | |
337 | info[j] = tinfo; | |
338 | ||
339 | tname = name[i]; | |
340 | name[i] = name[j]; | |
341 | name[j] = tname; | |
342 | } | |
1815bff5 A |
343 | } |
344 | } | |
8459d725 | 345 | } |
639dadd6 A |
346 | |
347 | must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time); | |
348 | zoneElements = 0; | |
349 | if (must_print) { | |
350 | if (ColFormat) { | |
c0bbac3a | 351 | if (!first_time) { |
639dadd6 | 352 | printf("\n"); |
c0bbac3a | 353 | } |
639dadd6 A |
354 | colprintzoneheader(); |
355 | } | |
356 | for (i = 0; i < nameCnt; i++) { | |
357 | if (deltas[i]) { | |
c0bbac3a | 358 | if (ColFormat) { |
639dadd6 | 359 | colprintzone(&name[i], &info[i]); |
c0bbac3a | 360 | } else { |
639dadd6 | 361 | printzone(&name[i], &info[i]); |
c0bbac3a | 362 | } |
639dadd6 A |
363 | zoneElements += info[i].mzi_count; |
364 | } | |
8459d725 A |
365 | } |
366 | } | |
9726c137 | 367 | |
639dadd6 A |
368 | if (ShowLarge && first_time) { |
369 | PrintLarge(wiredInfo, wiredInfoCnt, &info[0], &name[0], | |
c0bbac3a A |
370 | nameCnt, zoneElements, |
371 | SortZones ? &SortSize : &SortName, ColFormat); | |
639dadd6 | 372 | } |
8459d725 | 373 | |
639dadd6 | 374 | first_time = 0; |
8459d725 | 375 | |
639dadd6 A |
376 | if ((name != NULL) && (nameCnt != 0)) { |
377 | kr = vm_deallocate(mach_task_self(), (vm_address_t) name, | |
c0bbac3a | 378 | (vm_size_t) (nameCnt * sizeof *name)); |
639dadd6 A |
379 | if (kr != KERN_SUCCESS) { |
380 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
c0bbac3a | 381 | program, mach_error_string(kr)); |
639dadd6 A |
382 | exit(1); |
383 | } | |
1815bff5 | 384 | } |
1815bff5 | 385 | |
639dadd6 A |
386 | if ((info != NULL) && (infoCnt != 0)) { |
387 | kr = vm_deallocate(mach_task_self(), (vm_address_t) info, | |
c0bbac3a | 388 | (vm_size_t) (infoCnt * sizeof *info)); |
639dadd6 A |
389 | if (kr != KERN_SUCCESS) { |
390 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
c0bbac3a | 391 | program, mach_error_string(kr)); |
639dadd6 A |
392 | exit(1); |
393 | } | |
1815bff5 | 394 | } |
1815bff5 | 395 | |
639dadd6 A |
396 | if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) { |
397 | kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo, | |
c0bbac3a | 398 | (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo)); |
639dadd6 A |
399 | if (kr != KERN_SUCCESS) { |
400 | fprintf(stderr, "%s: vm_deallocate: %s\n", | |
c0bbac3a | 401 | program, mach_error_string(kr)); |
639dadd6 A |
402 | exit(1); |
403 | } | |
9726c137 | 404 | } |
9726c137 | 405 | |
c0bbac3a | 406 | if ((ShowWasted || ShowTotal) && PrintHeader && !ShowDeltas) { |
639dadd6 A |
407 | printf("\nZONE TOTALS\n"); |
408 | printf("---------------------------------------------\n"); | |
409 | printf("TOTAL SIZE = %llu\n", totalsize); | |
410 | printf("TOTAL USED = %llu\n", totalused); | |
411 | if (ShowWasted) { | |
412 | printf("TOTAL WASTED = %llu\n", totalsize - totalused); | |
413 | printf("TOTAL FRAGMENTED = %llu\n", totalfragmented); | |
414 | printf("TOTAL COLLECTABLE = %llu\n", totalcollectable); | |
415 | } | |
c0bbac3a | 416 | if (ShowTotal) { |
639dadd6 | 417 | printf("TOTAL ALLOCS = %llu\n", totalsum); |
c0bbac3a | 418 | } |
639dadd6 | 419 | } |
1815bff5 | 420 | |
c0bbac3a | 421 | if (ShowDeltas == FALSE || last_time) { |
639dadd6 | 422 | break; |
c0bbac3a | 423 | } |
1815bff5 | 424 | |
639dadd6 A |
425 | sleep(interval); |
426 | } | |
c0bbac3a | 427 | exit(0); |
1815bff5 A |
428 | } |
429 | ||
430 | static boolean_t | |
9726c137 | 431 | substr(const char *a, size_t alen, const char *b, size_t blen) |
1815bff5 A |
432 | { |
433 | int i; | |
434 | ||
c0bbac3a A |
435 | if (alen > blen) { |
436 | return FALSE; | |
437 | } | |
cf37c299 | 438 | |
c0bbac3a A |
439 | for (i = 0; i <= blen - alen; i++) { |
440 | if (strneql(a, b + i, alen)) { | |
1815bff5 | 441 | return TRUE; |
c0bbac3a A |
442 | } |
443 | } | |
1815bff5 A |
444 | |
445 | return FALSE; | |
446 | } | |
447 | ||
448 | static void | |
639dadd6 | 449 | printzone(mach_zone_name_t *name, mach_zone_info_t *info) |
1815bff5 | 450 | { |
639dadd6 | 451 | unsigned long long used, size, fragmented, collectable; |
8459d725 A |
452 | |
453 | printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name); | |
454 | printf("\tcur_size: %lluK bytes (%llu elements)\n", | |
c0bbac3a A |
455 | info->mzi_cur_size / 1024, |
456 | (info->mzi_elem_size == 0) ? 0 : | |
457 | info->mzi_cur_size / info->mzi_elem_size); | |
8459d725 | 458 | printf("\tmax_size: %lluK bytes (%llu elements)\n", |
c0bbac3a A |
459 | info->mzi_max_size / 1024, |
460 | (info->mzi_elem_size == 0) ? 0 : | |
461 | info->mzi_max_size / info->mzi_elem_size); | |
8459d725 | 462 | printf("\telem_size: %llu bytes\n", |
c0bbac3a | 463 | info->mzi_elem_size); |
8459d725 | 464 | printf("\t# of elems: %llu\n", |
c0bbac3a | 465 | info->mzi_count); |
8459d725 | 466 | printf("\talloc_size: %lluK bytes (%llu elements)\n", |
c0bbac3a A |
467 | info->mzi_alloc_size / 1024, |
468 | (info->mzi_elem_size == 0) ? 0 : | |
469 | info->mzi_alloc_size / info->mzi_elem_size); | |
470 | if (info->mzi_exhaustible) { | |
8459d725 | 471 | printf("\tEXHAUSTIBLE\n"); |
c0bbac3a A |
472 | } |
473 | if (GET_MZI_COLLECTABLE_FLAG(info->mzi_collectable)) { | |
1815bff5 | 474 | printf("\tCOLLECTABLE\n"); |
c0bbac3a | 475 | } |
1815bff5 | 476 | if (ShowWasted) { |
639dadd6 A |
477 | totalused += used = info->mzi_elem_size * info->mzi_count; |
478 | totalsize += size = info->mzi_cur_size; | |
479 | totalcollectable += collectable = GET_MZI_COLLECTABLE_BYTES(info->mzi_collectable); | |
480 | totalfragmented += fragmented = size - used - collectable; | |
8459d725 | 481 | printf("\t\t\t\t\tWASTED: %llu\n", size - used); |
639dadd6 A |
482 | printf("\t\t\t\t\tFRAGMENTED: %llu\n", fragmented); |
483 | printf("\t\t\t\t\tCOLLECTABLE: %llu\n", collectable); | |
8459d725 A |
484 | } |
485 | if (ShowTotal) { | |
639dadd6 | 486 | totalsum += info->mzi_sum_size; |
8459d725 | 487 | printf("\t\t\t\t\tTOTAL: %llu\n", totalsum); |
1815bff5 A |
488 | } |
489 | } | |
490 | ||
1815bff5 | 491 | static void |
639dadd6 | 492 | colprintzone(mach_zone_name_t *zone_name, mach_zone_info_t *info) |
1815bff5 | 493 | { |
8459d725 | 494 | char *name = zone_name->mzn_name; |
34d340d7 | 495 | int j, namewidth; |
639dadd6 A |
496 | unsigned long long used, size, fragmented, collectable; |
497 | ||
498 | namewidth = columns[COL_ZONE_NAME].colwidth; | |
1815bff5 | 499 | |
1815bff5 A |
500 | for (j = 0; j < namewidth - 1 && name[j]; j++) { |
501 | if (name[j] == ' ') { | |
502 | putchar('.'); | |
503 | } else { | |
504 | putchar(name[j]); | |
505 | } | |
506 | } | |
507 | if (j == namewidth - 1) { | |
508 | if (name[j]) { | |
509 | putchar('$'); | |
510 | } else { | |
511 | putchar(' '); | |
512 | } | |
513 | } else { | |
514 | for (; j < namewidth; j++) { | |
515 | putchar(' '); | |
516 | } | |
517 | } | |
639dadd6 A |
518 | |
519 | ||
c0bbac3a A |
520 | #define PRINTCOL(value, index) \ |
521 | if (columns[(index)].visible) { \ | |
522 | printf(" %*llu", columns[(index)].colwidth * columns[(index)].alignment, (value)); \ | |
1815bff5 | 523 | } |
c0bbac3a A |
524 | #define PRINTCOLSTR(value, index) \ |
525 | if (columns[(index)].visible) { \ | |
526 | printf(" %*s", columns[(index)].colwidth * columns[(index)].alignment, (value)); \ | |
1815bff5 | 527 | } |
c0bbac3a A |
528 | #define PRINTCOLK(value, index) \ |
529 | if (columns[(index)].visible) { \ | |
530 | printf(" %*lluK", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value) / 1024 ); \ | |
1815bff5 | 531 | } |
c0bbac3a A |
532 | #define PRINTCOLSZ(value, index) \ |
533 | if (columns[(index)].visible) { \ | |
534 | if ((value) < 1024) { \ | |
535 | printf(" %*lluB", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value)); \ | |
536 | } else { \ | |
537 | PRINTCOLK(value, index) \ | |
538 | } \ | |
8459d725 | 539 | } |
639dadd6 A |
540 | |
541 | ||
542 | PRINTCOL(info->mzi_elem_size, COL_ELEM_SIZE); | |
543 | PRINTCOLK(info->mzi_cur_size, COL_CUR_SIZE); | |
544 | if (info->mzi_max_size / 1024 > 9999999) { | |
545 | /* | |
546 | * Zones with preposterously large maximum sizes are shown with `-------' | |
547 | * in the max size and max num elts fields. | |
548 | */ | |
549 | PRINTCOLSTR("-------", COL_MAX_SIZE); | |
550 | } else { | |
551 | PRINTCOLK(info->mzi_max_size, COL_MAX_SIZE); | |
8459d725 | 552 | } |
639dadd6 A |
553 | PRINTCOL(info->mzi_cur_size / info->mzi_elem_size, COL_CUR_ELTS); |
554 | if (info->mzi_max_size / 1024 > 9999999) { | |
555 | PRINTCOLSTR("-------", COL_MAX_ELTS); | |
556 | } else { | |
557 | PRINTCOL(info->mzi_max_size / info->mzi_elem_size, COL_MAX_ELTS); | |
558 | } | |
559 | PRINTCOL(info->mzi_count, COL_CUR_INUSE); | |
560 | PRINTCOLK(info->mzi_alloc_size, COL_ALLOC_SIZE); | |
561 | PRINTCOL(info->mzi_alloc_size / info->mzi_elem_size, COL_ALLOC_COUNT); | |
562 | ||
563 | totalused += used = info->mzi_elem_size * info->mzi_count; | |
564 | totalsize += size = info->mzi_cur_size; | |
565 | totalsum += info->mzi_sum_size; | |
566 | totalcollectable += collectable = GET_MZI_COLLECTABLE_BYTES(info->mzi_collectable); | |
567 | totalfragmented += fragmented = size - used - collectable; | |
568 | ||
569 | printf(" %c%c", | |
c0bbac3a A |
570 | (info->mzi_exhaustible ? 'X' : ' '), |
571 | (GET_MZI_COLLECTABLE_FLAG(info->mzi_collectable) ? 'C' : ' ')); | |
639dadd6 A |
572 | |
573 | PRINTCOLSZ(fragmented, COL_FRAG_SIZE); | |
574 | PRINTCOLSZ(collectable, COL_FREE_SIZE); | |
575 | PRINTCOLSZ(info->mzi_sum_size, COL_TOTAL_ALLOCS); | |
576 | ||
8459d725 | 577 | printf("\n"); |
1815bff5 A |
578 | } |
579 | ||
639dadd6 | 580 | |
1815bff5 | 581 | static void |
8459d725 | 582 | colprintzoneheader(void) |
1815bff5 | 583 | { |
639dadd6 A |
584 | int i, totalwidth = 0; |
585 | ||
c0bbac3a | 586 | if (!PrintHeader) { |
1815bff5 A |
587 | return; |
588 | } | |
639dadd6 A |
589 | |
590 | for (i = 0; i < COL_MAX; i++) { | |
591 | if (columns[i].visible) { | |
592 | printf("%*s ", columns[i].colwidth * columns[i].alignment, columns[i].line1); | |
593 | } | |
594 | } | |
595 | printf("\n"); | |
596 | ||
597 | for (i = 0; i < COL_MAX; i++) { | |
598 | if (columns[i].visible) { | |
599 | printf("%*s ", columns[i].colwidth * columns[i].alignment, columns[i].line2); | |
600 | totalwidth += (columns[i].colwidth + 1); | |
601 | } | |
602 | } | |
603 | ||
604 | printf("\n"); | |
605 | for (i = 0; i < totalwidth; i++) { | |
606 | printf("-"); | |
607 | } | |
8459d725 A |
608 | printf("\n"); |
609 | } | |
610 | ||
611 | int | |
639dadd6 | 612 | find_deltas(mach_zone_name_t *name, mach_zone_info_t *info, mach_zone_info_t *max_info, |
c0bbac3a | 613 | char *deltas, int cnt, int first_time) |
8459d725 | 614 | { |
c0bbac3a A |
615 | int i; |
616 | int found_one = 0; | |
617 | ||
618 | for (i = 0; i < cnt; i++) { | |
619 | deltas[i] = 0; | |
620 | if (substr(zname, znamelen, name[i].mzn_name, | |
621 | strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) { | |
622 | if (first_time || info->mzi_cur_size > max_info->mzi_cur_size || | |
623 | (ShowTotal && ((info->mzi_sum_size >> 1) > max_info->mzi_sum_size))) { | |
624 | max_info->mzi_cur_size = info->mzi_cur_size; | |
625 | max_info->mzi_sum_size = info->mzi_sum_size; | |
626 | deltas[i] = 1; | |
627 | found_one = 1; | |
628 | } | |
629 | } | |
630 | info++; | |
631 | max_info++; | |
632 | } | |
633 | return found_one; | |
1815bff5 | 634 | } |
9726c137 A |
635 | |
636 | /********************************************************************* | |
637 | *********************************************************************/ | |
638 | ||
639 | static char * | |
640 | kern_vm_tag_name(uint64_t tag) | |
641 | { | |
c0bbac3a A |
642 | char * result; |
643 | const char * name; | |
644 | switch (tag) { | |
645 | case (VM_KERN_MEMORY_NONE): name = "VM_KERN_MEMORY_NONE"; break; | |
646 | case (VM_KERN_MEMORY_OSFMK): name = "VM_KERN_MEMORY_OSFMK"; break; | |
647 | case (VM_KERN_MEMORY_BSD): name = "VM_KERN_MEMORY_BSD"; break; | |
648 | case (VM_KERN_MEMORY_IOKIT): name = "VM_KERN_MEMORY_IOKIT"; break; | |
649 | case (VM_KERN_MEMORY_LIBKERN): name = "VM_KERN_MEMORY_LIBKERN"; break; | |
650 | case (VM_KERN_MEMORY_OSKEXT): name = "VM_KERN_MEMORY_OSKEXT"; break; | |
651 | case (VM_KERN_MEMORY_KEXT): name = "VM_KERN_MEMORY_KEXT"; break; | |
652 | case (VM_KERN_MEMORY_IPC): name = "VM_KERN_MEMORY_IPC"; break; | |
653 | case (VM_KERN_MEMORY_STACK): name = "VM_KERN_MEMORY_STACK"; break; | |
654 | case (VM_KERN_MEMORY_CPU): name = "VM_KERN_MEMORY_CPU"; break; | |
655 | case (VM_KERN_MEMORY_PMAP): name = "VM_KERN_MEMORY_PMAP"; break; | |
656 | case (VM_KERN_MEMORY_PTE): name = "VM_KERN_MEMORY_PTE"; break; | |
657 | case (VM_KERN_MEMORY_ZONE): name = "VM_KERN_MEMORY_ZONE"; break; | |
658 | case (VM_KERN_MEMORY_KALLOC): name = "VM_KERN_MEMORY_KALLOC"; break; | |
659 | case (VM_KERN_MEMORY_COMPRESSOR): name = "VM_KERN_MEMORY_COMPRESSOR"; break; | |
660 | case (VM_KERN_MEMORY_COMPRESSED_DATA): name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break; | |
661 | case (VM_KERN_MEMORY_PHANTOM_CACHE): name = "VM_KERN_MEMORY_PHANTOM_CACHE"; break; | |
662 | case (VM_KERN_MEMORY_WAITQ): name = "VM_KERN_MEMORY_WAITQ"; break; | |
663 | case (VM_KERN_MEMORY_DIAG): name = "VM_KERN_MEMORY_DIAG"; break; | |
664 | case (VM_KERN_MEMORY_LOG): name = "VM_KERN_MEMORY_LOG"; break; | |
665 | case (VM_KERN_MEMORY_FILE): name = "VM_KERN_MEMORY_FILE"; break; | |
666 | case (VM_KERN_MEMORY_MBUF): name = "VM_KERN_MEMORY_MBUF"; break; | |
667 | case (VM_KERN_MEMORY_UBC): name = "VM_KERN_MEMORY_UBC"; break; | |
668 | case (VM_KERN_MEMORY_SECURITY): name = "VM_KERN_MEMORY_SECURITY"; break; | |
669 | case (VM_KERN_MEMORY_MLOCK): name = "VM_KERN_MEMORY_MLOCK"; break; | |
670 | case (VM_KERN_MEMORY_REASON): name = "VM_KERN_MEMORY_REASON"; break; | |
671 | case (VM_KERN_MEMORY_SKYWALK): name = "VM_KERN_MEMORY_SKYWALK"; break; | |
672 | case (VM_KERN_MEMORY_LTABLE): name = "VM_KERN_MEMORY_LTABLE"; break; | |
00bf83c0 | 673 | case (VM_KERN_MEMORY_HV): name = "VM_KERN_MEMORY_HV"; break; |
c0bbac3a | 674 | case (VM_KERN_MEMORY_ANY): name = "VM_KERN_MEMORY_ANY"; break; |
00bf83c0 | 675 | case (VM_KERN_MEMORY_RETIRED): name = "VM_KERN_MEMORY_RETIRED"; break; |
c0bbac3a A |
676 | default: name = NULL; break; |
677 | } | |
678 | if (name) { | |
679 | asprintf(&result, "%s", name); | |
680 | } else { | |
681 | asprintf(&result, "VM_KERN_MEMORY_%lld", tag); | |
682 | } | |
683 | return result; | |
684 | } | |
9726c137 | 685 | |
cf37c299 | 686 | static char * |
9726c137 A |
687 | kern_vm_counter_name(uint64_t tag) |
688 | { | |
c0bbac3a A |
689 | char * result; |
690 | const char * name; | |
691 | switch (tag) { | |
692 | case (VM_KERN_COUNT_MANAGED): name = "VM_KERN_COUNT_MANAGED"; break; | |
693 | case (VM_KERN_COUNT_RESERVED): name = "VM_KERN_COUNT_RESERVED"; break; | |
694 | case (VM_KERN_COUNT_WIRED): name = "VM_KERN_COUNT_WIRED"; break; | |
695 | case (VM_KERN_COUNT_WIRED_BOOT): name = "VM_KERN_COUNT_WIRED_BOOT"; break; | |
696 | case (VM_KERN_COUNT_WIRED_MANAGED): name = "VM_KERN_COUNT_WIRED_MANAGED"; break; | |
697 | case (VM_KERN_COUNT_STOLEN): name = "VM_KERN_COUNT_STOLEN"; break; | |
698 | case (VM_KERN_COUNT_BOOT_STOLEN): name = "VM_KERN_COUNT_BOOT_STOLEN"; break; | |
699 | case (VM_KERN_COUNT_LOPAGE): name = "VM_KERN_COUNT_LOPAGE"; break; | |
700 | case (VM_KERN_COUNT_MAP_KERNEL): name = "VM_KERN_COUNT_MAP_KERNEL"; break; | |
701 | case (VM_KERN_COUNT_MAP_ZONE): name = "VM_KERN_COUNT_MAP_ZONE"; break; | |
702 | case (VM_KERN_COUNT_MAP_KALLOC): name = "VM_KERN_COUNT_MAP_KALLOC"; break; | |
703 | case (VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE): | |
704 | name = "VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE"; | |
705 | break; | |
706 | default: name = NULL; break; | |
707 | } | |
708 | if (name) { | |
709 | asprintf(&result, "%s", name); | |
710 | } else { | |
711 | asprintf(&result, "VM_KERN_COUNT_%lld", tag); | |
712 | } | |
713 | return result; | |
9726c137 A |
714 | } |
715 | ||
716 | static void | |
717 | MakeLoadTagKeys(const void * key, const void * value, void * context) | |
718 | { | |
c0bbac3a A |
719 | CFMutableDictionaryRef newDict = context; |
720 | CFDictionaryRef kextInfo = value; | |
721 | CFNumberRef loadTag; | |
722 | uint32_t loadTagValue; | |
723 | ||
724 | loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey)); | |
725 | CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue); | |
726 | key = (const void *)(uintptr_t) loadTagValue; | |
727 | CFDictionarySetValue(newDict, key, value); | |
9726c137 A |
728 | } |
729 | ||
c0bbac3a | 730 | static CSSymbolicatorRef gSym; |
9726c137 A |
731 | static CFMutableDictionaryRef gTagDict; |
732 | static mach_memory_info_t * gSites; | |
733 | ||
cf37c299 | 734 | static char * |
887d5eed | 735 | GetSiteName(int siteIdx, mach_zone_name_t * zoneNames, unsigned int zoneNamesCnt) |
9726c137 | 736 | { |
c0bbac3a A |
737 | const char * name; |
738 | uintptr_t kmodid; | |
739 | char * result; | |
740 | char * append; | |
741 | mach_vm_address_t addr; | |
742 | CFDictionaryRef kextInfo; | |
743 | CFStringRef bundleID; | |
744 | uint32_t type; | |
745 | ||
746 | const mach_memory_info_t * site; | |
747 | const char * fileName; | |
748 | CSSymbolRef symbol; | |
749 | const char * symbolName; | |
750 | CSSourceInfoRef sourceInfo; | |
751 | ||
752 | name = NULL; | |
753 | result = NULL; | |
754 | site = &gSites[siteIdx]; | |
755 | addr = site->site; | |
756 | type = (VM_KERN_SITE_TYPE & site->flags); | |
757 | kmodid = 0; | |
758 | ||
759 | if (VM_KERN_SITE_NAMED & site->flags) { | |
760 | asprintf(&result, "%s", &site->name[0]); | |
761 | } else { | |
762 | switch (type) { | |
763 | case VM_KERN_SITE_TAG: | |
764 | result = kern_vm_tag_name(addr); | |
765 | break; | |
766 | ||
767 | case VM_KERN_SITE_COUNTER: | |
768 | result = kern_vm_counter_name(addr); | |
769 | break; | |
770 | ||
771 | case VM_KERN_SITE_KMOD: | |
772 | ||
773 | kmodid = (uintptr_t) addr; | |
774 | kextInfo = CFDictionaryGetValue(gTagDict, (const void *)kmodid); | |
775 | if (kextInfo) { | |
776 | bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey); | |
777 | name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8); | |
778 | // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey)); | |
779 | } | |
780 | ||
781 | if (name) { | |
782 | asprintf(&result, "%s", name); | |
783 | } else { | |
784 | asprintf(&result, "(unloaded kmod)"); | |
785 | } | |
786 | break; | |
787 | ||
788 | case VM_KERN_SITE_KERNEL: | |
789 | symbolName = NULL; | |
790 | if (addr) { | |
791 | symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow); | |
792 | symbolName = CSSymbolGetName(symbol); | |
793 | } | |
794 | if (symbolName) { | |
795 | asprintf(&result, "%s", symbolName); | |
796 | sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow); | |
797 | fileName = CSSourceInfoGetPath(sourceInfo); | |
798 | if (fileName) { | |
799 | printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo)); | |
800 | } | |
801 | } else { | |
802 | asprintf(&result, "site 0x%qx", addr); | |
803 | } | |
804 | break; | |
805 | default: | |
806 | asprintf(&result, ""); | |
807 | break; | |
808 | } | |
809 | } | |
810 | ||
811 | if (result | |
812 | && (VM_KERN_SITE_ZONE & site->flags) | |
813 | && zoneNames | |
814 | && (site->zone < zoneNamesCnt)) { | |
815 | size_t namelen, zonelen; | |
816 | namelen = strlen(result); | |
817 | zonelen = strnlen(zoneNames[site->zone].mzn_name, sizeof(zoneNames[site->zone].mzn_name)); | |
818 | if (((namelen + zonelen) > 61) && (zonelen < 61)) { | |
819 | namelen = (61 - zonelen); | |
820 | } | |
821 | asprintf(&append, "%.*s[%.*s]", | |
887d5eed A |
822 | (int)namelen, |
823 | result, | |
824 | (int)zonelen, | |
825 | zoneNames[site->zone].mzn_name); | |
c0bbac3a A |
826 | free(result); |
827 | result = append; | |
828 | } | |
829 | if (result && kmodid) { | |
830 | asprintf(&append, "%-64s%3ld", result, kmodid); | |
831 | free(result); | |
832 | result = append; | |
833 | } | |
834 | ||
835 | return result; | |
9726c137 A |
836 | } |
837 | ||
c0bbac3a A |
838 | struct CompareThunk { |
839 | mach_zone_name_t *zoneNames; | |
840 | unsigned int zoneNamesCnt; | |
887d5eed A |
841 | }; |
842 | ||
cf37c299 | 843 | static int |
887d5eed | 844 | SortName(void * thunk, const void * left, const void * right) |
9726c137 | 845 | { |
c0bbac3a A |
846 | const struct CompareThunk * t = (typeof(t))thunk; |
847 | const int * idxL; | |
848 | const int * idxR; | |
849 | char * l; | |
850 | char * r; | |
851 | CFStringRef lcf; | |
852 | CFStringRef rcf; | |
853 | int result; | |
854 | ||
855 | idxL = (typeof(idxL))left; | |
856 | idxR = (typeof(idxR))right; | |
857 | l = GetSiteName(*idxL, t->zoneNames, t->zoneNamesCnt); | |
858 | r = GetSiteName(*idxR, t->zoneNames, t->zoneNamesCnt); | |
859 | ||
860 | lcf = CFStringCreateWithCString(kCFAllocatorDefault, l, kCFStringEncodingUTF8); | |
861 | rcf = CFStringCreateWithCString(kCFAllocatorDefault, r, kCFStringEncodingUTF8); | |
862 | ||
863 | result = (int) CFStringCompareWithOptionsAndLocale(lcf, rcf, CFRangeMake(0, CFStringGetLength(lcf)), kCFCompareNumerically, NULL); | |
864 | ||
865 | CFRelease(lcf); | |
866 | CFRelease(rcf); | |
867 | free(l); | |
868 | free(r); | |
869 | ||
870 | return result; | |
9726c137 A |
871 | } |
872 | ||
cf37c299 | 873 | static int |
887d5eed | 874 | SortSize(void * thunk, const void * left, const void * right) |
9726c137 | 875 | { |
c0bbac3a A |
876 | const mach_memory_info_t * siteL; |
877 | const mach_memory_info_t * siteR; | |
878 | const int * idxL; | |
879 | const int * idxR; | |
880 | ||
881 | idxL = (typeof(idxL))left; | |
882 | idxR = (typeof(idxR))right; | |
883 | siteL = &gSites[*idxL]; | |
884 | siteR = &gSites[*idxR]; | |
885 | ||
886 | if (siteL->size > siteR->size) { | |
887 | return -1; | |
888 | } else if (siteL->size < siteR->size) { | |
889 | return 1; | |
890 | } | |
891 | return 0; | |
9726c137 A |
892 | } |
893 | ||
894 | ||
895 | static void | |
896 | PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, | |
c0bbac3a A |
897 | mach_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames, |
898 | unsigned int zoneCnt, uint64_t zoneElements, | |
899 | int (*func)(void *, const void *, const void *), boolean_t column) | |
9726c137 | 900 | { |
c0bbac3a A |
901 | uint64_t zonetotal; |
902 | uint64_t top_wired; | |
903 | uint64_t size; | |
904 | uint64_t elemsTagged; | |
9726c137 | 905 | |
c0bbac3a A |
906 | CFDictionaryRef allKexts; |
907 | unsigned int idx, site, first; | |
908 | int sorted[wiredInfoCnt]; | |
909 | char totalstr[40]; | |
910 | char * name; | |
911 | bool headerPrinted; | |
9726c137 | 912 | |
c0bbac3a | 913 | zonetotal = totalsize; |
9726c137 | 914 | |
c0bbac3a | 915 | gSites = wiredInfo; |
9726c137 | 916 | |
c0bbac3a | 917 | gSym = CSSymbolicatorCreateWithMachKernel(); |
cf37c299 | 918 | |
c0bbac3a A |
919 | allKexts = OSKextCopyLoadedKextInfo(NULL, NULL); |
920 | gTagDict = CFDictionaryCreateMutable( | |
921 | kCFAllocatorDefault, (CFIndex) 0, | |
922 | (CFDictionaryKeyCallBacks *) 0, | |
923 | &kCFTypeDictionaryValueCallBacks); | |
9726c137 | 924 | |
c0bbac3a A |
925 | CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict); |
926 | CFRelease(allKexts); | |
9726c137 | 927 | |
c0bbac3a | 928 | top_wired = 0; |
9726c137 | 929 | |
c0bbac3a A |
930 | for (idx = 0; idx < wiredInfoCnt; idx++) { |
931 | sorted[idx] = idx; | |
932 | } | |
933 | first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC | |
934 | struct CompareThunk thunk; | |
935 | thunk.zoneNames = zoneNames; | |
936 | thunk.zoneNamesCnt = zoneCnt; | |
937 | qsort_r(&sorted[first], | |
cf37c299 A |
938 | wiredInfoCnt - first, |
939 | sizeof(sorted[0]), | |
887d5eed | 940 | &thunk, |
9726c137 A |
941 | func); |
942 | ||
c0bbac3a A |
943 | elemsTagged = 0; |
944 | for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) { | |
945 | site = sorted[idx]; | |
946 | if ((VM_KERN_SITE_COUNTER & gSites[site].flags) | |
947 | && (VM_KERN_COUNT_WIRED == gSites[site].site)) { | |
948 | top_wired = gSites[site].size; | |
949 | } | |
950 | if (VM_KERN_SITE_HIDE & gSites[site].flags) { | |
951 | continue; | |
952 | } | |
953 | if (!((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) { | |
954 | continue; | |
955 | } | |
887d5eed | 956 | |
c0bbac3a A |
957 | if ((VM_KERN_SITE_ZONE & gSites[site].flags) |
958 | && gSites[site].zone < zoneCnt) { | |
959 | elemsTagged += gSites[site].size / zoneInfo[gSites[site].zone].mzi_elem_size; | |
960 | } | |
887d5eed | 961 | |
c0bbac3a A |
962 | if ((gSites[site].size < 1024) && (gSites[site].peak < 1024)) { |
963 | continue; | |
964 | } | |
9726c137 | 965 | |
c0bbac3a A |
966 | name = GetSiteName(site, zoneNames, zoneCnt); |
967 | if (!substr(zname, znamelen, name, strlen(name))) { | |
968 | continue; | |
969 | } | |
970 | if (!headerPrinted) { | |
971 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
972 | printf(" kmod vm peak cur\n"); | |
973 | printf("wired memory id tag size waste size\n"); | |
974 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
975 | headerPrinted = true; | |
976 | } | |
977 | printf("%-67s", name); | |
978 | free(name); | |
979 | printf("%12d", gSites[site].tag); | |
9726c137 | 980 | |
c0bbac3a A |
981 | if (gSites[site].peak) { |
982 | PRINTK(" %10llu", gSites[site].peak); | |
983 | } else { | |
984 | printf(" %11s", ""); | |
985 | } | |
887d5eed | 986 | |
c0bbac3a A |
987 | if (gSites[site].collectable_bytes) { |
988 | PRINTK(" %5llu", gSites[site].collectable_bytes); | |
989 | } else { | |
990 | printf(" %6s", ""); | |
991 | } | |
887d5eed | 992 | |
c0bbac3a | 993 | PRINTK(" %9llu", gSites[site].size); |
887d5eed | 994 | |
c0bbac3a A |
995 | if (!(VM_KERN_SITE_ZONE & gSites[site].flags)) { |
996 | totalsize += gSites[site].size; | |
997 | } | |
9726c137 | 998 | |
c0bbac3a A |
999 | printf("\n"); |
1000 | } | |
9726c137 | 1001 | |
c0bbac3a A |
1002 | if (!znamelen) { |
1003 | printf("%-67s", "zones"); | |
1004 | printf("%12s", ""); | |
1005 | printf(" %11s", ""); | |
1006 | printf(" %6s", ""); | |
1007 | PRINTK(" %9llu", zonetotal); | |
1008 | printf("\n"); | |
1009 | } | |
1010 | if (headerPrinted) { | |
1011 | if (elemsTagged) { | |
1012 | snprintf(totalstr, sizeof(totalstr), "%lld of %lld", elemsTagged, zoneElements); | |
1013 | printf("zone tags%100s\n", totalstr); | |
1014 | } | |
1015 | snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0); | |
1016 | printf("total%104s\n", totalstr); | |
1017 | } | |
1018 | for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) { | |
1019 | site = sorted[idx]; | |
1020 | size = gSites[site].mapped; | |
1021 | if (!size) { | |
1022 | continue; | |
1023 | } | |
1024 | if (VM_KERN_SITE_HIDE & gSites[site].flags) { | |
1025 | continue; | |
1026 | } | |
1027 | if ((size == gSites[site].size) | |
1028 | && ((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) { | |
1029 | continue; | |
1030 | } | |
1031 | ||
1032 | name = GetSiteName(site, NULL, 0); | |
1033 | if (!substr(zname, znamelen, name, strlen(name))) { | |
1034 | continue; | |
1035 | } | |
1036 | if (!headerPrinted) { | |
1037 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
1038 | printf(" largest peak cur\n"); | |
1039 | printf("maps free free size size\n"); | |
1040 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
1041 | headerPrinted = true; | |
1042 | } | |
1043 | printf("%-55s", name); | |
1044 | free(name); | |
1045 | ||
1046 | if (gSites[site].free) { | |
1047 | PRINTK(" %10llu", gSites[site].free); | |
1048 | } else { | |
1049 | printf(" %11s", ""); | |
1050 | } | |
1051 | if (gSites[site].largest) { | |
1052 | PRINTK(" %10llu", gSites[site].largest); | |
1053 | } else { | |
1054 | printf(" %11s", ""); | |
1055 | } | |
1056 | if (gSites[site].peak) { | |
1057 | PRINTK(" %10llu", gSites[site].peak); | |
1058 | } else { | |
1059 | printf(" %11s", ""); | |
1060 | } | |
1061 | PRINTK(" %16llu", size); | |
1062 | ||
1063 | printf("\n"); | |
1064 | } | |
1065 | for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) { | |
1066 | site = sorted[idx]; | |
1067 | size = gSites[site].size; | |
1068 | if (!size || !(VM_KERN_SITE_ZONE_VIEW & gSites[site].flags)) { | |
1069 | continue; | |
1070 | } | |
1071 | ||
1072 | name = GetSiteName(site, NULL, 0); | |
1073 | if (!substr(zname, znamelen, name, strlen(name))) { | |
1074 | continue; | |
1075 | } | |
1076 | if (!headerPrinted) { | |
1077 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
1078 | printf(" cur\n"); | |
1079 | printf("zone views inuse\n"); | |
1080 | printf("-------------------------------------------------------------------------------------------------------------\n"); | |
1081 | headerPrinted = true; | |
1082 | } | |
1083 | printf("%-55s", name); | |
1084 | free(name); | |
1085 | ||
1086 | printf(" %11s", ""); | |
1087 | printf(" %11s", ""); | |
1088 | printf(" %11s", ""); | |
1089 | PRINTK(" %16llu", size); | |
1090 | ||
1091 | printf("\n"); | |
1092 | } | |
639dadd6 | 1093 | totalsize = zonetotal; |
9726c137 | 1094 | } |