diff options
author | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
---|---|---|
committer | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c | |
download | apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip |
Import macOS userland
adv_cmds-176
basic_cmds-55
bootstrap_cmds-116.100.1
developer_cmds-66
diskdev_cmds-667.40.1
doc_cmds-53.60.1
file_cmds-321.40.3
mail_cmds-35
misc_cmds-34
network_cmds-606.40.1
patch_cmds-17
remote_cmds-63
shell_cmds-216.60.1
system_cmds-880.60.2
text_cmds-106
Diffstat (limited to 'system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c')
-rw-r--r-- | system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c b/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c new file mode 100644 index 0000000..bfef539 --- /dev/null +++ b/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. 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 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource 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 OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <mach/mach.h> +#include <mach/mach_types.h> +#include <mach/task.h> +#include <libproc.h> +#include <mach/vm_purgable.h> + +#define USAGE "Usage: vm_purgeable_stat [-a | -p <pid> | -s <interval>]\n" +#define PRIV_ERR_MSG "The option specified needs root priveleges." +#define PROC_NAME_LEN 256 +#define KB 1024 +#define PURGEABLE_PRIO_LEVELS VM_VOLATILE_GROUP_SHIFT + +static inline int purge_info_size_adjust(uint64_t size); +static inline char purge_info_unit(uint64_t size); +void print_header(int summary_view); +int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count); +int get_task_from_pid(int pid, task_t *task); +void print_purge_info_task(task_t task, int pid); +void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count); +void print_purge_info_summary(int sleep_duration); + +static inline int purge_info_size_adjust(uint64_t size) +{ + while(size > KB) + size /= KB; + return (int)size; +} + +static inline char purge_info_unit(uint64_t size) +{ + char sizes[] = {'B', 'K', 'M', 'G', 'T'}; + int index = 0; + + while(size > KB) { + index++; + size /= KB; + } + return sizes[index]; +} + +void print_header(int summary_view) +{ + if (!summary_view) + printf("%20s ", "Process-Name"); + + printf("%9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n", + "FIFO-P0", "FIFO-P1", "FIFO-P2", "FIFO-P3", + "FIFO-P4", "FIFO-P5", "FIFO-P6", "FIFO-P7", + "OBSOLETE", + "LIFO-P0", "LIFO-P1", "LIFO-P2", "LIFO-P3", + "LIFO-P4", "LIFO-P5", "LIFO-P6", "LIFO-P7" + ); +} + +int get_task_from_pid(int pid, task_t *task) +{ + kern_return_t kr; + if (geteuid() != 0) { + fprintf(stderr, "%s\n", PRIV_ERR_MSG); + return -1; + } + kr = task_for_pid(mach_task_self(), pid, task); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "Failed to get task port for pid: %d\n", pid); + return -1; + } + return 0; +} + +int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count) +{ + processor_set_name_array_t psets; + mach_msg_type_number_t psetCount; + mach_port_t pset_priv; + kern_return_t ret; + + if (geteuid() != 0) { + fprintf(stderr, "%s\n", PRIV_ERR_MSG); + return -1; + } + + ret = host_processor_sets(mach_host_self(), &psets, &psetCount); + if (ret != KERN_SUCCESS) { + fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret)); + return -1; + } + if (psetCount != 1) { + fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount); + return -1; + } + + /* convert the processor-set-name port to a privileged port */ + ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv); + if (ret != KERN_SUCCESS) { + fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret)); + return -1; + } + mach_port_deallocate(mach_task_self(), psets[0]); + vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t)); + + /* convert the processor-set-priv to a list of tasks for the processor set */ + ret = processor_set_tasks(pset_priv, tasks, count); + if (ret != KERN_SUCCESS) { + fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret)); + return -1; + } + mach_port_deallocate(mach_task_self(), pset_priv); + return 0; +} + +void print_purge_info_task(task_t task, int pid) +{ + task_purgable_info_t info; + kern_return_t kr; + int i; + char pname[PROC_NAME_LEN]; + + kr = task_purgable_info(task, &info); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "(pid: %d) task_purgable_info() failed: %s\n", pid, mach_error_string(kr)); + return; + } + if (0 == proc_name(pid, pname, PROC_NAME_LEN)) + strncpy(pname, "Unknown", 7); + pname[20] = 0; + printf("%20s ", pname); + for (i=0; i<PURGEABLE_PRIO_LEVELS; i++) + printf("%4u/%3d%c ", (unsigned)info.fifo_data[i].count, purge_info_size_adjust(info.fifo_data[i].size), purge_info_unit(info.fifo_data[i].size)); + printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size)); + for (i=0; i<PURGEABLE_PRIO_LEVELS; i++) + printf("%4u/%3d%c ", (unsigned)info.lifo_data[i].count, purge_info_size_adjust(info.lifo_data[i].size), purge_info_unit(info.lifo_data[i].size)); + printf("\n"); + return; +} + +void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count) +{ + int i; + int pid; + + for (i=0; i<count; i++) { + if (KERN_SUCCESS != pid_for_task(tasks[i], &pid)) + continue; + print_purge_info_task(tasks[i], pid); + } + return; +} + +void print_purge_info_summary(int sleep_duration) +{ + host_purgable_info_data_t info; + mach_msg_type_number_t count; + kern_return_t result; + int i; + + while(1) { + count = HOST_VM_PURGABLE_COUNT; + result = host_info(mach_host_self(), HOST_VM_PURGABLE, (host_info_t)&info, &count); + if (result != KERN_SUCCESS) + break; + for (i=0; i<PURGEABLE_PRIO_LEVELS; i++) + printf("%4u/%3d%c ", (unsigned)info.fifo_data[i].count, purge_info_size_adjust(info.fifo_data[i].size), purge_info_unit(info.fifo_data[i].size)); + printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size)); + for (i=0; i<PURGEABLE_PRIO_LEVELS; i++) + printf("%4u/%3d%c ", (unsigned)info.lifo_data[i].count, purge_info_size_adjust(info.lifo_data[i].size), purge_info_unit(info.lifo_data[i].size)); + printf("\n"); + sleep(sleep_duration); + } + return; +} + +int main(int argc, char *argv[]) +{ + + char ch; + int pid; + int sleep_duration; + task_array_t tasks; + task_t task; + mach_msg_type_number_t taskCount; + int noargs = 1; + + while(1) { + ch = getopt(argc, argv, "ahp:s:"); + if (ch == -1) + break; + noargs = 0; + switch(ch) { + case 'a': + if (get_system_tasks(&tasks, &taskCount) < 0) + break; + print_header(0); + print_purge_info_task_array(tasks, taskCount); + break; + + case 'p': + pid = (int)strtol(optarg, NULL, 10); + if (pid < 0) + break; + if (get_task_from_pid(pid, &task) < 0) + break; + print_header(0); + print_purge_info_task(task, pid); + break; + case 's': + sleep_duration = (int)strtol(optarg, NULL, 10); + if (sleep_duration < 0) + break; + print_header(1); + print_purge_info_summary(sleep_duration); + break; + case '?': + case 'h': + default: + printf("%s", USAGE); + } + break; + } + if (noargs) + printf("%s", USAGE); + return 0; +} |