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 #ifndef VM_KERN_SITE_ZONE_VIEW
89 #define VM_KERN_SITE_ZONE_VIEW 0x00001000
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 */
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);
101 static void colprintzoneheader(void);
102 static boolean_t
substr(const char *a
, size_t alen
, const char *b
, size_t blen
);
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
,
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
);
111 static char *program
;
113 static boolean_t ShowDeltas
= FALSE
;
114 static boolean_t ShowWasted
= FALSE
;
115 static boolean_t ShowTotal
= FALSE
;
116 static boolean_t ShowLarge
= TRUE
;
117 static boolean_t SortZones
= FALSE
;
118 static boolean_t ColFormat
= TRUE
;
119 static boolean_t PrintHeader
= TRUE
;
121 static unsigned long long totalsize
= 0;
122 static unsigned long long totalused
= 0;
123 static unsigned long long totalsum
= 0;
124 static unsigned long long totalfragmented
= 0;
125 static unsigned long long totalcollectable
= 0;
127 static int last_time
= 0;
129 static char *zname
= NULL
;
130 static size_t znamelen
= 0;
161 * The order in which the columns appear below should match
162 * the order in which the values are printed in colprintzone().
164 static column_format columns
[] = {
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 }
182 sigintr(__unused
int signum
)
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
);
205 main(int argc
, char **argv
)
207 mach_zone_name_t
*name
= NULL
;
208 unsigned int nameCnt
= 0;
209 mach_zone_info_t
*info
= NULL
;
210 unsigned int infoCnt
= 0;
211 mach_memory_info_t
*wiredInfo
= NULL
;
212 unsigned int wiredInfoCnt
= 0;
213 mach_zone_info_t
*max_info
= NULL
;
215 uint64_t zoneElements
;
223 signal(SIGINT
, sigintr
);
225 program
= strrchr(argv
[0], '/');
226 if (program
== NULL
) {
232 for (i
= 1; i
< argc
; i
++) {
233 if (streql(argv
[i
], "-d")) {
235 } else if (streql(argv
[i
], "-t")) {
237 } else if (streql(argv
[i
], "-T")) {
239 } else if (streql(argv
[i
], "-w")) {
241 } else if (streql(argv
[i
], "-W")) {
243 } else if (streql(argv
[i
], "-l")) {
245 } else if (streql(argv
[i
], "-L")) {
247 } else if (streql(argv
[i
], "-s")) {
249 } else if (streql(argv
[i
], "-S")) {
251 } else if (streql(argv
[i
], "-c")) {
253 } else if (streql(argv
[i
], "-C")) {
255 } else if (streql(argv
[i
], "-h")) {
257 } else if (streql(argv
[i
], "-H")) {
259 } else if (streql(argv
[i
], "--")) {
262 } else if (argv
[i
][0] == '-') {
277 znamelen
= strlen(zname
);
291 columns
[COL_FRAG_SIZE
].visible
= true;
292 columns
[COL_FREE_SIZE
].visible
= true;
295 columns
[COL_TOTAL_ALLOCS
].visible
= true;
299 kr
= mach_memory_info(mach_host_self(),
300 &name
, &nameCnt
, &info
, &infoCnt
,
301 &wiredInfo
, &wiredInfoCnt
);
302 if (kr
!= KERN_SUCCESS
) {
303 fprintf(stderr
, "%s: mach_memory_info: %s (try running as root)\n",
304 program
, mach_error_string(kr
));
308 if (nameCnt
!= infoCnt
) {
309 fprintf(stderr
, "%s: mach_zone_name/ mach_zone_info: counts not equal?\n",
315 deltas
= (char *)malloc(infoCnt
);
316 max_info
= (mach_zone_info_t
*)malloc((infoCnt
* sizeof *info
));
320 for (i
= 0; i
< nameCnt
- 1; i
++) {
321 for (j
= i
+ 1; j
< nameCnt
; j
++) {
322 unsigned long long wastei
, wastej
;
324 wastei
= (info
[i
].mzi_cur_size
-
325 (info
[i
].mzi_elem_size
*
327 wastej
= (info
[j
].mzi_cur_size
-
328 (info
[j
].mzi_elem_size
*
331 if (wastej
> wastei
) {
332 mach_zone_info_t tinfo
;
333 mach_zone_name_t tname
;
347 must_print
= find_deltas(name
, info
, max_info
, deltas
, infoCnt
, first_time
);
354 colprintzoneheader();
356 for (i
= 0; i
< nameCnt
; i
++) {
359 colprintzone(&name
[i
], &info
[i
]);
361 printzone(&name
[i
], &info
[i
]);
363 zoneElements
+= info
[i
].mzi_count
;
368 if (ShowLarge
&& first_time
) {
369 PrintLarge(wiredInfo
, wiredInfoCnt
, &info
[0], &name
[0],
370 nameCnt
, zoneElements
,
371 SortZones
? &SortSize
: &SortName
, ColFormat
);
376 if ((name
!= NULL
) && (nameCnt
!= 0)) {
377 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) name
,
378 (vm_size_t
) (nameCnt
* sizeof *name
));
379 if (kr
!= KERN_SUCCESS
) {
380 fprintf(stderr
, "%s: vm_deallocate: %s\n",
381 program
, mach_error_string(kr
));
386 if ((info
!= NULL
) && (infoCnt
!= 0)) {
387 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) info
,
388 (vm_size_t
) (infoCnt
* sizeof *info
));
389 if (kr
!= KERN_SUCCESS
) {
390 fprintf(stderr
, "%s: vm_deallocate: %s\n",
391 program
, mach_error_string(kr
));
396 if ((wiredInfo
!= NULL
) && (wiredInfoCnt
!= 0)) {
397 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) wiredInfo
,
398 (vm_size_t
) (wiredInfoCnt
* sizeof *wiredInfo
));
399 if (kr
!= KERN_SUCCESS
) {
400 fprintf(stderr
, "%s: vm_deallocate: %s\n",
401 program
, mach_error_string(kr
));
406 if ((ShowWasted
|| ShowTotal
) && PrintHeader
&& !ShowDeltas
) {
407 printf("\nZONE TOTALS\n");
408 printf("---------------------------------------------\n");
409 printf("TOTAL SIZE = %llu\n", totalsize
);
410 printf("TOTAL USED = %llu\n", totalused
);
412 printf("TOTAL WASTED = %llu\n", totalsize
- totalused
);
413 printf("TOTAL FRAGMENTED = %llu\n", totalfragmented
);
414 printf("TOTAL COLLECTABLE = %llu\n", totalcollectable
);
417 printf("TOTAL ALLOCS = %llu\n", totalsum
);
421 if (ShowDeltas
== FALSE
|| last_time
) {
431 substr(const char *a
, size_t alen
, const char *b
, size_t blen
)
439 for (i
= 0; i
<= blen
- alen
; i
++) {
440 if (strneql(a
, b
+ i
, alen
)) {
449 printzone(mach_zone_name_t
*name
, mach_zone_info_t
*info
)
451 unsigned long long used
, size
, fragmented
, collectable
;
453 printf("%.*s zone:\n", (int)sizeof name
->mzn_name
, name
->mzn_name
);
454 printf("\tcur_size: %lluK bytes (%llu elements)\n",
455 info
->mzi_cur_size
/ 1024,
456 (info
->mzi_elem_size
== 0) ? 0 :
457 info
->mzi_cur_size
/ info
->mzi_elem_size
);
458 printf("\tmax_size: %lluK bytes (%llu elements)\n",
459 info
->mzi_max_size
/ 1024,
460 (info
->mzi_elem_size
== 0) ? 0 :
461 info
->mzi_max_size
/ info
->mzi_elem_size
);
462 printf("\telem_size: %llu bytes\n",
463 info
->mzi_elem_size
);
464 printf("\t# of elems: %llu\n",
466 printf("\talloc_size: %lluK bytes (%llu elements)\n",
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
) {
471 printf("\tEXHAUSTIBLE\n");
473 if (GET_MZI_COLLECTABLE_FLAG(info
->mzi_collectable
)) {
474 printf("\tCOLLECTABLE\n");
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
;
481 printf("\t\t\t\t\tWASTED: %llu\n", size
- used
);
482 printf("\t\t\t\t\tFRAGMENTED: %llu\n", fragmented
);
483 printf("\t\t\t\t\tCOLLECTABLE: %llu\n", collectable
);
486 totalsum
+= info
->mzi_sum_size
;
487 printf("\t\t\t\t\tTOTAL: %llu\n", totalsum
);
492 colprintzone(mach_zone_name_t
*zone_name
, mach_zone_info_t
*info
)
494 char *name
= zone_name
->mzn_name
;
496 unsigned long long used
, size
, fragmented
, collectable
;
498 namewidth
= columns
[COL_ZONE_NAME
].colwidth
;
500 for (j
= 0; j
< namewidth
- 1 && name
[j
]; j
++) {
501 if (name
[j
] == ' ') {
507 if (j
== namewidth
- 1) {
514 for (; j
< namewidth
; j
++) {
520 #define PRINTCOL(value, index) \
521 if (columns[(index)].visible) { \
522 printf(" %*llu", columns[(index)].colwidth * columns[(index)].alignment, (value)); \
524 #define PRINTCOLSTR(value, index) \
525 if (columns[(index)].visible) { \
526 printf(" %*s", columns[(index)].colwidth * columns[(index)].alignment, (value)); \
528 #define PRINTCOLK(value, index) \
529 if (columns[(index)].visible) { \
530 printf(" %*lluK", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value) / 1024 ); \
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)); \
537 PRINTCOLK(value, index) \
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) {
546 * Zones with preposterously large maximum sizes are shown with `-------'
547 * in the max size and max num elts fields.
549 PRINTCOLSTR("-------", COL_MAX_SIZE
);
551 PRINTCOLK(info
->mzi_max_size
, COL_MAX_SIZE
);
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
);
557 PRINTCOL(info
->mzi_max_size
/ info
->mzi_elem_size
, COL_MAX_ELTS
);
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
);
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
;
570 (info
->mzi_exhaustible
? 'X' : ' '),
571 (GET_MZI_COLLECTABLE_FLAG(info
->mzi_collectable
) ? 'C' : ' '));
573 PRINTCOLSZ(fragmented
, COL_FRAG_SIZE
);
574 PRINTCOLSZ(collectable
, COL_FREE_SIZE
);
575 PRINTCOLSZ(info
->mzi_sum_size
, COL_TOTAL_ALLOCS
);
582 colprintzoneheader(void)
584 int i
, totalwidth
= 0;
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
);
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);
605 for (i
= 0; i
< totalwidth
; i
++) {
612 find_deltas(mach_zone_name_t
*name
, mach_zone_info_t
*info
, mach_zone_info_t
*max_info
,
613 char *deltas
, int cnt
, int first_time
)
618 for (i
= 0; i
< cnt
; i
++) {
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
;
636 /*********************************************************************
637 *********************************************************************/
640 kern_vm_tag_name(uint64_t 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;
673 case (VM_KERN_MEMORY_ANY
): name
= "VM_KERN_MEMORY_ANY"; break;
674 default: name
= NULL
; break;
677 asprintf(&result
, "%s", name
);
679 asprintf(&result
, "VM_KERN_MEMORY_%lld", tag
);
685 kern_vm_counter_name(uint64_t tag
)
690 case (VM_KERN_COUNT_MANAGED
): name
= "VM_KERN_COUNT_MANAGED"; break;
691 case (VM_KERN_COUNT_RESERVED
): name
= "VM_KERN_COUNT_RESERVED"; break;
692 case (VM_KERN_COUNT_WIRED
): name
= "VM_KERN_COUNT_WIRED"; break;
693 case (VM_KERN_COUNT_WIRED_BOOT
): name
= "VM_KERN_COUNT_WIRED_BOOT"; break;
694 case (VM_KERN_COUNT_WIRED_MANAGED
): name
= "VM_KERN_COUNT_WIRED_MANAGED"; break;
695 case (VM_KERN_COUNT_STOLEN
): name
= "VM_KERN_COUNT_STOLEN"; break;
696 case (VM_KERN_COUNT_BOOT_STOLEN
): name
= "VM_KERN_COUNT_BOOT_STOLEN"; break;
697 case (VM_KERN_COUNT_LOPAGE
): name
= "VM_KERN_COUNT_LOPAGE"; break;
698 case (VM_KERN_COUNT_MAP_KERNEL
): name
= "VM_KERN_COUNT_MAP_KERNEL"; break;
699 case (VM_KERN_COUNT_MAP_ZONE
): name
= "VM_KERN_COUNT_MAP_ZONE"; break;
700 case (VM_KERN_COUNT_MAP_KALLOC
): name
= "VM_KERN_COUNT_MAP_KALLOC"; break;
701 case (VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE
):
702 name
= "VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE";
704 default: name
= NULL
; break;
707 asprintf(&result
, "%s", name
);
709 asprintf(&result
, "VM_KERN_COUNT_%lld", tag
);
715 MakeLoadTagKeys(const void * key
, const void * value
, void * context
)
717 CFMutableDictionaryRef newDict
= context
;
718 CFDictionaryRef kextInfo
= value
;
720 uint32_t loadTagValue
;
722 loadTag
= (CFNumberRef
)CFDictionaryGetValue(kextInfo
, CFSTR(kOSBundleLoadTagKey
));
723 CFNumberGetValue(loadTag
, kCFNumberSInt32Type
, &loadTagValue
);
724 key
= (const void *)(uintptr_t) loadTagValue
;
725 CFDictionarySetValue(newDict
, key
, value
);
728 static CSSymbolicatorRef gSym
;
729 static CFMutableDictionaryRef gTagDict
;
730 static mach_memory_info_t
* gSites
;
733 GetSiteName(int siteIdx
, mach_zone_name_t
* zoneNames
, unsigned int zoneNamesCnt
)
739 mach_vm_address_t addr
;
740 CFDictionaryRef kextInfo
;
741 CFStringRef bundleID
;
744 const mach_memory_info_t
* site
;
745 const char * fileName
;
747 const char * symbolName
;
748 CSSourceInfoRef sourceInfo
;
752 site
= &gSites
[siteIdx
];
754 type
= (VM_KERN_SITE_TYPE
& site
->flags
);
757 if (VM_KERN_SITE_NAMED
& site
->flags
) {
758 asprintf(&result
, "%s", &site
->name
[0]);
761 case VM_KERN_SITE_TAG
:
762 result
= kern_vm_tag_name(addr
);
765 case VM_KERN_SITE_COUNTER
:
766 result
= kern_vm_counter_name(addr
);
769 case VM_KERN_SITE_KMOD
:
771 kmodid
= (uintptr_t) addr
;
772 kextInfo
= CFDictionaryGetValue(gTagDict
, (const void *)kmodid
);
774 bundleID
= (CFStringRef
)CFDictionaryGetValue(kextInfo
, kCFBundleIdentifierKey
);
775 name
= CFStringGetCStringPtr(bundleID
, kCFStringEncodingUTF8
);
776 // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
780 asprintf(&result
, "%s", name
);
782 asprintf(&result
, "(unloaded kmod)");
786 case VM_KERN_SITE_KERNEL
:
789 symbol
= CSSymbolicatorGetSymbolWithAddressAtTime(gSym
, addr
, kCSNow
);
790 symbolName
= CSSymbolGetName(symbol
);
793 asprintf(&result
, "%s", symbolName
);
794 sourceInfo
= CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym
, addr
, kCSNow
);
795 fileName
= CSSourceInfoGetPath(sourceInfo
);
797 printf(" (%s:%d)", fileName
, CSSourceInfoGetLineNumber(sourceInfo
));
800 asprintf(&result
, "site 0x%qx", addr
);
804 asprintf(&result
, "");
810 && (VM_KERN_SITE_ZONE
& site
->flags
)
812 && (site
->zone
< zoneNamesCnt
)) {
813 size_t namelen
, zonelen
;
814 namelen
= strlen(result
);
815 zonelen
= strnlen(zoneNames
[site
->zone
].mzn_name
, sizeof(zoneNames
[site
->zone
].mzn_name
));
816 if (((namelen
+ zonelen
) > 61) && (zonelen
< 61)) {
817 namelen
= (61 - zonelen
);
819 asprintf(&append
, "%.*s[%.*s]",
823 zoneNames
[site
->zone
].mzn_name
);
827 if (result
&& kmodid
) {
828 asprintf(&append
, "%-64s%3ld", result
, kmodid
);
836 struct CompareThunk
{
837 mach_zone_name_t
*zoneNames
;
838 unsigned int zoneNamesCnt
;
842 SortName(void * thunk
, const void * left
, const void * right
)
844 const struct CompareThunk
* t
= (typeof(t
))thunk
;
853 idxL
= (typeof(idxL
))left
;
854 idxR
= (typeof(idxR
))right
;
855 l
= GetSiteName(*idxL
, t
->zoneNames
, t
->zoneNamesCnt
);
856 r
= GetSiteName(*idxR
, t
->zoneNames
, t
->zoneNamesCnt
);
858 lcf
= CFStringCreateWithCString(kCFAllocatorDefault
, l
, kCFStringEncodingUTF8
);
859 rcf
= CFStringCreateWithCString(kCFAllocatorDefault
, r
, kCFStringEncodingUTF8
);
861 result
= (int) CFStringCompareWithOptionsAndLocale(lcf
, rcf
, CFRangeMake(0, CFStringGetLength(lcf
)), kCFCompareNumerically
, NULL
);
872 SortSize(void * thunk
, const void * left
, const void * right
)
874 const mach_memory_info_t
* siteL
;
875 const mach_memory_info_t
* siteR
;
879 idxL
= (typeof(idxL
))left
;
880 idxR
= (typeof(idxR
))right
;
881 siteL
= &gSites
[*idxL
];
882 siteR
= &gSites
[*idxR
];
884 if (siteL
->size
> siteR
->size
) {
886 } else if (siteL
->size
< siteR
->size
) {
894 PrintLarge(mach_memory_info_t
*wiredInfo
, unsigned int wiredInfoCnt
,
895 mach_zone_info_t
*zoneInfo
, mach_zone_name_t
*zoneNames
,
896 unsigned int zoneCnt
, uint64_t zoneElements
,
897 int (*func
)(void *, const void *, const void *), boolean_t column
)
902 uint64_t elemsTagged
;
904 CFDictionaryRef allKexts
;
905 unsigned int idx
, site
, first
;
906 int sorted
[wiredInfoCnt
];
911 zonetotal
= totalsize
;
915 gSym
= CSSymbolicatorCreateWithMachKernel();
917 allKexts
= OSKextCopyLoadedKextInfo(NULL
, NULL
);
918 gTagDict
= CFDictionaryCreateMutable(
919 kCFAllocatorDefault
, (CFIndex
) 0,
920 (CFDictionaryKeyCallBacks
*) 0,
921 &kCFTypeDictionaryValueCallBacks
);
923 CFDictionaryApplyFunction(allKexts
, &MakeLoadTagKeys
, gTagDict
);
928 for (idx
= 0; idx
< wiredInfoCnt
; idx
++) {
931 first
= 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
932 struct CompareThunk thunk
;
933 thunk
.zoneNames
= zoneNames
;
934 thunk
.zoneNamesCnt
= zoneCnt
;
935 qsort_r(&sorted
[first
],
936 wiredInfoCnt
- first
,
942 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++) {
944 if ((VM_KERN_SITE_COUNTER
& gSites
[site
].flags
)
945 && (VM_KERN_COUNT_WIRED
== gSites
[site
].site
)) {
946 top_wired
= gSites
[site
].size
;
948 if (VM_KERN_SITE_HIDE
& gSites
[site
].flags
) {
951 if (!((VM_KERN_SITE_WIRED
| VM_KERN_SITE_ZONE
) & gSites
[site
].flags
)) {
955 if ((VM_KERN_SITE_ZONE
& gSites
[site
].flags
)
956 && gSites
[site
].zone
< zoneCnt
) {
957 elemsTagged
+= gSites
[site
].size
/ zoneInfo
[gSites
[site
].zone
].mzi_elem_size
;
960 if ((gSites
[site
].size
< 1024) && (gSites
[site
].peak
< 1024)) {
964 name
= GetSiteName(site
, zoneNames
, zoneCnt
);
965 if (!substr(zname
, znamelen
, name
, strlen(name
))) {
968 if (!headerPrinted
) {
969 printf("-------------------------------------------------------------------------------------------------------------\n");
970 printf(" kmod vm peak cur\n");
971 printf("wired memory id tag size waste size\n");
972 printf("-------------------------------------------------------------------------------------------------------------\n");
973 headerPrinted
= true;
975 printf("%-67s", name
);
977 printf("%12d", gSites
[site
].tag
);
979 if (gSites
[site
].peak
) {
980 PRINTK(" %10llu", gSites
[site
].peak
);
985 if (gSites
[site
].collectable_bytes
) {
986 PRINTK(" %5llu", gSites
[site
].collectable_bytes
);
991 PRINTK(" %9llu", gSites
[site
].size
);
993 if (!(VM_KERN_SITE_ZONE
& gSites
[site
].flags
)) {
994 totalsize
+= gSites
[site
].size
;
1001 printf("%-67s", "zones");
1003 printf(" %11s", "");
1005 PRINTK(" %9llu", zonetotal
);
1008 if (headerPrinted
) {
1010 snprintf(totalstr
, sizeof(totalstr
), "%lld of %lld", elemsTagged
, zoneElements
);
1011 printf("zone tags%100s\n", totalstr
);
1013 snprintf(totalstr
, sizeof(totalstr
), "%6.2fM of %6.2fM", totalsize
/ 1024.0 / 1024.0, top_wired
/ 1024.0 / 1024.0);
1014 printf("total%104s\n", totalstr
);
1016 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++) {
1018 size
= gSites
[site
].mapped
;
1022 if (VM_KERN_SITE_HIDE
& gSites
[site
].flags
) {
1025 if ((size
== gSites
[site
].size
)
1026 && ((VM_KERN_SITE_WIRED
| VM_KERN_SITE_ZONE
) & gSites
[site
].flags
)) {
1030 name
= GetSiteName(site
, NULL
, 0);
1031 if (!substr(zname
, znamelen
, name
, strlen(name
))) {
1034 if (!headerPrinted
) {
1035 printf("-------------------------------------------------------------------------------------------------------------\n");
1036 printf(" largest peak cur\n");
1037 printf("maps free free size size\n");
1038 printf("-------------------------------------------------------------------------------------------------------------\n");
1039 headerPrinted
= true;
1041 printf("%-55s", name
);
1044 if (gSites
[site
].free
) {
1045 PRINTK(" %10llu", gSites
[site
].free
);
1047 printf(" %11s", "");
1049 if (gSites
[site
].largest
) {
1050 PRINTK(" %10llu", gSites
[site
].largest
);
1052 printf(" %11s", "");
1054 if (gSites
[site
].peak
) {
1055 PRINTK(" %10llu", gSites
[site
].peak
);
1057 printf(" %11s", "");
1059 PRINTK(" %16llu", size
);
1063 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++) {
1065 size
= gSites
[site
].size
;
1066 if (!size
|| !(VM_KERN_SITE_ZONE_VIEW
& gSites
[site
].flags
)) {
1070 name
= GetSiteName(site
, NULL
, 0);
1071 if (!substr(zname
, znamelen
, name
, strlen(name
))) {
1074 if (!headerPrinted
) {
1075 printf("-------------------------------------------------------------------------------------------------------------\n");
1077 printf("zone views inuse\n");
1078 printf("-------------------------------------------------------------------------------------------------------------\n");
1079 headerPrinted
= true;
1081 printf("%-55s", name
);
1084 printf(" %11s", "");
1085 printf(" %11s", "");
1086 printf(" %11s", "");
1087 PRINTK(" %16llu", size
);
1091 totalsize
= zonetotal
;