X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/ef8ad44b9b5d9c6d8c0fa5b5494f449fb6717387..faa687fed273e36ee92ac51d06a94d786084a3b0:/zprint.tproj/zprint.c?ds=inline diff --git a/zprint.tproj/zprint.c b/zprint.tproj/zprint.c index e637a45..104161c 100644 --- a/zprint.tproj/zprint.c +++ b/zprint.tproj/zprint.c @@ -1,28 +1,55 @@ +/* + * Copyright (c) 2009-2016 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ /* * @OSF_COPYRIGHT@ */ -/* +/* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ @@ -38,6 +65,7 @@ * to zones but not currently in use. */ +#include #include #include #include @@ -46,56 +74,89 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define streql(a, b) (strcmp((a), (b)) == 0) #define strneql(a, b, n) (strncmp((a), (b), (n)) == 0) +#define PRINTK(fmt, value) \ + printf(fmt "K", (value) / 1024 ) /* ick */ -static void printzone(); -static void colprintzone(); -static void colprintzoneheader(); -static void printk(); -static int strnlen(); -static boolean_t substr(); +static void usage(void); +static void printzone(mach_zone_name_t *, task_zone_info_t *); +static void colprintzone(mach_zone_name_t *, task_zone_info_t *); +static int find_deltas(mach_zone_name_t *, task_zone_info_t *, task_zone_info_t *, char *, int, int); +static void colprintzoneheader(void); +static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen); + +static int SortName(const void * left, const void * right); +static int SortSize(const void * left, const void * right); +static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, int (*func)(const void *, const void *), boolean_t column); static char *program; +static pid_t pid = 0; +static task_t task = TASK_NULL; +static boolean_t ShowPid = FALSE; + +static boolean_t ShowDeltas = FALSE; static boolean_t ShowWasted = FALSE; +static boolean_t ShowTotal = FALSE; +static boolean_t ShowLarge = TRUE; static boolean_t SortZones = FALSE; static boolean_t ColFormat = TRUE; static boolean_t PrintHeader = TRUE; -static unsigned int totalsize = 0; -static unsigned int totalused = 0; +static unsigned long long totalsize = 0; +static unsigned long long totalused = 0; +static unsigned long long totalsum = 0; +static unsigned long long pidsum = 0; + +static int last_time = 0; + +static char *zname = NULL; +static size_t znamelen = 0; static void -usage() +sigintr(__unused int signum) { - fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [name]\n", program); + last_time = 1; +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p ] [name]\n", program); exit(1); } int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char **argv) { - zone_name_t name_buf[1024]; - zone_name_t *name = name_buf; - unsigned int nameCnt = sizeof name_buf/sizeof name_buf[0]; - zone_info_t info_buf[1024]; - zone_info_t *info = info_buf; - unsigned int infoCnt = sizeof info_buf/sizeof info_buf[0]; - - char *zname = NULL; - int znamelen = 0; + mach_zone_name_t *name = NULL; + unsigned int nameCnt = 0; + task_zone_info_t *info = NULL; + unsigned int infoCnt = 0; + mach_memory_info_t *wiredInfo = NULL; + unsigned int wiredInfoCnt = 0; + task_zone_info_t *max_info = NULL; + char *deltas = NULL; kern_return_t kr; int i, j; + int first_time = 1; + int must_print = 1; + int interval = 1; - if (0 != reexec_to_match_kernel()) { - fprintf(stderr, "Could not re-execute: %d\n", errno); - exit(1); - } + signal(SIGINT, sigintr); program = strrchr(argv[0], '/'); if (program == NULL) @@ -104,10 +165,20 @@ main(argc, argv) program++; for (i = 1; i < argc; i++) { - if (streql(argv[i], "-w")) + if (streql(argv[i], "-d")) + ShowDeltas = TRUE; + else if (streql(argv[i], "-t")) + ShowTotal = TRUE; + else if (streql(argv[i], "-T")) + ShowTotal = FALSE; + else if (streql(argv[i], "-w")) ShowWasted = TRUE; else if (streql(argv[i], "-W")) ShowWasted = FALSE; + else if (streql(argv[i], "-l")) + ShowLarge = TRUE; + else if (streql(argv[i], "-L")) + ShowLarge = FALSE; else if (streql(argv[i], "-s")) SortZones = TRUE; else if (streql(argv[i], "-S")) @@ -118,7 +189,14 @@ main(argc, argv) ColFormat = FALSE; else if (streql(argv[i], "-H")) PrintHeader = FALSE; - else if (streql(argv[i], "--")) { + else if (streql(argv[i], "-p")) { + ShowPid = TRUE; + if (i < argc - 1) { + pid = atoi(argv[i+1]); + i++; + } else + usage(); + } else if (streql(argv[i], "--")) { i++; break; } else if (argv[i][0] == '-') @@ -142,34 +220,89 @@ main(argc, argv) usage(); } - kr = host_zone_info(mach_host_self(), - &name, &nameCnt, &info, &infoCnt); - if (kr != KERN_SUCCESS) { - fprintf(stderr, "%s: host_zone_info: %s\n", - program, mach_error_string(kr)); + if (ShowDeltas) { + SortZones = FALSE; + ColFormat = TRUE; + PrintHeader = TRUE; + } + + if (ShowPid) { + kr = task_for_pid(mach_task_self(), pid, &task); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n", + program, pid, mach_error_string(kr)); + exit(1); + } + } + + for (;;) { + if (ShowPid) { + kr = task_zone_info(task, &name, &nameCnt, &info, &infoCnt); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "%s: task_zone_info: %s\n", + program, mach_error_string(kr)); + exit(1); + } + } else { + mach_zone_info_t *zinfo = NULL; + + kr = mach_memory_info(mach_host_self(), + &name, &nameCnt, &zinfo, &infoCnt, + &wiredInfo, &wiredInfoCnt); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "%s: mach_zone_info: %s\n", + program, mach_error_string(kr)); exit(1); + } + + kr = vm_allocate(mach_task_self(), (vm_address_t *)&info, + infoCnt * sizeof *info, VM_FLAGS_ANYWHERE); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "%s vm_allocate: %s\n", + program, mach_error_string(kr)); + exit(1); + } + for (i = 0; i < infoCnt; i++) { + *(mach_zone_info_t *)(info + i) = zinfo[i]; + info[i].tzi_caller_acct = 0; + info[i].tzi_task_alloc = 0; + info[i].tzi_task_free = 0; + } + kr = vm_deallocate(mach_task_self(), (vm_address_t) zinfo, + (vm_size_t) (infoCnt * sizeof *zinfo)); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "%s: vm_deallocate: %s\n", + program, mach_error_string(kr)); + exit(1); + } } - else if (nameCnt != infoCnt) { - fprintf(stderr, "%s: host_zone_info: counts not equal?\n", + + if (nameCnt != infoCnt) { + fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n", program); exit(1); } + if (first_time) { + deltas = (char *)malloc(infoCnt); + max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info)); + } + if (SortZones) { for (i = 0; i < nameCnt-1; i++) for (j = i+1; j < nameCnt; j++) { - int wastei, wastej; + unsigned long long wastei, wastej; - wastei = (info[i].zi_cur_size - - (info[i].zi_elem_size * - info[i].zi_count)); - wastej = (info[j].zi_cur_size - - (info[j].zi_elem_size * - info[j].zi_count)); + wastei = (info[i].tzi_cur_size - + (info[i].tzi_elem_size * + info[i].tzi_count)); + wastej = (info[j].tzi_cur_size - + (info[j].tzi_elem_size * + info[j].tzi_count)); if (wastej > wastei) { - zone_info_t tinfo; - zone_name_t tname; + task_zone_info_t tinfo; + mach_zone_name_t tname; tinfo = info[i]; info[i] = info[j]; @@ -182,18 +315,31 @@ main(argc, argv) } } - if (ColFormat) { - colprintzoneheader(); + must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time); + if (must_print) { + if (ColFormat) { + if (!first_time) + printf("\n"); + colprintzoneheader(); + } + for (i = 0; i < nameCnt; i++) { + if (deltas[i]) { + if (ColFormat) + colprintzone(&name[i], &info[i]); + else + printzone(&name[i], &info[i]); + } + } } - for (i = 0; i < nameCnt; i++) - if (substr(zname, znamelen, name[i].zn_name, - strnlen(name[i].zn_name, sizeof name[i].zn_name))) - if (ColFormat) - colprintzone(&name[i], &info[i]); - else - printzone(&name[i], &info[i]); - - if ((name != name_buf) && (nameCnt != 0)) { + + if (ShowLarge && first_time) { + PrintLarge(wiredInfo, wiredInfoCnt, + SortZones ? &SortSize : &SortName, ColFormat); + } + + first_time = 0; + + if ((name != NULL) && (nameCnt != 0)) { kr = vm_deallocate(mach_task_self(), (vm_address_t) name, (vm_size_t) (nameCnt * sizeof *name)); if (kr != KERN_SUCCESS) { @@ -203,7 +349,7 @@ main(argc, argv) } } - if ((info != info_buf) && (infoCnt != 0)) { + if ((info != NULL) && (infoCnt != 0)) { kr = vm_deallocate(mach_task_self(), (vm_address_t) info, (vm_size_t) (infoCnt * sizeof *info)); if (kr != KERN_SUCCESS) { @@ -213,37 +359,40 @@ main(argc, argv) } } - if (ShowWasted && PrintHeader) { - printf("TOTAL SIZE = %u\n", totalsize); - printf("TOTAL USED = %u\n", totalused); - printf("TOTAL WASTED = %d\n", totalsize - totalused); + if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) { + kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo, + (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo)); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "%s: vm_deallocate: %s\n", + program, mach_error_string(kr)); + exit(1); + } } - exit(0); -} - -static int -strnlen(s, n) - char *s; - int n; -{ - int len = 0; + if ((ShowWasted||ShowTotal) && PrintHeader && !ShowDeltas) { + printf("TOTAL SIZE = %llu\n", totalsize); + printf("TOTAL USED = %llu\n", totalused); + if (ShowWasted) + printf("TOTAL WASTED = %llu\n", totalsize - totalused); + if (ShowTotal) + printf("TOTAL ALLOCS = %llu\n", totalsum); + } - while ((len < n) && (*s++ != '\0')) - len++; + if (ShowDeltas == FALSE || last_time) + break; - return len; + sleep(interval); + } + exit(0); } static boolean_t -substr(a, alen, b, blen) - char *a; - int alen; - char *b; - int blen; +substr(const char *a, size_t alen, const char *b, size_t blen) { int i; + if (alen > blen) return FALSE; + for (i = 0; i <= blen - alen; i++) if (strneql(a, b+i, alen)) return TRUE; @@ -252,58 +401,62 @@ substr(a, alen, b, blen) } static void -printzone(name, info) - zone_name_t *name; - zone_info_t *info; +printzone(mach_zone_name_t *name, task_zone_info_t *info) { - unsigned int used, size; - - printf("%.*s zone:\n", (int)sizeof name->zn_name, name->zn_name); - printf("\tcur_size: %dK bytes (%d elements)\n", - info->zi_cur_size/1024, - info->zi_cur_size/info->zi_elem_size); - printf("\tmax_size: %dK bytes (%d elements)\n", - info->zi_max_size/1024, - info->zi_max_size/info->zi_elem_size); - printf("\telem_size: %d bytes\n", - info->zi_elem_size); - printf("\t# of elems: %d\n", - info->zi_count); - printf("\talloc_size: %dK bytes (%d elements)\n", - info->zi_alloc_size/1024, - info->zi_alloc_size/info->zi_elem_size); - if (info->zi_pageable) - printf("\tPAGEABLE\n"); - if (info->zi_collectable) + unsigned long long used, size; + + printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name); + printf("\tcur_size: %lluK bytes (%llu elements)\n", + info->tzi_cur_size/1024, + (info->tzi_elem_size == 0) ? 0 : + info->tzi_cur_size/info->tzi_elem_size); + printf("\tmax_size: %lluK bytes (%llu elements)\n", + info->tzi_max_size/1024, + (info->tzi_elem_size == 0) ? 0 : + info->tzi_max_size/info->tzi_elem_size); + printf("\telem_size: %llu bytes\n", + info->tzi_elem_size); + printf("\t# of elems: %llu\n", + info->tzi_count); + printf("\talloc_size: %lluK bytes (%llu elements)\n", + info->tzi_alloc_size/1024, + (info->tzi_elem_size == 0) ? 0 : + info->tzi_alloc_size/info->tzi_elem_size); + if (info->tzi_exhaustible) + printf("\tEXHAUSTIBLE\n"); + if (info->tzi_collectable) printf("\tCOLLECTABLE\n"); - + if (ShowPid && info->tzi_caller_acct) + printf("\tCALLER ACCOUNTED\n"); + if (ShowPid) { + pidsum += info->tzi_task_alloc - info->tzi_task_free; + printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n", + (int)((info->tzi_task_alloc - info->tzi_task_free)/1024), + (info->tzi_elem_size == 0) ? 0 : + (info->tzi_task_alloc - info->tzi_task_free)/info->tzi_elem_size); + } if (ShowWasted) { - totalused += used = info->zi_elem_size * info->zi_count; - totalsize += size = info->zi_cur_size; - printf("\t\t\t\t\tWASTED: %d\n", size - used); + totalused += used = info->tzi_elem_size * info->tzi_count; + totalsize += size = info->tzi_cur_size; + printf("\t\t\t\t\tWASTED: %llu\n", size - used); + } + if (ShowTotal) { + totalsum += info->tzi_sum_size; + printf("\t\t\t\t\tTOTAL: %llu\n", totalsum); + if (ShowPid) + printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum); } } static void -printk(fmt, i) - char *fmt; - int i; -{ - printf(fmt, i / 1024); - putchar('K'); -} - -static void -colprintzone(zone_name, info) - zone_name_t *zone_name; - zone_info_t *info; +colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info) { - char *name = zone_name->zn_name; + char *name = zone_name->mzn_name; int j, namewidth; - unsigned int used, size; + unsigned long long used, size; namewidth = 25; - if (ShowWasted) { + if (ShowWasted || ShowTotal) { namewidth -= 7; } for (j = 0; j < namewidth - 1 && name[j]; j++) { @@ -324,51 +477,402 @@ colprintzone(zone_name, info) putchar(' '); } } - printf("%5d", info->zi_elem_size); - printk("%6d", info->zi_cur_size); - if (info->zi_max_size >= 99999 * 1024) { - printf(" ----"); + printf(" %6llu", info->tzi_elem_size); + PRINTK(" %10llu", info->tzi_cur_size); + if (info->tzi_max_size / 1024 > 9999999) { + printf(" --------"); } else { - printk("%6d", info->zi_max_size); + PRINTK(" %10llu", info->tzi_max_size); } - printf("%7d", info->zi_cur_size / info->zi_elem_size); - if (info->zi_max_size >= 99999 * 1024) { - printf(" ----"); + printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size); + if (info->tzi_max_size / 1024 >= 999999999) { + printf(" ----------"); } else { - printf("%7d", info->zi_max_size / info->zi_elem_size); + printf(" %11llu", info->tzi_max_size / info->tzi_elem_size); } - printf("%6d", info->zi_count); - printk("%5d", info->zi_alloc_size); - printf("%6d", info->zi_alloc_size / info->zi_elem_size); - - totalused += used = info->zi_elem_size * info->zi_count; - totalsize += size = info->zi_cur_size; + printf(" %11llu", info->tzi_count); + PRINTK(" %5llu", info->tzi_alloc_size); + printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size); + + totalused += used = info->tzi_elem_size * info->tzi_count; + totalsize += size = info->tzi_cur_size; + totalsum += info->tzi_sum_size; + + printf(" %c%c%c", + (info->tzi_exhaustible ? 'X' : ' '), + (info->tzi_caller_acct ? 'A' : ' '), + (info->tzi_collectable ? 'C' : ' ')); if (ShowWasted) { - printf("%7d", size - used); + PRINTK(" %8llu", size - used); } - - printf("%c%c\n", - (info->zi_pageable ? 'P' : ' '), - (info->zi_collectable ? 'C' : ' ')); + if (ShowPid) { + printf("%8dK", (int)((info->tzi_task_alloc - info->tzi_task_free)/1024)); + } + if (ShowTotal) { + if (info->tzi_sum_size < 1024) + printf(" %16lluB", info->tzi_sum_size); + else + PRINTK(" %16llu", info->tzi_sum_size); + } + printf("\n"); } static void -colprintzoneheader() +colprintzoneheader(void) { if (! PrintHeader) { return; } - if (ShowWasted) { - printf(" elem cur max cur max%s", - " cur alloc alloc\n"); - printf("zone name size size size #elts #elts%s", - " inuse size count wasted\n"); - } else { - printf(" elem cur max cur%s", - " max cur alloc alloc\n"); - printf("zone name size size size #elts%s", - " #elts inuse size count\n"); - } - printf("-----------------------------------------------%s", - "--------------------------------\n"); + printf("%s elem cur max cur max" + " cur alloc alloc %s%s\n", + (ShowWasted||ShowTotal)? "" : " ", + (ShowWasted)? " ":"", + (ShowPid) ? " PID" : "" ); + printf("zone name%s size size size #elts #elts" + " inuse size count ", (ShowWasted||ShowTotal)? " " : " " ); + if (ShowWasted) + printf(" wasted"); + if (ShowPid) + printf(" Allocs"); + if (ShowTotal) + printf(" Total Allocs"); + printf("\n%s-------------------------------------------------------" + "-----------------------------------------------", + (ShowWasted||ShowTotal)? "" : "-------"); + if (ShowWasted) + printf("----------"); + if (ShowPid) + printf("---------"); + if (ShowTotal) + printf("------------------"); + printf("\n"); +} + +int +find_deltas(mach_zone_name_t *name, task_zone_info_t *info, task_zone_info_t *max_info, + char *deltas, int cnt, int first_time) +{ + int i; + int found_one = 0; + + for (i = 0; i < cnt; i++) { + deltas[i] = 0; + if (substr(zname, znamelen, name[i].mzn_name, + strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) { + if (first_time || info->tzi_cur_size > max_info->tzi_cur_size || + (ShowTotal && ((info->tzi_sum_size >> 1) > max_info->tzi_sum_size))) { + max_info->tzi_cur_size = info->tzi_cur_size; + max_info->tzi_sum_size = info->tzi_sum_size; + deltas[i] = 1; + found_one = 1; + } + } + info++; + max_info++; + } + return(found_one); +} + +/********************************************************************* +*********************************************************************/ + +static char * +kern_vm_tag_name(uint64_t tag) +{ + char * result; + const char * name; + switch (tag) + { + case (VM_KERN_MEMORY_NONE): name = "VM_KERN_MEMORY_NONE"; break; + case (VM_KERN_MEMORY_OSFMK): name = "VM_KERN_MEMORY_OSFMK"; break; + case (VM_KERN_MEMORY_BSD): name = "VM_KERN_MEMORY_BSD"; break; + case (VM_KERN_MEMORY_IOKIT): name = "VM_KERN_MEMORY_IOKIT"; break; + case (VM_KERN_MEMORY_LIBKERN): name = "VM_KERN_MEMORY_LIBKERN"; break; + case (VM_KERN_MEMORY_OSKEXT): name = "VM_KERN_MEMORY_OSKEXT"; break; + case (VM_KERN_MEMORY_KEXT): name = "VM_KERN_MEMORY_KEXT"; break; + case (VM_KERN_MEMORY_IPC): name = "VM_KERN_MEMORY_IPC"; break; + case (VM_KERN_MEMORY_STACK): name = "VM_KERN_MEMORY_STACK"; break; + case (VM_KERN_MEMORY_CPU): name = "VM_KERN_MEMORY_CPU"; break; + case (VM_KERN_MEMORY_PMAP): name = "VM_KERN_MEMORY_PMAP"; break; + case (VM_KERN_MEMORY_PTE): name = "VM_KERN_MEMORY_PTE"; break; + case (VM_KERN_MEMORY_ZONE): name = "VM_KERN_MEMORY_ZONE"; break; + case (VM_KERN_MEMORY_KALLOC): name = "VM_KERN_MEMORY_KALLOC"; break; + case (VM_KERN_MEMORY_COMPRESSOR): name = "VM_KERN_MEMORY_COMPRESSOR"; break; + case (VM_KERN_MEMORY_COMPRESSED_DATA): name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break; + case (VM_KERN_MEMORY_PHANTOM_CACHE): name = "VM_KERN_MEMORY_PHANTOM_CACHE"; break; + case (VM_KERN_MEMORY_WAITQ): name = "VM_KERN_MEMORY_WAITQ"; break; + case (VM_KERN_MEMORY_DIAG): name = "VM_KERN_MEMORY_DIAG"; break; + case (VM_KERN_MEMORY_LOG): name = "VM_KERN_MEMORY_LOG"; break; + case (VM_KERN_MEMORY_FILE): name = "VM_KERN_MEMORY_FILE"; break; + case (VM_KERN_MEMORY_MBUF): name = "VM_KERN_MEMORY_MBUF"; break; + case (VM_KERN_MEMORY_UBC): name = "VM_KERN_MEMORY_UBC"; break; + case (VM_KERN_MEMORY_SECURITY): name = "VM_KERN_MEMORY_SECURITY"; break; + case (VM_KERN_MEMORY_MLOCK): name = "VM_KERN_MEMORY_MLOCK"; break; + case (VM_KERN_MEMORY_REASON): name = "VM_KERN_MEMORY_REASON"; break; + case (VM_KERN_MEMORY_SKYWALK): name = "VM_KERN_MEMORY_SKYWALK"; break; + case (VM_KERN_MEMORY_LTABLE): name = "VM_KERN_MEMORY_LTABLE"; break; + case (VM_KERN_MEMORY_ANY): name = "VM_KERN_MEMORY_ANY"; break; + default: name = NULL; break; + } + if (name) asprintf(&result, "%s", name); + else asprintf(&result, "VM_KERN_MEMORY_%lld", tag); + return (result); + } + +static char * +kern_vm_counter_name(uint64_t tag) +{ + char * result; + const char * name; + switch (tag) + { + case (VM_KERN_COUNT_MANAGED): name = "VM_KERN_COUNT_MANAGED"; break; + case (VM_KERN_COUNT_RESERVED): name = "VM_KERN_COUNT_RESERVED"; break; + case (VM_KERN_COUNT_WIRED): name = "VM_KERN_COUNT_WIRED"; break; + case (VM_KERN_COUNT_WIRED_MANAGED): name = "VM_KERN_COUNT_WIRED_MANAGED"; break; + case (VM_KERN_COUNT_STOLEN): name = "VM_KERN_COUNT_STOLEN"; break; + case (VM_KERN_COUNT_LOPAGE): name = "VM_KERN_COUNT_LOPAGE"; break; + case (VM_KERN_COUNT_MAP_KERNEL): name = "VM_KERN_COUNT_MAP_KERNEL"; break; + case (VM_KERN_COUNT_MAP_ZONE): name = "VM_KERN_COUNT_MAP_ZONE"; break; + case (VM_KERN_COUNT_MAP_KALLOC): name = "VM_KERN_COUNT_MAP_KALLOC"; break; + default: name = NULL; break; + } + if (name) asprintf(&result, "%s", name); + else asprintf(&result, "VM_KERN_COUNT_%lld", tag); + return (result); +} + +static void +MakeLoadTagKeys(const void * key, const void * value, void * context) +{ + CFMutableDictionaryRef newDict = context; + CFDictionaryRef kextInfo = value; + CFNumberRef loadTag; + uint32_t loadTagValue; + + loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey)); + CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue); + key = (const void *)(uintptr_t) loadTagValue; + CFDictionarySetValue(newDict, key, value); +} + +static CSSymbolicatorRef gSym; +static CFMutableDictionaryRef gTagDict; +static mach_memory_info_t * gSites; + +static char * +GetSiteName(int siteIdx) +{ + const char * name; + char * result; + mach_vm_address_t addr; + CFDictionaryRef kextInfo; + CFStringRef bundleID; + uint32_t type; + + const mach_memory_info_t * site; + const char * fileName; + CSSymbolRef symbol; + const char * symbolName; + CSSourceInfoRef sourceInfo; + + name = NULL; + result = NULL; + site = &gSites[siteIdx]; + addr = site->site; + type = (VM_KERN_SITE_TYPE & site->flags); + switch (type) + { + case VM_KERN_SITE_TAG: + result = kern_vm_tag_name(addr); + break; + + case VM_KERN_SITE_COUNTER: + result = kern_vm_counter_name(addr); + break; + + case VM_KERN_SITE_KMOD: + kextInfo = CFDictionaryGetValue(gTagDict, (const void *)(uintptr_t) addr); + if (kextInfo) + { + bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey); + name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8); + // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey)); + } + asprintf(&result, "%-64s%3lld", name ? name : "(unknown kmod)", addr); + break; + + case VM_KERN_SITE_KERNEL: + symbolName = NULL; + if (addr) + { + symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow); + symbolName = CSSymbolGetName(symbol); + } + if (symbolName) + { + asprintf(&result, "%s", symbolName); + sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow); + fileName = CSSourceInfoGetPath(sourceInfo); + if (fileName) printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo)); + } + else + { + asprintf(&result, "site 0x%qx", addr); + } + break; + default: + asprintf(&result, ""); + break; + } + + return (result); +} + +static int +SortName(const void * left, const void * right) +{ + const int * idxL; + const int * idxR; + char * l; + char * r; + int result; + + idxL = (typeof(idxL)) left; + idxR = (typeof(idxR)) right; + l = GetSiteName(*idxL); + r = GetSiteName(*idxR); + + result = strcmp(l, r); + free(l); + free(r); + + return (result); +} + +static int +SortSize(const void * left, const void * right) +{ + const mach_memory_info_t * siteL; + const mach_memory_info_t * siteR; + const int * idxL; + const int * idxR; + + idxL = (typeof(idxL)) left; + idxR = (typeof(idxR)) right; + siteL = &gSites[*idxL]; + siteR = &gSites[*idxR]; + + if (siteL->size > siteR->size) return (-1); + else if (siteL->size < siteR->size) return (1); + return (0); +} + + +static void +PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, + int (*func)(const void *, const void *), boolean_t column) +{ + uint64_t zonetotal; + uint64_t top_wired; + + CFDictionaryRef allKexts; + unsigned int idx, site, first; + int sorted[wiredInfoCnt]; + char totalstr[40]; + char * name; + bool headerPrinted; + + zonetotal = totalsize; + + gSites = wiredInfo; + + gSym = CSSymbolicatorCreateWithMachKernel(); + + allKexts = OSKextCopyLoadedKextInfo(NULL, NULL); + gTagDict = CFDictionaryCreateMutable( + kCFAllocatorDefault, (CFIndex) 0, + (CFDictionaryKeyCallBacks *) 0, + &kCFTypeDictionaryValueCallBacks); + + CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict); + CFRelease(allKexts); + + top_wired = 0; + + for (idx = 0; idx < wiredInfoCnt; idx++) sorted[idx] = idx; + first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC + qsort(&sorted[first], + wiredInfoCnt - first, + sizeof(sorted[0]), + func); + + for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) + { + site = sorted[idx]; + if (!gSites[site].size) continue; + if (VM_KERN_COUNT_WIRED == gSites[site].site) top_wired = gSites[site].size; + if (VM_KERN_SITE_HIDE & gSites[site].flags) continue; + if (!(VM_KERN_SITE_WIRED & gSites[site].flags)) continue; + + name = GetSiteName(site); + if (!substr(zname, znamelen, name, strlen(name))) continue; + if (!headerPrinted) + { + printf("-------------------------------------------------------------------------------------------------------------\n"); + printf(" kmod vm cur\n"); + printf("wired memory id tag size\n"); + printf("-------------------------------------------------------------------------------------------------------------\n"); + headerPrinted = true; + } + printf("%-67s", name); + free(name); + printf("%12d", site); + + printf(" %11s", ""); + PRINTK(" %12llu", gSites[site].size); + totalsize += gSites[site].size; + + printf("\n"); + } + + if (!znamelen) + { + printf("%-67s", "zones"); + printf("%12s", ""); + printf(" %11s", ""); + PRINTK(" %12llu", zonetotal); + printf("\n"); + } + if (headerPrinted) + { + snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0); + printf("total%100s\n", totalstr); + } + for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) + { + site = sorted[idx]; + if (!gSites[site].size) continue; + if (VM_KERN_SITE_HIDE & gSites[site].flags) continue; + if (VM_KERN_SITE_WIRED & gSites[site].flags) continue; + + name = GetSiteName(site); + if (!substr(zname, znamelen, name, strlen(name))) continue; + if (!headerPrinted) + { + printf("-------------------------------------------------------------------------------------------------------------\n"); + printf(" largest\n"); + printf("maps free free size\n"); + printf("-------------------------------------------------------------------------------------------------------------\n"); + headerPrinted = true; + } + printf("%-67s", name); + free(name); + + PRINTK(" %10llu", gSites[site].free); + PRINTK(" %10llu", gSites[site].largest); + PRINTK(" %12llu", gSites[site].size); + + printf("\n"); + } }