aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-07-02 11:35:46 -0400
committerCameron Katri <me@cameronkatri.com>2021-07-02 11:35:46 -0400
commit7e206fa669783bf7aeee0c047e21e7f2606c92e7 (patch)
tree57526a9f7e389be83ae7593192b2daf15fb78c43
parent5390ec5a5b7a59cb52f01cf6d053978b2f44460c (diff)
downloadapple_cmds-7e206fa669783bf7aeee0c047e21e7f2606c92e7.tar.gz
apple_cmds-7e206fa669783bf7aeee0c047e21e7f2606c92e7.tar.zst
apple_cmds-7e206fa669783bf7aeee0c047e21e7f2606c92e7.zip
system_cmds: 880.120.1
-rw-r--r--system_cmds/.apple_version2
-rw-r--r--system_cmds/zprint.tproj/zprint.c387
2 files changed, 325 insertions, 64 deletions
diff --git a/system_cmds/.apple_version b/system_cmds/.apple_version
index f6c5d7f..b7119ae 100644
--- a/system_cmds/.apple_version
+++ b/system_cmds/.apple_version
@@ -1 +1 @@
-880.100.5
+880.120.1
diff --git a/system_cmds/zprint.tproj/zprint.c b/system_cmds/zprint.tproj/zprint.c
index 97f31e4..20cf2ca 100644
--- a/system_cmds/zprint.tproj/zprint.c
+++ b/system_cmds/zprint.tproj/zprint.c
@@ -88,18 +88,61 @@
#ifndef VM_KERN_SITE_ZONE_VIEW
#define VM_KERN_SITE_ZONE_VIEW 0x00001000
#endif
+#ifndef KALLOC_SIZECLASSES
+#define KALLOC_SIZECLASSES 32
+/*
+ * Type of kalloc zone
+ */
+__options_decl(kalloc_zone_type, uint32_t, {
+ KALLOC_ZONE_NONE = 0x00000000, /* Not kalloc zone */
+ KALLOC_ZONE_DEFAULT = 0x00000001, /* default.kalloc zone */
+ KALLOC_ZONE_DATA = 0x00000002, /* data.kalloc zone */
+ KALLOC_ZONE_KEXT = 0x00000004, /* kext.kalloc zone*/
+ KALLOC_ZONE_TYPE = 0x00000008, /* kalloc.type zone */
+#define KALLOC_ZONE_COUNT 5
+});
+const char *kalloc_zone_names[KALLOC_ZONE_COUNT] = {
+ "",
+ "default.kalloc.",
+ "data.kalloc.",
+ "kext.kalloc.",
+ "kalloc.type"
+};
+#endif
#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 */
+/*
+ * Globals that are used to accumulate kalloc zone info
+ */
+mach_zone_name_t *kalloc_zone_name = NULL;
+mach_zone_info_t *kalloc_zone_info = NULL;
+char *kalloc_zone_delta = NULL;
+uint64_t kalloc_info_idx = 0;
+
static void usage(FILE *stream);
static void printzone(mach_zone_name_t *, mach_zone_info_t *);
static void colprintzone(mach_zone_name_t *, mach_zone_info_t *);
-static int find_deltas(mach_zone_name_t *, mach_zone_info_t *, mach_zone_info_t *, char *, int, int);
static void colprintzoneheader(void);
+static void PrintZones(mach_zone_name_t *names, mach_zone_info_t *info,
+ unsigned int count, char *deltas,
+ uint64_t *zoneElements);
static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen);
+static int find_deltas(mach_zone_name_t *, mach_zone_info_t *, mach_zone_info_t *,
+ char *, int, int);
+static bool sort_zones(mach_zone_name_t **name, mach_zone_info_t **info,
+ char **deltas, unsigned int *infoCnt);
+static void free_zone_info_resources(mach_zone_name_t *name,
+ mach_zone_info_t *info,
+ unsigned int count, bool vm);
+static uint64_t get_kalloc_info_idx(uint64_t sizeclass);
+static char *get_kalloc_sizep(char *name);
+static kalloc_zone_type get_zone_type(mach_zone_name_t name);
+static void coalesce_kalloc(mach_zone_name_t name, mach_zone_info_t info,
+ char *deltas);
static int SortName(void * thunk, const void * left, const void * right);
static int SortSize(void * thunk, const void * left, const void * right);
@@ -117,6 +160,7 @@ static boolean_t ShowLarge = TRUE;
static boolean_t SortZones = FALSE;
static boolean_t ColFormat = TRUE;
static boolean_t PrintHeader = TRUE;
+static kalloc_zone_type CoalesceKalloc = KALLOC_ZONE_DEFAULT;
static unsigned long long totalsize = 0;
static unsigned long long totalused = 0;
@@ -187,7 +231,7 @@ sigintr(__unused int signum)
static void
usage(FILE *stream)
{
- fprintf(stream, "usage: %s [-w] [-s] [-c] [-h] [-H] [-t] [-d] [-l] [-L] [name]\n\n", program);
+ fprintf(stream, "usage: %s [-w] [-s] [-c] [-h] [-H] [-t] [-d] [-l] [-L] [-k] [-kt] [-kd] [name]\n\n", program);
fprintf(stream, "\t-w\tshow wasted memory for each zone\n");
fprintf(stream, "\t-s\tsort zones by wasted memory\n");
fprintf(stream, "\t-c\t(default) display output formatted in columns\n");
@@ -197,6 +241,9 @@ usage(FILE *stream)
fprintf(stream, "\t-d\tdisplay deltas over time\n");
fprintf(stream, "\t-l\t(default) display wired memory info after zone info\n");
fprintf(stream, "\t-L\tdo not show wired memory info, only show zone info\n");
+ fprintf(stream, "\t-k\tcoalesce all kalloc zones for specific size\n");
+ fprintf(stream, "\t-kt\tcoalesce kalloc type/kext zones with default\n");
+ fprintf(stream, "\t-kd\tcoalesce kalloc data zones with default\n");
fprintf(stream, "\nAny option (including default options) can be overridden by specifying the option in upper-case.\n\n");
exit(stream != stdout);
}
@@ -213,9 +260,11 @@ main(int argc, char **argv)
mach_zone_info_t *max_info = NULL;
char *deltas = NULL;
uint64_t zoneElements;
+ unsigned all_infoCnt = 0;
+ bool replaced_resources = false;
kern_return_t kr;
- int i, j;
+ int i;
int first_time = 1;
int must_print = 1;
int interval = 1;
@@ -256,6 +305,12 @@ main(int argc, char **argv)
usage(stdout);
} else if (streql(argv[i], "-H")) {
PrintHeader = FALSE;
+ } else if (streql(argv[i], "-k")) {
+ CoalesceKalloc |= (KALLOC_ZONE_TYPE | KALLOC_ZONE_KEXT | KALLOC_ZONE_DATA);
+ } else if (streql(argv[i], "-kt")) {
+ CoalesceKalloc |= (KALLOC_ZONE_TYPE | KALLOC_ZONE_KEXT);
+ } else if (streql(argv[i], "-kd")) {
+ CoalesceKalloc |= KALLOC_ZONE_DATA;
} else if (streql(argv[i], "--")) {
i++;
break;
@@ -311,40 +366,36 @@ main(int argc, char **argv)
exit(1);
}
- if (first_time) {
- deltas = (char *)malloc(infoCnt);
- max_info = (mach_zone_info_t *)malloc((infoCnt * sizeof *info));
- }
+ all_infoCnt = infoCnt;
+ if (CoalesceKalloc != KALLOC_ZONE_DEFAULT) {
+ all_infoCnt += KALLOC_SIZECLASSES;
+ kalloc_zone_name = (mach_zone_name_t *) calloc(KALLOC_SIZECLASSES, sizeof *name);
+ kalloc_zone_info = (mach_zone_info_t *) calloc(KALLOC_SIZECLASSES, sizeof *info);
+ if (!kalloc_zone_name || !kalloc_zone_info) {
+ fprintf(stderr, "%s: calloc failed to allocate memory\n", program);
+ exit(1);
+ }
+ }
- if (SortZones) {
- for (i = 0; i < nameCnt - 1; i++) {
- for (j = i + 1; j < nameCnt; j++) {
- unsigned long long wastei, wastej;
-
- wastei = (info[i].mzi_cur_size -
- (info[i].mzi_elem_size *
- info[i].mzi_count));
- wastej = (info[j].mzi_cur_size -
- (info[j].mzi_elem_size *
- info[j].mzi_count));
-
- if (wastej > wastei) {
- mach_zone_info_t tinfo;
- mach_zone_name_t tname;
-
- tinfo = info[i];
- info[i] = info[j];
- info[j] = tinfo;
-
- tname = name[i];
- name[i] = name[j];
- name[j] = tname;
- }
- }
- }
+ if (first_time) {
+ deltas = (char *)malloc(all_infoCnt);
+ max_info = (mach_zone_info_t *)malloc((infoCnt * sizeof *info));
+ kalloc_zone_delta = deltas + infoCnt;
+ if (!deltas || !max_info) {
+ fprintf(stderr, "%s: malloc failed to allocate memory\n", program);
+ exit(1);
+ }
}
must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
+
+ if (SortZones) {
+ /*
+ * All parameters are updated when a additional buffer is required
+ * for sorting.
+ */
+ replaced_resources = sort_zones(&name, &info, &deltas, &infoCnt);
+ }
zoneElements = 0;
if (must_print) {
if (ColFormat) {
@@ -353,16 +404,11 @@ main(int argc, char **argv)
}
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].mzi_count;
- }
- }
+ PrintZones(name, info, infoCnt, deltas, &zoneElements);
+ if (!SortZones && (CoalesceKalloc != KALLOC_ZONE_DEFAULT)) {
+ PrintZones(kalloc_zone_name, kalloc_zone_info, KALLOC_SIZECLASSES,
+ kalloc_zone_delta, &zoneElements);
+ }
}
if (ShowLarge && first_time) {
@@ -372,26 +418,15 @@ main(int argc, char **argv)
}
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) {
- fprintf(stderr, "%s: vm_deallocate: %s\n",
- program, mach_error_string(kr));
- exit(1);
- }
- }
-
- 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) {
- fprintf(stderr, "%s: vm_deallocate: %s\n",
- program, mach_error_string(kr));
- exit(1);
- }
- }
+
+ /*
+ * Clean up resources and reset deltas
+ */
+ free_zone_info_resources(name, info, infoCnt, !replaced_resources);
+ if (CoalesceKalloc != KALLOC_ZONE_DEFAULT) {
+ bzero(kalloc_zone_delta, KALLOC_SIZECLASSES);
+ kalloc_info_idx = 0;
+ }
if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) {
kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo,
@@ -577,6 +612,21 @@ colprintzone(mach_zone_name_t *zone_name, mach_zone_info_t *info)
printf("\n");
}
+static void
+PrintZones(mach_zone_name_t *names, mach_zone_info_t *info,
+ unsigned int count, char *deltas, uint64_t *zoneElements)
+{
+ for (unsigned int i = 0; i < count; i++) {
+ if (deltas[i]) {
+ if (ColFormat) {
+ colprintzone(&names[i], &info[i]);
+ } else {
+ printzone(&names[i], &info[i]);
+ }
+ *zoneElements += info[i].mzi_count;
+ }
+ }
+}
static void
colprintzoneheader(void)
@@ -608,6 +658,209 @@ colprintzoneheader(void)
printf("\n");
}
+static void
+free_zone_info_resources(mach_zone_name_t *name, mach_zone_info_t *info,
+ unsigned int count, bool vm)
+{
+ if (!vm) {
+ free(name);
+ free(info);
+ return;
+ }
+
+ kern_return_t kr;
+ if ((name != NULL) && (count != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) name,
+ (vm_size_t) (count * sizeof *name));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if ((info != NULL) && (count != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) info,
+ (vm_size_t) (count * sizeof *info));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if (CoalesceKalloc != KALLOC_ZONE_DEFAULT) {
+ free(kalloc_zone_name);
+ free(kalloc_zone_info);
+ }
+}
+
+/*
+ * Sort zones based on wasted memory (frag size + free size).
+ */
+static bool
+sort_zones(mach_zone_name_t **name, mach_zone_info_t **info, char **deltas,
+ unsigned int *infoCnt)
+{
+ unsigned int i, j;
+ mach_zone_name_t *all_name = *name;
+ mach_zone_info_t *all_info = *info;
+ char *all_deltas = *deltas;
+ unsigned int all_infoCnt = *infoCnt;
+ bool replaced_resources = false;
+ /*
+ * Combine accumulated kalloc zone info array with other
+ */
+ if (CoalesceKalloc != KALLOC_ZONE_DEFAULT) {
+ unsigned int tinfoCnt = all_infoCnt;
+ all_infoCnt += KALLOC_SIZECLASSES;
+ all_name = malloc(sizeof(mach_zone_name_t) * all_infoCnt);
+ all_info = malloc(sizeof(mach_zone_info_t) * all_infoCnt);
+ if (!all_name || !all_info) {
+ fprintf(stderr, "%s: malloc failed to allocate memory\n", program);
+ exit(1);
+ }
+
+ size_t copy_size = sizeof(mach_zone_name_t) * tinfoCnt;
+ memcpy(all_name, *name, copy_size);
+ copy_size = sizeof(mach_zone_name_t) * KALLOC_SIZECLASSES;
+ memcpy(all_name + tinfoCnt, kalloc_zone_name, copy_size);
+
+ copy_size = sizeof(mach_zone_info_t) * tinfoCnt;
+ memcpy(all_info, *info, copy_size);
+ copy_size = sizeof(mach_zone_info_t) * KALLOC_SIZECLASSES;
+ memcpy(all_info + tinfoCnt, kalloc_zone_info, copy_size);
+
+ free_zone_info_resources(*name, *info, tinfoCnt, true);
+ replaced_resources = true;
+ }
+ for (i = 0; i < all_infoCnt - 1; i++) {
+ for (j = i + 1; j < all_infoCnt; j++) {
+ unsigned long long wastei, wastej;
+
+ wastei = (all_info[i].mzi_cur_size -
+ (all_info[i].mzi_elem_size *
+ all_info[i].mzi_count));
+ wastej = (all_info[j].mzi_cur_size -
+ (all_info[j].mzi_elem_size *
+ all_info[j].mzi_count));
+
+ if (wastej > wastei) {
+ mach_zone_info_t tinfo;
+ mach_zone_name_t tname;
+ char tdelta;
+
+ tinfo = all_info[i];
+ all_info[i] = all_info[j];
+ all_info[j] = tinfo;
+
+ tname = all_name[i];
+ all_name[i] = all_name[j];
+ all_name[j] = tname;
+
+ tdelta = all_deltas[i];
+ all_deltas[i] = all_deltas[j];
+ all_deltas[j] = tdelta;
+
+ }
+ }
+ }
+ *name = all_name;
+ *info = all_info;
+ *deltas = all_deltas;
+ *infoCnt = all_infoCnt;
+ return replaced_resources;
+}
+
+/*
+ * Returns index in kalloc_zone_info with matching sizeclass.
+ */
+static uint64_t
+get_kalloc_info_idx(uint64_t sizeclass)
+{
+ for (uint64_t i = 0; i < kalloc_info_idx; i++) {
+ mach_zone_info_t kzi = kalloc_zone_info[i];
+ if (kzi.mzi_elem_size == sizeclass) {
+ return i;
+ }
+ }
+ assert(kalloc_info_idx < KALLOC_SIZECLASSES - 1);
+ return kalloc_info_idx++;
+}
+
+/*
+ * In Azul size from name and element size can be different due
+ * to slack space redistribution, therefore use size from name.
+ */
+static char *
+get_kalloc_sizep(char *name)
+{
+ for (uint64_t i = strlen(name); i > 0; i--) {
+ if (name[i] == '.') {
+ return &name[i+1];
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Determine kalloc type for zone based on name.
+ */
+static kalloc_zone_type
+get_zone_type(mach_zone_name_t name)
+{
+ kalloc_zone_type type = KALLOC_ZONE_NONE;
+ for (uint32_t i = 1; i < KALLOC_ZONE_COUNT; i++) {
+ const char *kalloc_name = kalloc_zone_names[i];
+ if (strncmp(name.mzn_name, kalloc_name, strlen(kalloc_name)) == 0) {
+ type = 1 << (i - 1);
+ break;
+ }
+ }
+ return type;
+}
+
+/*
+ * Aggregate zone info's of requested kalloc zones.
+ */
+static void
+coalesce_kalloc(mach_zone_name_t name, mach_zone_info_t info, char *deltas)
+{
+ kalloc_zone_type kalloc_type = get_zone_type(name);
+ if (kalloc_type == KALLOC_ZONE_NONE) {
+ return;
+ }
+
+ if (kalloc_type & CoalesceKalloc) {
+ uint64_t idx = get_kalloc_info_idx(info.mzi_elem_size);
+ mach_zone_info_t *kzi = kalloc_zone_info + idx;
+ mach_zone_name_t *kzn = kalloc_zone_name + idx;
+ if (*deltas) {
+ kalloc_zone_delta[idx] = 1;
+ *deltas = 0;
+ }
+ kzi->mzi_count += info.mzi_count;
+ kzi->mzi_cur_size += info.mzi_cur_size;
+ if (idx == kalloc_info_idx - 1) {
+ /*
+ * First time assignments for specific size
+ */
+ snprintf(kzn->mzn_name, ZONE_NAME_MAX_LEN, "kalloc.%s",
+ get_kalloc_sizep(name.mzn_name));
+ kzi->mzi_alloc_size = info.mzi_alloc_size;
+ kzi->mzi_elem_size = info.mzi_elem_size;
+ kzi->mzi_exhaustible = info.mzi_exhaustible;
+ }
+ if (GET_MZI_COLLECTABLE_FLAG(info.mzi_collectable)) {
+ SET_MZI_COLLECTABLE_BYTES(kzi->mzi_collectable,
+ GET_MZI_COLLECTABLE_BYTES(kzi->mzi_collectable) +
+ GET_MZI_COLLECTABLE_BYTES(info.mzi_collectable));
+ }
+ kzi->mzi_sum_size += info.mzi_sum_size;
+ kzi->mzi_max_size += info.mzi_max_size;
+ }
+}
+
int
find_deltas(mach_zone_name_t *name, mach_zone_info_t *info, mach_zone_info_t *max_info,
char *deltas, int cnt, int first_time)
@@ -627,6 +880,14 @@ find_deltas(mach_zone_name_t *name, mach_zone_info_t *info, mach_zone_info_t *ma
found_one = 1;
}
}
+ /*
+ * Caolesce kalloc zones outside the above if to ensure that we
+ * consider all other kalloc zones for the size when one of them hits
+ * conditions other than first_time.
+ */
+ if (CoalesceKalloc != KALLOC_ZONE_DEFAULT) {
+ coalesce_kalloc(name[i], *info, &deltas[i]);
+ }
info++;
max_info++;
}