2 * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
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.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie the
54 * rights to redistribute these changes.
59 * utility for printing out zone structures
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.
68 #include <vm_statistics.h>
72 #include <mach/mach.h>
73 #include <mach_debug/mach_debug.h>
74 #include <mach/mach_error.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>
88 #define streql(a, b) (strcmp((a), (b)) == 0)
89 #define strneql(a, b, n) (strncmp((a), (b), (n)) == 0)
90 #define PRINTK(fmt, value) \
91 printf(fmt "K", (value) / 1024 ) /* ick */
93 static void usage(FILE *stream
);
94 static void printzone(mach_zone_name_t
*, mach_zone_info_t
*);
95 static void colprintzone(mach_zone_name_t
*, mach_zone_info_t
*);
96 static int find_deltas(mach_zone_name_t
*, mach_zone_info_t
*, mach_zone_info_t
*, char *, int, int);
97 static void colprintzoneheader(void);
98 static boolean_t
substr(const char *a
, size_t alen
, const char *b
, size_t blen
);
100 static int SortName(void * thunk
, const void * left
, const void * right
);
101 static int SortSize(void * thunk
, const void * left
, const void * right
);
102 static void PrintLarge(mach_memory_info_t
*wiredInfo
, unsigned int wiredInfoCnt
,
103 mach_zone_info_t
*zoneInfo
, mach_zone_name_t
*zoneNames
,
104 unsigned int zoneCnt
, uint64_t zoneElements
,
105 int (*func
)(void *, const void *, const void *), boolean_t column
);
107 static char *program
;
109 static boolean_t ShowDeltas
= FALSE
;
110 static boolean_t ShowWasted
= FALSE
;
111 static boolean_t ShowTotal
= FALSE
;
112 static boolean_t ShowLarge
= TRUE
;
113 static boolean_t SortZones
= FALSE
;
114 static boolean_t ColFormat
= TRUE
;
115 static boolean_t PrintHeader
= TRUE
;
117 static unsigned long long totalsize
= 0;
118 static unsigned long long totalused
= 0;
119 static unsigned long long totalsum
= 0;
120 static unsigned long long totalfragmented
= 0;
121 static unsigned long long totalcollectable
= 0;
123 static int last_time
= 0;
125 static char *zname
= NULL
;
126 static size_t znamelen
= 0;
157 * The order in which the columns appear below should match
158 * the order in which the values are printed in colprintzone().
160 static column_format columns
[] = {
161 [COL_ZONE_NAME
] = { "", "zone name", 25, LEFTALIGN
, true },
162 [COL_ELEM_SIZE
] = { "elem", "size", 6, RIGHTALIGN
, true },
163 [COL_CUR_SIZE
] = { "cur", "size", 11, RIGHTALIGN
, true },
164 [COL_MAX_SIZE
] = { "max", "size", 11, RIGHTALIGN
, true },
165 [COL_CUR_ELTS
] = { "cur", "#elts", 10, RIGHTALIGN
, true },
166 [COL_MAX_ELTS
] = { "max", "#elts", 11, RIGHTALIGN
, true },
167 [COL_CUR_INUSE
] = { "cur", "inuse", 11, RIGHTALIGN
, true },
168 [COL_ALLOC_SIZE
] = { "alloc", "size", 6, RIGHTALIGN
, true },
169 [COL_ALLOC_COUNT
] = { "alloc", "count", 6, RIGHTALIGN
, true },
170 [COL_ZONE_FLAGS
] = { "", "", 2, RIGHTALIGN
, true },
171 /* additional columns for special flags, not visible by default */
172 [COL_FRAG_SIZE
] = { "frag", "size", 9, RIGHTALIGN
, false },
173 [COL_FREE_SIZE
] = { "free", "size", 9, RIGHTALIGN
, false },
174 [COL_TOTAL_ALLOCS
] = { "total", "allocs", 17, RIGHTALIGN
, false }
178 sigintr(__unused
int signum
)
186 fprintf(stream
, "usage: %s [-w] [-s] [-c] [-h] [-H] [-t] [-d] [-l] [-L] [name]\n\n", program
);
187 fprintf(stream
, "\t-w\tshow wasted memory for each zone\n");
188 fprintf(stream
, "\t-s\tsort zones by wasted memory\n");
189 fprintf(stream
, "\t-c\t(default) display output formatted in columns\n");
190 fprintf(stream
, "\t-h\tdisplay this help message\n");
191 fprintf(stream
, "\t-H\thide column names\n");
192 fprintf(stream
, "\t-t\tdisplay the total size of allocations over the life of the zone\n");
193 fprintf(stream
, "\t-d\tdisplay deltas over time\n");
194 fprintf(stream
, "\t-l\t(default) display wired memory info after zone info\n");
195 fprintf(stream
, "\t-L\tdo not show wired memory info, only show zone info\n");
196 fprintf(stream
, "\nAny option (including default options) can be overridden by specifying the option in upper-case.\n\n");
197 exit(stream
!= stdout
);
201 main(int argc
, char **argv
)
203 mach_zone_name_t
*name
= NULL
;
204 unsigned int nameCnt
= 0;
205 mach_zone_info_t
*info
= NULL
;
206 unsigned int infoCnt
= 0;
207 mach_memory_info_t
*wiredInfo
= NULL
;
208 unsigned int wiredInfoCnt
= 0;
209 mach_zone_info_t
*max_info
= NULL
;
211 uint64_t zoneElements
;
219 signal(SIGINT
, sigintr
);
221 program
= strrchr(argv
[0], '/');
227 for (i
= 1; i
< argc
; i
++) {
228 if (streql(argv
[i
], "-d"))
230 else if (streql(argv
[i
], "-t"))
232 else if (streql(argv
[i
], "-T"))
234 else if (streql(argv
[i
], "-w"))
236 else if (streql(argv
[i
], "-W"))
238 else if (streql(argv
[i
], "-l"))
240 else if (streql(argv
[i
], "-L"))
242 else if (streql(argv
[i
], "-s"))
244 else if (streql(argv
[i
], "-S"))
246 else if (streql(argv
[i
], "-c"))
248 else if (streql(argv
[i
], "-C"))
250 else if (streql(argv
[i
], "-h"))
252 else if (streql(argv
[i
], "-H"))
254 else if (streql(argv
[i
], "--")) {
257 } else if (argv
[i
][0] == '-')
271 znamelen
= strlen(zname
);
285 columns
[COL_FRAG_SIZE
].visible
= true;
286 columns
[COL_FREE_SIZE
].visible
= true;
289 columns
[COL_TOTAL_ALLOCS
].visible
= true;
293 kr
= mach_memory_info(mach_host_self(),
294 &name
, &nameCnt
, &info
, &infoCnt
,
295 &wiredInfo
, &wiredInfoCnt
);
296 if (kr
!= KERN_SUCCESS
) {
297 fprintf(stderr
, "%s: mach_zone_info: %s\n",
298 program
, mach_error_string(kr
));
302 if (nameCnt
!= infoCnt
) {
303 fprintf(stderr
, "%s: mach_zone_name/ mach_zone_info: counts not equal?\n",
309 deltas
= (char *)malloc(infoCnt
);
310 max_info
= (mach_zone_info_t
*)malloc((infoCnt
* sizeof *info
));
314 for (i
= 0; i
< nameCnt
-1; i
++) {
315 for (j
= i
+1; j
< nameCnt
; j
++) {
316 unsigned long long wastei
, wastej
;
318 wastei
= (info
[i
].mzi_cur_size
-
319 (info
[i
].mzi_elem_size
*
321 wastej
= (info
[j
].mzi_cur_size
-
322 (info
[j
].mzi_elem_size
*
325 if (wastej
> wastei
) {
326 mach_zone_info_t tinfo
;
327 mach_zone_name_t tname
;
341 must_print
= find_deltas(name
, info
, max_info
, deltas
, infoCnt
, first_time
);
347 colprintzoneheader();
349 for (i
= 0; i
< nameCnt
; i
++) {
352 colprintzone(&name
[i
], &info
[i
]);
354 printzone(&name
[i
], &info
[i
]);
355 zoneElements
+= info
[i
].mzi_count
;
360 if (ShowLarge
&& first_time
) {
361 PrintLarge(wiredInfo
, wiredInfoCnt
, &info
[0], &name
[0],
362 nameCnt
, zoneElements
,
363 SortZones
? &SortSize
: &SortName
, ColFormat
);
368 if ((name
!= NULL
) && (nameCnt
!= 0)) {
369 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) name
,
370 (vm_size_t
) (nameCnt
* sizeof *name
));
371 if (kr
!= KERN_SUCCESS
) {
372 fprintf(stderr
, "%s: vm_deallocate: %s\n",
373 program
, mach_error_string(kr
));
378 if ((info
!= NULL
) && (infoCnt
!= 0)) {
379 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) info
,
380 (vm_size_t
) (infoCnt
* sizeof *info
));
381 if (kr
!= KERN_SUCCESS
) {
382 fprintf(stderr
, "%s: vm_deallocate: %s\n",
383 program
, mach_error_string(kr
));
388 if ((wiredInfo
!= NULL
) && (wiredInfoCnt
!= 0)) {
389 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) wiredInfo
,
390 (vm_size_t
) (wiredInfoCnt
* sizeof *wiredInfo
));
391 if (kr
!= KERN_SUCCESS
) {
392 fprintf(stderr
, "%s: vm_deallocate: %s\n",
393 program
, mach_error_string(kr
));
398 if ((ShowWasted
||ShowTotal
) && PrintHeader
&& !ShowDeltas
) {
399 printf("\nZONE TOTALS\n");
400 printf("---------------------------------------------\n");
401 printf("TOTAL SIZE = %llu\n", totalsize
);
402 printf("TOTAL USED = %llu\n", totalused
);
404 printf("TOTAL WASTED = %llu\n", totalsize
- totalused
);
405 printf("TOTAL FRAGMENTED = %llu\n", totalfragmented
);
406 printf("TOTAL COLLECTABLE = %llu\n", totalcollectable
);
409 printf("TOTAL ALLOCS = %llu\n", totalsum
);
412 if (ShowDeltas
== FALSE
|| last_time
)
421 substr(const char *a
, size_t alen
, const char *b
, size_t blen
)
425 if (alen
> blen
) return FALSE
;
427 for (i
= 0; i
<= blen
- alen
; i
++)
428 if (strneql(a
, b
+i
, alen
))
435 printzone(mach_zone_name_t
*name
, mach_zone_info_t
*info
)
437 unsigned long long used
, size
, fragmented
, collectable
;
439 printf("%.*s zone:\n", (int)sizeof name
->mzn_name
, name
->mzn_name
);
440 printf("\tcur_size: %lluK bytes (%llu elements)\n",
441 info
->mzi_cur_size
/1024,
442 (info
->mzi_elem_size
== 0) ? 0 :
443 info
->mzi_cur_size
/info
->mzi_elem_size
);
444 printf("\tmax_size: %lluK bytes (%llu elements)\n",
445 info
->mzi_max_size
/1024,
446 (info
->mzi_elem_size
== 0) ? 0 :
447 info
->mzi_max_size
/info
->mzi_elem_size
);
448 printf("\telem_size: %llu bytes\n",
449 info
->mzi_elem_size
);
450 printf("\t# of elems: %llu\n",
452 printf("\talloc_size: %lluK bytes (%llu elements)\n",
453 info
->mzi_alloc_size
/1024,
454 (info
->mzi_elem_size
== 0) ? 0 :
455 info
->mzi_alloc_size
/info
->mzi_elem_size
);
456 if (info
->mzi_exhaustible
)
457 printf("\tEXHAUSTIBLE\n");
458 if (GET_MZI_COLLECTABLE_FLAG(info
->mzi_collectable
))
459 printf("\tCOLLECTABLE\n");
461 totalused
+= used
= info
->mzi_elem_size
* info
->mzi_count
;
462 totalsize
+= size
= info
->mzi_cur_size
;
463 totalcollectable
+= collectable
= GET_MZI_COLLECTABLE_BYTES(info
->mzi_collectable
);
464 totalfragmented
+= fragmented
= size
- used
- collectable
;
465 printf("\t\t\t\t\tWASTED: %llu\n", size
- used
);
466 printf("\t\t\t\t\tFRAGMENTED: %llu\n", fragmented
);
467 printf("\t\t\t\t\tCOLLECTABLE: %llu\n", collectable
);
470 totalsum
+= info
->mzi_sum_size
;
471 printf("\t\t\t\t\tTOTAL: %llu\n", totalsum
);
476 colprintzone(mach_zone_name_t
*zone_name
, mach_zone_info_t
*info
)
478 char *name
= zone_name
->mzn_name
;
480 unsigned long long used
, size
, fragmented
, collectable
;
482 namewidth
= columns
[COL_ZONE_NAME
].colwidth
;
484 for (j
= 0; j
< namewidth
- 1 && name
[j
]; j
++) {
485 if (name
[j
] == ' ') {
491 if (j
== namewidth
- 1) {
498 for (; j
< namewidth
; j
++) {
504 #define PRINTCOL(value, index) \
505 if (columns[(index)].visible) { \
506 printf(" %*llu", columns[(index)].colwidth * columns[(index)].alignment, (value)); \
508 #define PRINTCOLSTR(value, index) \
509 if (columns[(index)].visible) { \
510 printf(" %*s", columns[(index)].colwidth * columns[(index)].alignment, (value)); \
512 #define PRINTCOLK(value, index) \
513 if (columns[(index)].visible) { \
514 printf(" %*lluK", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value) / 1024 ); \
516 #define PRINTCOLSZ(value, index) \
517 if (columns[(index)].visible) { \
518 if ((value) < 1024) { \
519 printf(" %*lluB", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value)); \
521 PRINTCOLK(value, index) \
526 PRINTCOL(info
->mzi_elem_size
, COL_ELEM_SIZE
);
527 PRINTCOLK(info
->mzi_cur_size
, COL_CUR_SIZE
);
528 if (info
->mzi_max_size
/ 1024 > 9999999) {
530 * Zones with preposterously large maximum sizes are shown with `-------'
531 * in the max size and max num elts fields.
533 PRINTCOLSTR("-------", COL_MAX_SIZE
);
535 PRINTCOLK(info
->mzi_max_size
, COL_MAX_SIZE
);
537 PRINTCOL(info
->mzi_cur_size
/ info
->mzi_elem_size
, COL_CUR_ELTS
);
538 if (info
->mzi_max_size
/ 1024 > 9999999) {
539 PRINTCOLSTR("-------", COL_MAX_ELTS
);
541 PRINTCOL(info
->mzi_max_size
/ info
->mzi_elem_size
, COL_MAX_ELTS
);
543 PRINTCOL(info
->mzi_count
, COL_CUR_INUSE
);
544 PRINTCOLK(info
->mzi_alloc_size
, COL_ALLOC_SIZE
);
545 PRINTCOL(info
->mzi_alloc_size
/ info
->mzi_elem_size
, COL_ALLOC_COUNT
);
547 totalused
+= used
= info
->mzi_elem_size
* info
->mzi_count
;
548 totalsize
+= size
= info
->mzi_cur_size
;
549 totalsum
+= info
->mzi_sum_size
;
550 totalcollectable
+= collectable
= GET_MZI_COLLECTABLE_BYTES(info
->mzi_collectable
);
551 totalfragmented
+= fragmented
= size
- used
- collectable
;
554 (info
->mzi_exhaustible
? 'X' : ' '),
555 (GET_MZI_COLLECTABLE_FLAG(info
->mzi_collectable
) ? 'C' : ' '));
557 PRINTCOLSZ(fragmented
, COL_FRAG_SIZE
);
558 PRINTCOLSZ(collectable
, COL_FREE_SIZE
);
559 PRINTCOLSZ(info
->mzi_sum_size
, COL_TOTAL_ALLOCS
);
566 colprintzoneheader(void)
568 int i
, totalwidth
= 0;
574 for (i
= 0; i
< COL_MAX
; i
++) {
575 if (columns
[i
].visible
) {
576 printf("%*s ", columns
[i
].colwidth
* columns
[i
].alignment
, columns
[i
].line1
);
581 for (i
= 0; i
< COL_MAX
; i
++) {
582 if (columns
[i
].visible
) {
583 printf("%*s ", columns
[i
].colwidth
* columns
[i
].alignment
, columns
[i
].line2
);
584 totalwidth
+= (columns
[i
].colwidth
+ 1);
589 for (i
= 0; i
< totalwidth
; i
++) {
596 find_deltas(mach_zone_name_t
*name
, mach_zone_info_t
*info
, mach_zone_info_t
*max_info
,
597 char *deltas
, int cnt
, int first_time
)
602 for (i
= 0; i
< cnt
; i
++) {
604 if (substr(zname
, znamelen
, name
[i
].mzn_name
,
605 strnlen(name
[i
].mzn_name
, sizeof name
[i
].mzn_name
))) {
606 if (first_time
|| info
->mzi_cur_size
> max_info
->mzi_cur_size
||
607 (ShowTotal
&& ((info
->mzi_sum_size
>> 1) > max_info
->mzi_sum_size
))) {
608 max_info
->mzi_cur_size
= info
->mzi_cur_size
;
609 max_info
->mzi_sum_size
= info
->mzi_sum_size
;
620 /*********************************************************************
621 *********************************************************************/
624 kern_vm_tag_name(uint64_t tag
)
630 case (VM_KERN_MEMORY_NONE
): name
= "VM_KERN_MEMORY_NONE"; break;
631 case (VM_KERN_MEMORY_OSFMK
): name
= "VM_KERN_MEMORY_OSFMK"; break;
632 case (VM_KERN_MEMORY_BSD
): name
= "VM_KERN_MEMORY_BSD"; break;
633 case (VM_KERN_MEMORY_IOKIT
): name
= "VM_KERN_MEMORY_IOKIT"; break;
634 case (VM_KERN_MEMORY_LIBKERN
): name
= "VM_KERN_MEMORY_LIBKERN"; break;
635 case (VM_KERN_MEMORY_OSKEXT
): name
= "VM_KERN_MEMORY_OSKEXT"; break;
636 case (VM_KERN_MEMORY_KEXT
): name
= "VM_KERN_MEMORY_KEXT"; break;
637 case (VM_KERN_MEMORY_IPC
): name
= "VM_KERN_MEMORY_IPC"; break;
638 case (VM_KERN_MEMORY_STACK
): name
= "VM_KERN_MEMORY_STACK"; break;
639 case (VM_KERN_MEMORY_CPU
): name
= "VM_KERN_MEMORY_CPU"; break;
640 case (VM_KERN_MEMORY_PMAP
): name
= "VM_KERN_MEMORY_PMAP"; break;
641 case (VM_KERN_MEMORY_PTE
): name
= "VM_KERN_MEMORY_PTE"; break;
642 case (VM_KERN_MEMORY_ZONE
): name
= "VM_KERN_MEMORY_ZONE"; break;
643 case (VM_KERN_MEMORY_KALLOC
): name
= "VM_KERN_MEMORY_KALLOC"; break;
644 case (VM_KERN_MEMORY_COMPRESSOR
): name
= "VM_KERN_MEMORY_COMPRESSOR"; break;
645 case (VM_KERN_MEMORY_COMPRESSED_DATA
): name
= "VM_KERN_MEMORY_COMPRESSED_DATA"; break;
646 case (VM_KERN_MEMORY_PHANTOM_CACHE
): name
= "VM_KERN_MEMORY_PHANTOM_CACHE"; break;
647 case (VM_KERN_MEMORY_WAITQ
): name
= "VM_KERN_MEMORY_WAITQ"; break;
648 case (VM_KERN_MEMORY_DIAG
): name
= "VM_KERN_MEMORY_DIAG"; break;
649 case (VM_KERN_MEMORY_LOG
): name
= "VM_KERN_MEMORY_LOG"; break;
650 case (VM_KERN_MEMORY_FILE
): name
= "VM_KERN_MEMORY_FILE"; break;
651 case (VM_KERN_MEMORY_MBUF
): name
= "VM_KERN_MEMORY_MBUF"; break;
652 case (VM_KERN_MEMORY_UBC
): name
= "VM_KERN_MEMORY_UBC"; break;
653 case (VM_KERN_MEMORY_SECURITY
): name
= "VM_KERN_MEMORY_SECURITY"; break;
654 case (VM_KERN_MEMORY_MLOCK
): name
= "VM_KERN_MEMORY_MLOCK"; break;
655 case (VM_KERN_MEMORY_REASON
): name
= "VM_KERN_MEMORY_REASON"; break;
656 case (VM_KERN_MEMORY_SKYWALK
): name
= "VM_KERN_MEMORY_SKYWALK"; break;
657 case (VM_KERN_MEMORY_LTABLE
): name
= "VM_KERN_MEMORY_LTABLE"; break;
658 case (VM_KERN_MEMORY_ANY
): name
= "VM_KERN_MEMORY_ANY"; break;
659 default: name
= NULL
; break;
661 if (name
) asprintf(&result
, "%s", name
);
662 else asprintf(&result
, "VM_KERN_MEMORY_%lld", tag
);
667 kern_vm_counter_name(uint64_t tag
)
673 case (VM_KERN_COUNT_MANAGED
): name
= "VM_KERN_COUNT_MANAGED"; break;
674 case (VM_KERN_COUNT_RESERVED
): name
= "VM_KERN_COUNT_RESERVED"; break;
675 case (VM_KERN_COUNT_WIRED
): name
= "VM_KERN_COUNT_WIRED"; break;
676 case (VM_KERN_COUNT_WIRED_BOOT
): name
= "VM_KERN_COUNT_WIRED_BOOT"; break;
677 case (VM_KERN_COUNT_WIRED_MANAGED
): name
= "VM_KERN_COUNT_WIRED_MANAGED"; break;
678 case (VM_KERN_COUNT_STOLEN
): name
= "VM_KERN_COUNT_STOLEN"; break;
679 case (VM_KERN_COUNT_BOOT_STOLEN
): name
= "VM_KERN_COUNT_BOOT_STOLEN"; break;
680 case (VM_KERN_COUNT_LOPAGE
): name
= "VM_KERN_COUNT_LOPAGE"; break;
681 case (VM_KERN_COUNT_MAP_KERNEL
): name
= "VM_KERN_COUNT_MAP_KERNEL"; break;
682 case (VM_KERN_COUNT_MAP_ZONE
): name
= "VM_KERN_COUNT_MAP_ZONE"; break;
683 case (VM_KERN_COUNT_MAP_KALLOC
): name
= "VM_KERN_COUNT_MAP_KALLOC"; break;
684 default: name
= NULL
; break;
686 if (name
) asprintf(&result
, "%s", name
);
687 else asprintf(&result
, "VM_KERN_COUNT_%lld", tag
);
692 MakeLoadTagKeys(const void * key
, const void * value
, void * context
)
694 CFMutableDictionaryRef newDict
= context
;
695 CFDictionaryRef kextInfo
= value
;
697 uint32_t loadTagValue
;
699 loadTag
= (CFNumberRef
)CFDictionaryGetValue(kextInfo
, CFSTR(kOSBundleLoadTagKey
));
700 CFNumberGetValue(loadTag
, kCFNumberSInt32Type
, &loadTagValue
);
701 key
= (const void *)(uintptr_t) loadTagValue
;
702 CFDictionarySetValue(newDict
, key
, value
);
705 static CSSymbolicatorRef gSym
;
706 static CFMutableDictionaryRef gTagDict
;
707 static mach_memory_info_t
* gSites
;
710 GetSiteName(int siteIdx
, mach_zone_name_t
* zoneNames
, unsigned int zoneNamesCnt
)
716 mach_vm_address_t addr
;
717 CFDictionaryRef kextInfo
;
718 CFStringRef bundleID
;
721 const mach_memory_info_t
* site
;
722 const char * fileName
;
724 const char * symbolName
;
725 CSSourceInfoRef sourceInfo
;
729 site
= &gSites
[siteIdx
];
731 type
= (VM_KERN_SITE_TYPE
& site
->flags
);
734 if (VM_KERN_SITE_NAMED
& site
->flags
)
736 asprintf(&result
, "%s", &site
->name
[0]);
740 case VM_KERN_SITE_TAG
:
741 result
= kern_vm_tag_name(addr
);
744 case VM_KERN_SITE_COUNTER
:
745 result
= kern_vm_counter_name(addr
);
748 case VM_KERN_SITE_KMOD
:
750 kmodid
= (uintptr_t) addr
;
751 kextInfo
= CFDictionaryGetValue(gTagDict
, (const void *)kmodid
);
754 bundleID
= (CFStringRef
)CFDictionaryGetValue(kextInfo
, kCFBundleIdentifierKey
);
755 name
= CFStringGetCStringPtr(bundleID
, kCFStringEncodingUTF8
);
756 // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
759 if (name
) asprintf(&result
, "%s", name
);
760 else asprintf(&result
, "(unloaded kmod)");
763 case VM_KERN_SITE_KERNEL
:
767 symbol
= CSSymbolicatorGetSymbolWithAddressAtTime(gSym
, addr
, kCSNow
);
768 symbolName
= CSSymbolGetName(symbol
);
772 asprintf(&result
, "%s", symbolName
);
773 sourceInfo
= CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym
, addr
, kCSNow
);
774 fileName
= CSSourceInfoGetPath(sourceInfo
);
775 if (fileName
) printf(" (%s:%d)", fileName
, CSSourceInfoGetLineNumber(sourceInfo
));
779 asprintf(&result
, "site 0x%qx", addr
);
783 asprintf(&result
, "");
788 && (VM_KERN_SITE_ZONE
& site
->flags
)
790 && (site
->zone
< zoneNamesCnt
))
792 size_t namelen
, zonelen
;
793 namelen
= strlen(result
);
794 zonelen
= strnlen(zoneNames
[site
->zone
].mzn_name
, sizeof(zoneNames
[site
->zone
].mzn_name
));
795 if (((namelen
+ zonelen
) > 61) && (zonelen
< 61)) namelen
= (61 - zonelen
);
796 asprintf(&append
, "%.*s[%.*s]",
800 zoneNames
[site
->zone
].mzn_name
);
804 if (result
&& kmodid
)
806 asprintf(&append
, "%-64s%3ld", result
, kmodid
);
816 mach_zone_name_t
*zoneNames
;
817 unsigned int zoneNamesCnt
;
821 SortName(void * thunk
, const void * left
, const void * right
)
823 const struct CompareThunk
* t
= (typeof(t
)) thunk
;
832 idxL
= (typeof(idxL
)) left
;
833 idxR
= (typeof(idxR
)) right
;
834 l
= GetSiteName(*idxL
, t
->zoneNames
, t
->zoneNamesCnt
);
835 r
= GetSiteName(*idxR
, t
->zoneNames
, t
->zoneNamesCnt
);
837 lcf
= CFStringCreateWithCString(kCFAllocatorDefault
, l
, kCFStringEncodingUTF8
);
838 rcf
= CFStringCreateWithCString(kCFAllocatorDefault
, r
, kCFStringEncodingUTF8
);
840 result
= (int) CFStringCompareWithOptionsAndLocale(lcf
, rcf
, CFRangeMake(0, CFStringGetLength(lcf
)), kCFCompareNumerically
, NULL
);
851 SortSize(void * thunk
, const void * left
, const void * right
)
853 const mach_memory_info_t
* siteL
;
854 const mach_memory_info_t
* siteR
;
858 idxL
= (typeof(idxL
)) left
;
859 idxR
= (typeof(idxR
)) right
;
860 siteL
= &gSites
[*idxL
];
861 siteR
= &gSites
[*idxR
];
863 if (siteL
->size
> siteR
->size
) return (-1);
864 else if (siteL
->size
< siteR
->size
) return (1);
870 PrintLarge(mach_memory_info_t
*wiredInfo
, unsigned int wiredInfoCnt
,
871 mach_zone_info_t
*zoneInfo
, mach_zone_name_t
*zoneNames
,
872 unsigned int zoneCnt
, uint64_t zoneElements
,
873 int (*func
)(void *, const void *, const void *), boolean_t column
)
878 uint64_t elemsTagged
;
880 CFDictionaryRef allKexts
;
881 unsigned int idx
, site
, first
;
882 int sorted
[wiredInfoCnt
];
887 zonetotal
= totalsize
;
891 gSym
= CSSymbolicatorCreateWithMachKernel();
893 allKexts
= OSKextCopyLoadedKextInfo(NULL
, NULL
);
894 gTagDict
= CFDictionaryCreateMutable(
895 kCFAllocatorDefault
, (CFIndex
) 0,
896 (CFDictionaryKeyCallBacks
*) 0,
897 &kCFTypeDictionaryValueCallBacks
);
899 CFDictionaryApplyFunction(allKexts
, &MakeLoadTagKeys
, gTagDict
);
904 for (idx
= 0; idx
< wiredInfoCnt
; idx
++) sorted
[idx
] = idx
;
905 first
= 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
906 struct CompareThunk thunk
;
907 thunk
.zoneNames
= zoneNames
;
908 thunk
.zoneNamesCnt
= zoneCnt
;
909 qsort_r(&sorted
[first
],
910 wiredInfoCnt
- first
,
916 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++)
919 if ((VM_KERN_SITE_COUNTER
& gSites
[site
].flags
)
920 && (VM_KERN_COUNT_WIRED
== gSites
[site
].site
)) top_wired
= gSites
[site
].size
;
921 if (VM_KERN_SITE_HIDE
& gSites
[site
].flags
) continue;
922 if (!((VM_KERN_SITE_WIRED
| VM_KERN_SITE_ZONE
) & gSites
[site
].flags
)) continue;
924 if ((VM_KERN_SITE_ZONE
& gSites
[site
].flags
)
925 && gSites
[site
].zone
< zoneCnt
)
927 elemsTagged
+= gSites
[site
].size
/ zoneInfo
[gSites
[site
].zone
].mzi_elem_size
;
930 if ((gSites
[site
].size
< 1024) && (gSites
[site
].peak
< 1024)) continue;
932 name
= GetSiteName(site
, zoneNames
, zoneCnt
);
933 if (!substr(zname
, znamelen
, name
, strlen(name
))) continue;
936 printf("-------------------------------------------------------------------------------------------------------------\n");
937 printf(" kmod vm peak cur\n");
938 printf("wired memory id tag size waste size\n");
939 printf("-------------------------------------------------------------------------------------------------------------\n");
940 headerPrinted
= true;
942 printf("%-67s", name
);
944 printf("%12d", gSites
[site
].tag
);
946 if (gSites
[site
].peak
) PRINTK(" %10llu", gSites
[site
].peak
);
947 else printf(" %11s", "");
949 if (gSites
[site
].collectable_bytes
) PRINTK(" %5llu", gSites
[site
].collectable_bytes
);
950 else printf(" %6s", "");
952 PRINTK(" %9llu", gSites
[site
].size
);
954 if (!(VM_KERN_SITE_ZONE
& gSites
[site
].flags
)) totalsize
+= gSites
[site
].size
;
961 printf("%-67s", "zones");
965 PRINTK(" %9llu", zonetotal
);
972 snprintf(totalstr
, sizeof(totalstr
), "%lld of %lld", elemsTagged
, zoneElements
);
973 printf("zone tags%100s\n", totalstr
);
975 snprintf(totalstr
, sizeof(totalstr
), "%6.2fM of %6.2fM", totalsize
/ 1024.0 / 1024.0, top_wired
/ 1024.0 / 1024.0);
976 printf("total%104s\n", totalstr
);
978 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++)
981 size
= gSites
[site
].mapped
;
983 if (VM_KERN_SITE_HIDE
& gSites
[site
].flags
) continue;
984 if ((size
== gSites
[site
].size
)
985 && ((VM_KERN_SITE_WIRED
| VM_KERN_SITE_ZONE
) & gSites
[site
].flags
)) continue;
987 name
= GetSiteName(site
, NULL
, 0);
988 if (!substr(zname
, znamelen
, name
, strlen(name
))) continue;
991 printf("-------------------------------------------------------------------------------------------------------------\n");
992 printf(" largest peak cur\n");
993 printf("maps free free size size\n");
994 printf("-------------------------------------------------------------------------------------------------------------\n");
995 headerPrinted
= true;
997 printf("%-55s", name
);
1000 if (gSites
[site
].free
) PRINTK(" %10llu", gSites
[site
].free
);
1001 else printf(" %11s", "");
1002 if (gSites
[site
].largest
) PRINTK(" %10llu", gSites
[site
].largest
);
1003 else printf(" %11s", "");
1004 if (gSites
[site
].peak
) PRINTK(" %10llu", gSites
[site
].peak
);
1005 else printf(" %11s", "");
1006 PRINTK(" %16llu", size
);
1010 totalsize
= zonetotal
;