+/*
+ * 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.
*/
* to zones but not currently in use.
*/
+#include <vm_statistics.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mach/mach_error.h>
#include <libutil.h>
#include <errno.h>
+#include <sysexits.h>
+#include <getopt.h>
+#include <malloc/malloc.h>
+#include <Kernel/IOKit/IOKitDebug.h>
+#include <Kernel/libkern/OSKextLibPrivate.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/kext/OSKext.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreSymbolication/CoreSymbolication.h>
#define streql(a, b) (strcmp((a), (b)) == 0)
#define strneql(a, b, n) (strncmp((a), (b), (n)) == 0)
-
-static void printzone();
-static void colprintzone();
-static void colprintzoneheader();
-static void printk();
-static int strnlen();
-static boolean_t substr();
+#define PRINTK(fmt, value) \
+ printf(fmt "K", (value) / 1024 ) /* ick */
+
+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(void * thunk, const void * left, const void * right);
+static int SortSize(void * thunk, const void * left, const void * right);
+static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
+ task_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames,
+ unsigned int zoneCnt, uint64_t zoneElements,
+ int (*func)(void *, 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 <pid>] [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;
+ uint64_t zoneElements;
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)
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"))
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] == '-')
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];
}
}
- if (ColFormat) {
- colprintzoneheader();
+ must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
+ zoneElements = 0;
+ 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]);
+ zoneElements += info[i].tzi_count;
+ }
+ }
+ }
+
+ if (ShowLarge && first_time) {
+ PrintLarge(wiredInfo, wiredInfoCnt, &info[0], &name[0],
+ nameCnt, zoneElements,
+ SortZones ? &SortSize : &SortName, ColFormat);
}
- 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)) {
+
+ 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) {
}
}
- 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) {
}
}
- 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;
}
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++) {
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 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_BOOT): name = "VM_KERN_COUNT_WIRED_BOOT"; 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_BOOT_STOLEN): name = "VM_KERN_COUNT_BOOT_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, mach_zone_name_t * zoneNames, unsigned int zoneNamesCnt)
+{
+ const char * name;
+ uintptr_t kmodid;
+ char * result;
+ char * append;
+ 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);
+ kmodid = 0;
+
+ if (VM_KERN_SITE_NAMED & site->flags)
+ {
+ asprintf(&result, "%s", &site->name[0]);
+ }
+ else 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:
+
+ kmodid = (uintptr_t) addr;
+ kextInfo = CFDictionaryGetValue(gTagDict, (const void *)kmodid);
+ if (kextInfo)
+ {
+ bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey);
+ name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8);
+ // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
+ }
+
+ if (name) asprintf(&result, "%s", name);
+ else asprintf(&result, "(unloaded kmod)");
+ 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;
+ }
+
+ if (result
+ && (VM_KERN_SITE_ZONE & site->flags)
+ && zoneNames
+ && (site->zone < zoneNamesCnt))
+ {
+ size_t namelen, zonelen;
+ namelen = strlen(result);
+ zonelen = strnlen(zoneNames[site->zone].mzn_name, sizeof(zoneNames[site->zone].mzn_name));
+ if (((namelen + zonelen) > 61) && (zonelen < 61)) namelen = (61 - zonelen);
+ asprintf(&append, "%.*s[%.*s]",
+ (int)namelen,
+ result,
+ (int)zonelen,
+ zoneNames[site->zone].mzn_name);
+ free(result);
+ result = append;
+ }
+ if (result && kmodid)
+ {
+ asprintf(&append, "%-64s%3ld", result, kmodid);
+ free(result);
+ result = append;
+ }
+
+ return (result);
+}
+
+struct CompareThunk
+{
+ mach_zone_name_t *zoneNames;
+ unsigned int zoneNamesCnt;
+};
+
+static int
+SortName(void * thunk, const void * left, const void * right)
+{
+ const struct CompareThunk * t = (typeof(t)) thunk;
+ const int * idxL;
+ const int * idxR;
+ char * l;
+ char * r;
+ CFStringRef lcf;
+ CFStringRef rcf;
+ int result;
+
+ idxL = (typeof(idxL)) left;
+ idxR = (typeof(idxR)) right;
+ l = GetSiteName(*idxL, t->zoneNames, t->zoneNamesCnt);
+ r = GetSiteName(*idxR, t->zoneNames, t->zoneNamesCnt);
+
+ lcf = CFStringCreateWithCString(kCFAllocatorDefault, l, kCFStringEncodingUTF8);
+ rcf = CFStringCreateWithCString(kCFAllocatorDefault, r, kCFStringEncodingUTF8);
+
+ result = (int) CFStringCompareWithOptionsAndLocale(lcf, rcf, CFRangeMake(0, CFStringGetLength(lcf)), kCFCompareNumerically, NULL);
+
+ CFRelease(lcf);
+ CFRelease(rcf);
+ free(l);
+ free(r);
+
+ return (result);
+}
+
+static int
+SortSize(void * thunk, 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,
+ task_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames,
+ unsigned int zoneCnt, uint64_t zoneElements,
+ int (*func)(void *, const void *, const void *), boolean_t column)
+{
+ uint64_t zonetotal;
+ uint64_t top_wired;
+ uint64_t size;
+ uint64_t elemsTagged;
+
+ 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
+ struct CompareThunk thunk;
+ thunk.zoneNames = zoneNames;
+ thunk.zoneNamesCnt = zoneCnt;
+ qsort_r(&sorted[first],
+ wiredInfoCnt - first,
+ sizeof(sorted[0]),
+ &thunk,
+ func);
+
+ elemsTagged = 0;
+ for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
+ {
+ site = sorted[idx];
+ if ((VM_KERN_SITE_COUNTER & gSites[site].flags)
+ && (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 | VM_KERN_SITE_ZONE) & gSites[site].flags)) continue;
+
+ if ((VM_KERN_SITE_ZONE & gSites[site].flags)
+ && gSites[site].zone < zoneCnt)
+ {
+ elemsTagged += gSites[site].size / zoneInfo[gSites[site].zone].tzi_elem_size;
}
- printf("-----------------------------------------------%s",
- "--------------------------------\n");
+
+ if ((gSites[site].size < 1024) && (gSites[site].peak < 1024)) continue;
+
+ name = GetSiteName(site, zoneNames, zoneCnt);
+ if (!substr(zname, znamelen, name, strlen(name))) continue;
+ if (!headerPrinted)
+ {
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ printf(" kmod vm peak cur\n");
+ printf("wired memory id tag size waste size\n");
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ headerPrinted = true;
+ }
+ printf("%-67s", name);
+ free(name);
+ printf("%12d", gSites[site].tag);
+
+ if (gSites[site].peak) PRINTK(" %10llu", gSites[site].peak);
+ else printf(" %11s", "");
+
+ if (gSites[site].collectable_bytes) PRINTK(" %5llu", gSites[site].collectable_bytes);
+ else printf(" %6s", "");
+
+ PRINTK(" %9llu", gSites[site].size);
+
+ if (!(VM_KERN_SITE_ZONE & gSites[site].flags)) totalsize += gSites[site].size;
+
+ printf("\n");
+ }
+
+ if (!znamelen)
+ {
+ printf("%-67s", "zones");
+ printf("%12s", "");
+ printf(" %11s", "");
+ printf(" %6s", "");
+ PRINTK(" %9llu", zonetotal);
+ printf("\n");
+ }
+ if (headerPrinted)
+ {
+ if (elemsTagged)
+ {
+ snprintf(totalstr, sizeof(totalstr), "%lld of %lld", elemsTagged, zoneElements);
+ printf("zone tags%100s\n", totalstr);
+ }
+ snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0);
+ printf("total%104s\n", totalstr);
+ }
+ for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
+ {
+ site = sorted[idx];
+ size = gSites[site].mapped;
+ if (!size) continue;
+ if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
+ if ((size == gSites[site].size)
+ && ((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) continue;
+
+ name = GetSiteName(site, NULL, 0);
+ if (!substr(zname, znamelen, name, strlen(name))) continue;
+ if (!headerPrinted)
+ {
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ printf(" largest peak cur\n");
+ printf("maps free free size size\n");
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ headerPrinted = true;
+ }
+ printf("%-55s", name);
+ free(name);
+
+ if (gSites[site].free) PRINTK(" %10llu", gSites[site].free);
+ else printf(" %11s", "");
+ if (gSites[site].largest) PRINTK(" %10llu", gSites[site].largest);
+ else printf(" %11s", "");
+ if (gSites[site].peak) PRINTK(" %10llu", gSites[site].peak);
+ else printf(" %11s", "");
+ PRINTK(" %16llu", size);
+
+ printf("\n");
+ }
}