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(void);
94 static void printzone(mach_zone_name_t
*, task_zone_info_t
*);
95 static void colprintzone(mach_zone_name_t
*, task_zone_info_t
*);
96 static int find_deltas(mach_zone_name_t
*, task_zone_info_t
*, task_zone_info_t
*, char *, int, int);
97 static void colprintzoneheader(void);
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 task_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 pid_t pid
= 0;
110 static task_t task
= TASK_NULL
;
111 static boolean_t ShowPid
= FALSE
;
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 pidsum
= 0;
126 static int last_time
= 0;
128 static char *zname
= NULL
;
129 static size_t znamelen
= 0;
132 sigintr(__unused
int signum
)
140 fprintf(stderr
, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p <pid>] [name]\n", program
);
145 main(int argc
, char **argv
)
147 mach_zone_name_t
*name
= NULL
;
148 unsigned int nameCnt
= 0;
149 task_zone_info_t
*info
= NULL
;
150 unsigned int infoCnt
= 0;
151 mach_memory_info_t
*wiredInfo
= NULL
;
152 unsigned int wiredInfoCnt
= 0;
153 task_zone_info_t
*max_info
= NULL
;
155 uint64_t zoneElements
;
163 signal(SIGINT
, sigintr
);
165 program
= strrchr(argv
[0], '/');
171 for (i
= 1; i
< argc
; i
++) {
172 if (streql(argv
[i
], "-d"))
174 else if (streql(argv
[i
], "-t"))
176 else if (streql(argv
[i
], "-T"))
178 else if (streql(argv
[i
], "-w"))
180 else if (streql(argv
[i
], "-W"))
182 else if (streql(argv
[i
], "-l"))
184 else if (streql(argv
[i
], "-L"))
186 else if (streql(argv
[i
], "-s"))
188 else if (streql(argv
[i
], "-S"))
190 else if (streql(argv
[i
], "-c"))
192 else if (streql(argv
[i
], "-C"))
194 else if (streql(argv
[i
], "-H"))
196 else if (streql(argv
[i
], "-p")) {
199 pid
= atoi(argv
[i
+1]);
203 } else if (streql(argv
[i
], "--")) {
206 } else if (argv
[i
][0] == '-')
220 znamelen
= strlen(zname
);
234 kr
= task_for_pid(mach_task_self(), pid
, &task
);
235 if (kr
!= KERN_SUCCESS
) {
236 fprintf(stderr
, "%s: task_for_pid(%d) failed: %s (try running as root)\n",
237 program
, pid
, mach_error_string(kr
));
244 kr
= task_zone_info(task
, &name
, &nameCnt
, &info
, &infoCnt
);
245 if (kr
!= KERN_SUCCESS
) {
246 fprintf(stderr
, "%s: task_zone_info: %s\n",
247 program
, mach_error_string(kr
));
251 mach_zone_info_t
*zinfo
= NULL
;
253 kr
= mach_memory_info(mach_host_self(),
254 &name
, &nameCnt
, &zinfo
, &infoCnt
,
255 &wiredInfo
, &wiredInfoCnt
);
256 if (kr
!= KERN_SUCCESS
) {
257 fprintf(stderr
, "%s: mach_zone_info: %s\n",
258 program
, mach_error_string(kr
));
262 kr
= vm_allocate(mach_task_self(), (vm_address_t
*)&info
,
263 infoCnt
* sizeof *info
, VM_FLAGS_ANYWHERE
);
264 if (kr
!= KERN_SUCCESS
) {
265 fprintf(stderr
, "%s vm_allocate: %s\n",
266 program
, mach_error_string(kr
));
269 for (i
= 0; i
< infoCnt
; i
++) {
270 *(mach_zone_info_t
*)(info
+ i
) = zinfo
[i
];
271 info
[i
].tzi_caller_acct
= 0;
272 info
[i
].tzi_task_alloc
= 0;
273 info
[i
].tzi_task_free
= 0;
275 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) zinfo
,
276 (vm_size_t
) (infoCnt
* sizeof *zinfo
));
277 if (kr
!= KERN_SUCCESS
) {
278 fprintf(stderr
, "%s: vm_deallocate: %s\n",
279 program
, mach_error_string(kr
));
284 if (nameCnt
!= infoCnt
) {
285 fprintf(stderr
, "%s: mach/task_zone_info: counts not equal?\n",
291 deltas
= (char *)malloc(infoCnt
);
292 max_info
= (task_zone_info_t
*)malloc((infoCnt
* sizeof *info
));
296 for (i
= 0; i
< nameCnt
-1; i
++)
297 for (j
= i
+1; j
< nameCnt
; j
++) {
298 unsigned long long wastei
, wastej
;
300 wastei
= (info
[i
].tzi_cur_size
-
301 (info
[i
].tzi_elem_size
*
303 wastej
= (info
[j
].tzi_cur_size
-
304 (info
[j
].tzi_elem_size
*
307 if (wastej
> wastei
) {
308 task_zone_info_t tinfo
;
309 mach_zone_name_t tname
;
322 must_print
= find_deltas(name
, info
, max_info
, deltas
, infoCnt
, first_time
);
328 colprintzoneheader();
330 for (i
= 0; i
< nameCnt
; i
++) {
333 colprintzone(&name
[i
], &info
[i
]);
335 printzone(&name
[i
], &info
[i
]);
336 zoneElements
+= info
[i
].tzi_count
;
341 if (ShowLarge
&& first_time
) {
342 PrintLarge(wiredInfo
, wiredInfoCnt
, &info
[0], &name
[0],
343 nameCnt
, zoneElements
,
344 SortZones
? &SortSize
: &SortName
, ColFormat
);
349 if ((name
!= NULL
) && (nameCnt
!= 0)) {
350 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) name
,
351 (vm_size_t
) (nameCnt
* sizeof *name
));
352 if (kr
!= KERN_SUCCESS
) {
353 fprintf(stderr
, "%s: vm_deallocate: %s\n",
354 program
, mach_error_string(kr
));
359 if ((info
!= NULL
) && (infoCnt
!= 0)) {
360 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) info
,
361 (vm_size_t
) (infoCnt
* sizeof *info
));
362 if (kr
!= KERN_SUCCESS
) {
363 fprintf(stderr
, "%s: vm_deallocate: %s\n",
364 program
, mach_error_string(kr
));
369 if ((wiredInfo
!= NULL
) && (wiredInfoCnt
!= 0)) {
370 kr
= vm_deallocate(mach_task_self(), (vm_address_t
) wiredInfo
,
371 (vm_size_t
) (wiredInfoCnt
* sizeof *wiredInfo
));
372 if (kr
!= KERN_SUCCESS
) {
373 fprintf(stderr
, "%s: vm_deallocate: %s\n",
374 program
, mach_error_string(kr
));
379 if ((ShowWasted
||ShowTotal
) && PrintHeader
&& !ShowDeltas
) {
380 printf("TOTAL SIZE = %llu\n", totalsize
);
381 printf("TOTAL USED = %llu\n", totalused
);
383 printf("TOTAL WASTED = %llu\n", totalsize
- totalused
);
385 printf("TOTAL ALLOCS = %llu\n", totalsum
);
388 if (ShowDeltas
== FALSE
|| last_time
)
397 substr(const char *a
, size_t alen
, const char *b
, size_t blen
)
401 if (alen
> blen
) return FALSE
;
403 for (i
= 0; i
<= blen
- alen
; i
++)
404 if (strneql(a
, b
+i
, alen
))
411 printzone(mach_zone_name_t
*name
, task_zone_info_t
*info
)
413 unsigned long long used
, size
;
415 printf("%.*s zone:\n", (int)sizeof name
->mzn_name
, name
->mzn_name
);
416 printf("\tcur_size: %lluK bytes (%llu elements)\n",
417 info
->tzi_cur_size
/1024,
418 (info
->tzi_elem_size
== 0) ? 0 :
419 info
->tzi_cur_size
/info
->tzi_elem_size
);
420 printf("\tmax_size: %lluK bytes (%llu elements)\n",
421 info
->tzi_max_size
/1024,
422 (info
->tzi_elem_size
== 0) ? 0 :
423 info
->tzi_max_size
/info
->tzi_elem_size
);
424 printf("\telem_size: %llu bytes\n",
425 info
->tzi_elem_size
);
426 printf("\t# of elems: %llu\n",
428 printf("\talloc_size: %lluK bytes (%llu elements)\n",
429 info
->tzi_alloc_size
/1024,
430 (info
->tzi_elem_size
== 0) ? 0 :
431 info
->tzi_alloc_size
/info
->tzi_elem_size
);
432 if (info
->tzi_exhaustible
)
433 printf("\tEXHAUSTIBLE\n");
434 if (info
->tzi_collectable
)
435 printf("\tCOLLECTABLE\n");
436 if (ShowPid
&& info
->tzi_caller_acct
)
437 printf("\tCALLER ACCOUNTED\n");
439 pidsum
+= info
->tzi_task_alloc
- info
->tzi_task_free
;
440 printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n",
441 (int)((info
->tzi_task_alloc
- info
->tzi_task_free
)/1024),
442 (info
->tzi_elem_size
== 0) ? 0 :
443 (info
->tzi_task_alloc
- info
->tzi_task_free
)/info
->tzi_elem_size
);
446 totalused
+= used
= info
->tzi_elem_size
* info
->tzi_count
;
447 totalsize
+= size
= info
->tzi_cur_size
;
448 printf("\t\t\t\t\tWASTED: %llu\n", size
- used
);
451 totalsum
+= info
->tzi_sum_size
;
452 printf("\t\t\t\t\tTOTAL: %llu\n", totalsum
);
454 printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum
);
459 colprintzone(mach_zone_name_t
*zone_name
, task_zone_info_t
*info
)
461 char *name
= zone_name
->mzn_name
;
463 unsigned long long used
, size
;
466 if (ShowWasted
|| ShowTotal
) {
469 for (j
= 0; j
< namewidth
- 1 && name
[j
]; j
++) {
470 if (name
[j
] == ' ') {
476 if (j
== namewidth
- 1) {
483 for (; j
< namewidth
; j
++) {
487 printf(" %6llu", info
->tzi_elem_size
);
488 PRINTK(" %10llu", info
->tzi_cur_size
);
489 if (info
->tzi_max_size
/ 1024 > 9999999) {
492 PRINTK(" %10llu", info
->tzi_max_size
);
494 printf(" %10llu", info
->tzi_cur_size
/ info
->tzi_elem_size
);
495 if (info
->tzi_max_size
/ 1024 >= 999999999) {
496 printf(" ----------");
498 printf(" %11llu", info
->tzi_max_size
/ info
->tzi_elem_size
);
500 printf(" %11llu", info
->tzi_count
);
501 PRINTK(" %5llu", info
->tzi_alloc_size
);
502 printf(" %6llu", info
->tzi_alloc_size
/ info
->tzi_elem_size
);
504 totalused
+= used
= info
->tzi_elem_size
* info
->tzi_count
;
505 totalsize
+= size
= info
->tzi_cur_size
;
506 totalsum
+= info
->tzi_sum_size
;
509 (info
->tzi_exhaustible
? 'X' : ' '),
510 (info
->tzi_caller_acct
? 'A' : ' '),
511 (info
->tzi_collectable
? 'C' : ' '));
513 PRINTK(" %8llu", size
- used
);
516 printf("%8dK", (int)((info
->tzi_task_alloc
- info
->tzi_task_free
)/1024));
519 if (info
->tzi_sum_size
< 1024)
520 printf(" %16lluB", info
->tzi_sum_size
);
522 PRINTK(" %16llu", info
->tzi_sum_size
);
528 colprintzoneheader(void)
533 printf("%s elem cur max cur max"
534 " cur alloc alloc %s%s\n",
535 (ShowWasted
||ShowTotal
)? "" : " ",
536 (ShowWasted
)? " ":"",
537 (ShowPid
) ? " PID" : "" );
538 printf("zone name%s size size size #elts #elts"
539 " inuse size count ", (ShowWasted
||ShowTotal
)? " " : " " );
545 printf(" Total Allocs");
546 printf("\n%s-------------------------------------------------------"
547 "-----------------------------------------------",
548 (ShowWasted
||ShowTotal
)? "" : "-------");
550 printf("----------");
554 printf("------------------");
559 find_deltas(mach_zone_name_t
*name
, task_zone_info_t
*info
, task_zone_info_t
*max_info
,
560 char *deltas
, int cnt
, int first_time
)
565 for (i
= 0; i
< cnt
; i
++) {
567 if (substr(zname
, znamelen
, name
[i
].mzn_name
,
568 strnlen(name
[i
].mzn_name
, sizeof name
[i
].mzn_name
))) {
569 if (first_time
|| info
->tzi_cur_size
> max_info
->tzi_cur_size
||
570 (ShowTotal
&& ((info
->tzi_sum_size
>> 1) > max_info
->tzi_sum_size
))) {
571 max_info
->tzi_cur_size
= info
->tzi_cur_size
;
572 max_info
->tzi_sum_size
= info
->tzi_sum_size
;
583 /*********************************************************************
584 *********************************************************************/
587 kern_vm_tag_name(uint64_t tag
)
593 case (VM_KERN_MEMORY_NONE
): name
= "VM_KERN_MEMORY_NONE"; break;
594 case (VM_KERN_MEMORY_OSFMK
): name
= "VM_KERN_MEMORY_OSFMK"; break;
595 case (VM_KERN_MEMORY_BSD
): name
= "VM_KERN_MEMORY_BSD"; break;
596 case (VM_KERN_MEMORY_IOKIT
): name
= "VM_KERN_MEMORY_IOKIT"; break;
597 case (VM_KERN_MEMORY_LIBKERN
): name
= "VM_KERN_MEMORY_LIBKERN"; break;
598 case (VM_KERN_MEMORY_OSKEXT
): name
= "VM_KERN_MEMORY_OSKEXT"; break;
599 case (VM_KERN_MEMORY_KEXT
): name
= "VM_KERN_MEMORY_KEXT"; break;
600 case (VM_KERN_MEMORY_IPC
): name
= "VM_KERN_MEMORY_IPC"; break;
601 case (VM_KERN_MEMORY_STACK
): name
= "VM_KERN_MEMORY_STACK"; break;
602 case (VM_KERN_MEMORY_CPU
): name
= "VM_KERN_MEMORY_CPU"; break;
603 case (VM_KERN_MEMORY_PMAP
): name
= "VM_KERN_MEMORY_PMAP"; break;
604 case (VM_KERN_MEMORY_PTE
): name
= "VM_KERN_MEMORY_PTE"; break;
605 case (VM_KERN_MEMORY_ZONE
): name
= "VM_KERN_MEMORY_ZONE"; break;
606 case (VM_KERN_MEMORY_KALLOC
): name
= "VM_KERN_MEMORY_KALLOC"; break;
607 case (VM_KERN_MEMORY_COMPRESSOR
): name
= "VM_KERN_MEMORY_COMPRESSOR"; break;
608 case (VM_KERN_MEMORY_COMPRESSED_DATA
): name
= "VM_KERN_MEMORY_COMPRESSED_DATA"; break;
609 case (VM_KERN_MEMORY_PHANTOM_CACHE
): name
= "VM_KERN_MEMORY_PHANTOM_CACHE"; break;
610 case (VM_KERN_MEMORY_WAITQ
): name
= "VM_KERN_MEMORY_WAITQ"; break;
611 case (VM_KERN_MEMORY_DIAG
): name
= "VM_KERN_MEMORY_DIAG"; break;
612 case (VM_KERN_MEMORY_LOG
): name
= "VM_KERN_MEMORY_LOG"; break;
613 case (VM_KERN_MEMORY_FILE
): name
= "VM_KERN_MEMORY_FILE"; break;
614 case (VM_KERN_MEMORY_MBUF
): name
= "VM_KERN_MEMORY_MBUF"; break;
615 case (VM_KERN_MEMORY_UBC
): name
= "VM_KERN_MEMORY_UBC"; break;
616 case (VM_KERN_MEMORY_SECURITY
): name
= "VM_KERN_MEMORY_SECURITY"; break;
617 case (VM_KERN_MEMORY_MLOCK
): name
= "VM_KERN_MEMORY_MLOCK"; break;
618 case (VM_KERN_MEMORY_REASON
): name
= "VM_KERN_MEMORY_REASON"; break;
619 case (VM_KERN_MEMORY_SKYWALK
): name
= "VM_KERN_MEMORY_SKYWALK"; break;
620 case (VM_KERN_MEMORY_LTABLE
): name
= "VM_KERN_MEMORY_LTABLE"; break;
621 case (VM_KERN_MEMORY_ANY
): name
= "VM_KERN_MEMORY_ANY"; break;
622 default: name
= NULL
; break;
624 if (name
) asprintf(&result
, "%s", name
);
625 else asprintf(&result
, "VM_KERN_MEMORY_%lld", tag
);
630 kern_vm_counter_name(uint64_t tag
)
636 case (VM_KERN_COUNT_MANAGED
): name
= "VM_KERN_COUNT_MANAGED"; break;
637 case (VM_KERN_COUNT_RESERVED
): name
= "VM_KERN_COUNT_RESERVED"; break;
638 case (VM_KERN_COUNT_WIRED
): name
= "VM_KERN_COUNT_WIRED"; break;
639 case (VM_KERN_COUNT_WIRED_BOOT
): name
= "VM_KERN_COUNT_WIRED_BOOT"; break;
640 case (VM_KERN_COUNT_WIRED_MANAGED
): name
= "VM_KERN_COUNT_WIRED_MANAGED"; break;
641 case (VM_KERN_COUNT_STOLEN
): name
= "VM_KERN_COUNT_STOLEN"; break;
642 case (VM_KERN_COUNT_BOOT_STOLEN
): name
= "VM_KERN_COUNT_BOOT_STOLEN"; break;
643 case (VM_KERN_COUNT_LOPAGE
): name
= "VM_KERN_COUNT_LOPAGE"; break;
644 case (VM_KERN_COUNT_MAP_KERNEL
): name
= "VM_KERN_COUNT_MAP_KERNEL"; break;
645 case (VM_KERN_COUNT_MAP_ZONE
): name
= "VM_KERN_COUNT_MAP_ZONE"; break;
646 case (VM_KERN_COUNT_MAP_KALLOC
): name
= "VM_KERN_COUNT_MAP_KALLOC"; break;
647 default: name
= NULL
; break;
649 if (name
) asprintf(&result
, "%s", name
);
650 else asprintf(&result
, "VM_KERN_COUNT_%lld", tag
);
655 MakeLoadTagKeys(const void * key
, const void * value
, void * context
)
657 CFMutableDictionaryRef newDict
= context
;
658 CFDictionaryRef kextInfo
= value
;
660 uint32_t loadTagValue
;
662 loadTag
= (CFNumberRef
)CFDictionaryGetValue(kextInfo
, CFSTR(kOSBundleLoadTagKey
));
663 CFNumberGetValue(loadTag
, kCFNumberSInt32Type
, &loadTagValue
);
664 key
= (const void *)(uintptr_t) loadTagValue
;
665 CFDictionarySetValue(newDict
, key
, value
);
668 static CSSymbolicatorRef gSym
;
669 static CFMutableDictionaryRef gTagDict
;
670 static mach_memory_info_t
* gSites
;
673 GetSiteName(int siteIdx
, mach_zone_name_t
* zoneNames
, unsigned int zoneNamesCnt
)
679 mach_vm_address_t addr
;
680 CFDictionaryRef kextInfo
;
681 CFStringRef bundleID
;
684 const mach_memory_info_t
* site
;
685 const char * fileName
;
687 const char * symbolName
;
688 CSSourceInfoRef sourceInfo
;
692 site
= &gSites
[siteIdx
];
694 type
= (VM_KERN_SITE_TYPE
& site
->flags
);
697 if (VM_KERN_SITE_NAMED
& site
->flags
)
699 asprintf(&result
, "%s", &site
->name
[0]);
703 case VM_KERN_SITE_TAG
:
704 result
= kern_vm_tag_name(addr
);
707 case VM_KERN_SITE_COUNTER
:
708 result
= kern_vm_counter_name(addr
);
711 case VM_KERN_SITE_KMOD
:
713 kmodid
= (uintptr_t) addr
;
714 kextInfo
= CFDictionaryGetValue(gTagDict
, (const void *)kmodid
);
717 bundleID
= (CFStringRef
)CFDictionaryGetValue(kextInfo
, kCFBundleIdentifierKey
);
718 name
= CFStringGetCStringPtr(bundleID
, kCFStringEncodingUTF8
);
719 // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
722 if (name
) asprintf(&result
, "%s", name
);
723 else asprintf(&result
, "(unloaded kmod)");
726 case VM_KERN_SITE_KERNEL
:
730 symbol
= CSSymbolicatorGetSymbolWithAddressAtTime(gSym
, addr
, kCSNow
);
731 symbolName
= CSSymbolGetName(symbol
);
735 asprintf(&result
, "%s", symbolName
);
736 sourceInfo
= CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym
, addr
, kCSNow
);
737 fileName
= CSSourceInfoGetPath(sourceInfo
);
738 if (fileName
) printf(" (%s:%d)", fileName
, CSSourceInfoGetLineNumber(sourceInfo
));
742 asprintf(&result
, "site 0x%qx", addr
);
746 asprintf(&result
, "");
751 && (VM_KERN_SITE_ZONE
& site
->flags
)
753 && (site
->zone
< zoneNamesCnt
))
755 size_t namelen
, zonelen
;
756 namelen
= strlen(result
);
757 zonelen
= strnlen(zoneNames
[site
->zone
].mzn_name
, sizeof(zoneNames
[site
->zone
].mzn_name
));
758 if (((namelen
+ zonelen
) > 61) && (zonelen
< 61)) namelen
= (61 - zonelen
);
759 asprintf(&append
, "%.*s[%.*s]",
763 zoneNames
[site
->zone
].mzn_name
);
767 if (result
&& kmodid
)
769 asprintf(&append
, "%-64s%3ld", result
, kmodid
);
779 mach_zone_name_t
*zoneNames
;
780 unsigned int zoneNamesCnt
;
784 SortName(void * thunk
, const void * left
, const void * right
)
786 const struct CompareThunk
* t
= (typeof(t
)) thunk
;
795 idxL
= (typeof(idxL
)) left
;
796 idxR
= (typeof(idxR
)) right
;
797 l
= GetSiteName(*idxL
, t
->zoneNames
, t
->zoneNamesCnt
);
798 r
= GetSiteName(*idxR
, t
->zoneNames
, t
->zoneNamesCnt
);
800 lcf
= CFStringCreateWithCString(kCFAllocatorDefault
, l
, kCFStringEncodingUTF8
);
801 rcf
= CFStringCreateWithCString(kCFAllocatorDefault
, r
, kCFStringEncodingUTF8
);
803 result
= (int) CFStringCompareWithOptionsAndLocale(lcf
, rcf
, CFRangeMake(0, CFStringGetLength(lcf
)), kCFCompareNumerically
, NULL
);
814 SortSize(void * thunk
, const void * left
, const void * right
)
816 const mach_memory_info_t
* siteL
;
817 const mach_memory_info_t
* siteR
;
821 idxL
= (typeof(idxL
)) left
;
822 idxR
= (typeof(idxR
)) right
;
823 siteL
= &gSites
[*idxL
];
824 siteR
= &gSites
[*idxR
];
826 if (siteL
->size
> siteR
->size
) return (-1);
827 else if (siteL
->size
< siteR
->size
) return (1);
833 PrintLarge(mach_memory_info_t
*wiredInfo
, unsigned int wiredInfoCnt
,
834 task_zone_info_t
*zoneInfo
, mach_zone_name_t
*zoneNames
,
835 unsigned int zoneCnt
, uint64_t zoneElements
,
836 int (*func
)(void *, const void *, const void *), boolean_t column
)
841 uint64_t elemsTagged
;
843 CFDictionaryRef allKexts
;
844 unsigned int idx
, site
, first
;
845 int sorted
[wiredInfoCnt
];
850 zonetotal
= totalsize
;
854 gSym
= CSSymbolicatorCreateWithMachKernel();
856 allKexts
= OSKextCopyLoadedKextInfo(NULL
, NULL
);
857 gTagDict
= CFDictionaryCreateMutable(
858 kCFAllocatorDefault
, (CFIndex
) 0,
859 (CFDictionaryKeyCallBacks
*) 0,
860 &kCFTypeDictionaryValueCallBacks
);
862 CFDictionaryApplyFunction(allKexts
, &MakeLoadTagKeys
, gTagDict
);
867 for (idx
= 0; idx
< wiredInfoCnt
; idx
++) sorted
[idx
] = idx
;
868 first
= 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
869 struct CompareThunk thunk
;
870 thunk
.zoneNames
= zoneNames
;
871 thunk
.zoneNamesCnt
= zoneCnt
;
872 qsort_r(&sorted
[first
],
873 wiredInfoCnt
- first
,
879 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++)
882 if ((VM_KERN_SITE_COUNTER
& gSites
[site
].flags
)
883 && (VM_KERN_COUNT_WIRED
== gSites
[site
].site
)) top_wired
= gSites
[site
].size
;
884 if (VM_KERN_SITE_HIDE
& gSites
[site
].flags
) continue;
885 if (!((VM_KERN_SITE_WIRED
| VM_KERN_SITE_ZONE
) & gSites
[site
].flags
)) continue;
887 if ((VM_KERN_SITE_ZONE
& gSites
[site
].flags
)
888 && gSites
[site
].zone
< zoneCnt
)
890 elemsTagged
+= gSites
[site
].size
/ zoneInfo
[gSites
[site
].zone
].tzi_elem_size
;
893 if ((gSites
[site
].size
< 1024) && (gSites
[site
].peak
< 1024)) continue;
895 name
= GetSiteName(site
, zoneNames
, zoneCnt
);
896 if (!substr(zname
, znamelen
, name
, strlen(name
))) continue;
899 printf("-------------------------------------------------------------------------------------------------------------\n");
900 printf(" kmod vm peak cur\n");
901 printf("wired memory id tag size waste size\n");
902 printf("-------------------------------------------------------------------------------------------------------------\n");
903 headerPrinted
= true;
905 printf("%-67s", name
);
907 printf("%12d", gSites
[site
].tag
);
909 if (gSites
[site
].peak
) PRINTK(" %10llu", gSites
[site
].peak
);
910 else printf(" %11s", "");
912 if (gSites
[site
].collectable_bytes
) PRINTK(" %5llu", gSites
[site
].collectable_bytes
);
913 else printf(" %6s", "");
915 PRINTK(" %9llu", gSites
[site
].size
);
917 if (!(VM_KERN_SITE_ZONE
& gSites
[site
].flags
)) totalsize
+= gSites
[site
].size
;
924 printf("%-67s", "zones");
928 PRINTK(" %9llu", zonetotal
);
935 snprintf(totalstr
, sizeof(totalstr
), "%lld of %lld", elemsTagged
, zoneElements
);
936 printf("zone tags%100s\n", totalstr
);
938 snprintf(totalstr
, sizeof(totalstr
), "%6.2fM of %6.2fM", totalsize
/ 1024.0 / 1024.0, top_wired
/ 1024.0 / 1024.0);
939 printf("total%104s\n", totalstr
);
941 for (headerPrinted
= false, idx
= 0; idx
< wiredInfoCnt
; idx
++)
944 size
= gSites
[site
].mapped
;
946 if (VM_KERN_SITE_HIDE
& gSites
[site
].flags
) continue;
947 if ((size
== gSites
[site
].size
)
948 && ((VM_KERN_SITE_WIRED
| VM_KERN_SITE_ZONE
) & gSites
[site
].flags
)) continue;
950 name
= GetSiteName(site
, NULL
, 0);
951 if (!substr(zname
, znamelen
, name
, strlen(name
))) continue;
954 printf("-------------------------------------------------------------------------------------------------------------\n");
955 printf(" largest peak cur\n");
956 printf("maps free free size size\n");
957 printf("-------------------------------------------------------------------------------------------------------------\n");
958 headerPrinted
= true;
960 printf("%-55s", name
);
963 if (gSites
[site
].free
) PRINTK(" %10llu", gSites
[site
].free
);
964 else printf(" %11s", "");
965 if (gSites
[site
].largest
) PRINTK(" %10llu", gSites
[site
].largest
);
966 else printf(" %11s", "");
967 if (gSites
[site
].peak
) PRINTK(" %10llu", gSites
[site
].peak
);
968 else printf(" %11s", "");
969 PRINTK(" %16llu", size
);