]> git.saurik.com Git - apple/system_cmds.git/blame - vm_purgeable_stat.tproj/vm_purgeable_stat.c
system_cmds-880.100.5.tar.gz
[apple/system_cmds.git] / vm_purgeable_stat.tproj / vm_purgeable_stat.c
CommitLineData
cf37c299
A
1/*
2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
00bf83c0 25#include <System/sys/proc.h>
fc6d9e4b
A
26#include <stdio.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <mach/mach.h>
31#include <mach/mach_types.h>
32#include <mach/task.h>
33#include <libproc.h>
34#include <mach/vm_purgable.h>
35
36#define USAGE "Usage: vm_purgeable_stat [-a | -p <pid> | -s <interval>]\n"
37#define PRIV_ERR_MSG "The option specified needs root priveleges."
38#define PROC_NAME_LEN 256
39#define KB 1024
40#define PURGEABLE_PRIO_LEVELS VM_VOLATILE_GROUP_SHIFT
41
42static inline int purge_info_size_adjust(uint64_t size);
43static inline char purge_info_unit(uint64_t size);
44void print_header(int summary_view);
45int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count);
46int get_task_from_pid(int pid, task_t *task);
47void print_purge_info_task(task_t task, int pid);
48void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count);
49void print_purge_info_summary(int sleep_duration);
50
51static inline int purge_info_size_adjust(uint64_t size)
52{
53 while(size > KB)
54 size /= KB;
55 return (int)size;
56}
57
58static inline char purge_info_unit(uint64_t size)
59{
60 char sizes[] = {'B', 'K', 'M', 'G', 'T'};
61 int index = 0;
62
63 while(size > KB) {
64 index++;
65 size /= KB;
66 }
67 return sizes[index];
68}
69
70void print_header(int summary_view)
71{
72 if (!summary_view)
73 printf("%20s ", "Process-Name");
74
75 printf("%9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n",
76 "FIFO-P0", "FIFO-P1", "FIFO-P2", "FIFO-P3",
77 "FIFO-P4", "FIFO-P5", "FIFO-P6", "FIFO-P7",
78 "OBSOLETE",
79 "LIFO-P0", "LIFO-P1", "LIFO-P2", "LIFO-P3",
80 "LIFO-P4", "LIFO-P5", "LIFO-P6", "LIFO-P7"
81 );
82}
83
84int get_task_from_pid(int pid, task_t *task)
85{
86 kern_return_t kr;
87 if (geteuid() != 0) {
88 fprintf(stderr, "%s\n", PRIV_ERR_MSG);
89 return -1;
90 }
00bf83c0 91 kr = task_inspect_for_pid(mach_task_self(), pid, task);
fc6d9e4b
A
92 if (kr != KERN_SUCCESS) {
93 fprintf(stderr, "Failed to get task port for pid: %d\n", pid);
94 return -1;
95 }
96 return 0;
97}
98
99int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count)
100{
101 processor_set_name_array_t psets;
102 mach_msg_type_number_t psetCount;
103 mach_port_t pset_priv;
104 kern_return_t ret;
105
106 if (geteuid() != 0) {
107 fprintf(stderr, "%s\n", PRIV_ERR_MSG);
108 return -1;
109 }
cf37c299 110
fc6d9e4b
A
111 ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
112 if (ret != KERN_SUCCESS) {
113 fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
114 return -1;
115 }
116 if (psetCount != 1) {
117 fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
118 return -1;
119 }
120
121 /* convert the processor-set-name port to a privileged port */
122 ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
123 if (ret != KERN_SUCCESS) {
124 fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
125 return -1;
126 }
127 mach_port_deallocate(mach_task_self(), psets[0]);
128 vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
129
130 /* convert the processor-set-priv to a list of tasks for the processor set */
00bf83c0 131 ret = processor_set_tasks_with_flavor(pset_priv, TASK_FLAVOR_INSPECT, tasks, count);
fc6d9e4b 132 if (ret != KERN_SUCCESS) {
00bf83c0 133 fprintf(stderr, "processor_set_tasks_with_flavor() failed: %s\n", mach_error_string(ret));
fc6d9e4b
A
134 return -1;
135 }
136 mach_port_deallocate(mach_task_self(), pset_priv);
137 return 0;
138}
139
140void print_purge_info_task(task_t task, int pid)
141{
142 task_purgable_info_t info;
143 kern_return_t kr;
144 int i;
145 char pname[PROC_NAME_LEN];
146
147 kr = task_purgable_info(task, &info);
148 if (kr != KERN_SUCCESS) {
149 fprintf(stderr, "(pid: %d) task_purgable_info() failed: %s\n", pid, mach_error_string(kr));
150 return;
151 }
152 if (0 == proc_name(pid, pname, PROC_NAME_LEN))
153 strncpy(pname, "Unknown", 7);
154 pname[20] = 0;
155 printf("%20s ", pname);
156 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
157 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));
158 printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
159 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
160 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));
161 printf("\n");
162 return;
163}
164
165void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count)
166{
167 int i;
168 int pid;
169
170 for (i=0; i<count; i++) {
171 if (KERN_SUCCESS != pid_for_task(tasks[i], &pid))
172 continue;
173 print_purge_info_task(tasks[i], pid);
174 }
175 return;
176}
177
178void print_purge_info_summary(int sleep_duration)
179{
180 host_purgable_info_data_t info;
181 mach_msg_type_number_t count;
182 kern_return_t result;
183 int i;
184
185 while(1) {
186 count = HOST_VM_PURGABLE_COUNT;
187 result = host_info(mach_host_self(), HOST_VM_PURGABLE, (host_info_t)&info, &count);
188 if (result != KERN_SUCCESS)
189 break;
190 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
191 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));
192 printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
193 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
194 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));
195 printf("\n");
196 sleep(sleep_duration);
197 }
198 return;
199}
200
201int main(int argc, char *argv[])
202{
cf37c299 203
fc6d9e4b
A
204 char ch;
205 int pid;
206 int sleep_duration;
207 task_array_t tasks;
208 task_t task;
209 mach_msg_type_number_t taskCount;
210 int noargs = 1;
211
212 while(1) {
213 ch = getopt(argc, argv, "ahp:s:");
214 if (ch == -1)
215 break;
216 noargs = 0;
217 switch(ch) {
218 case 'a':
219 if (get_system_tasks(&tasks, &taskCount) < 0)
220 break;
221 print_header(0);
222 print_purge_info_task_array(tasks, taskCount);
223 break;
224
225 case 'p':
226 pid = (int)strtol(optarg, NULL, 10);
227 if (pid < 0)
228 break;
229 if (get_task_from_pid(pid, &task) < 0)
230 break;
231 print_header(0);
232 print_purge_info_task(task, pid);
233 break;
234 case 's':
235 sleep_duration = (int)strtol(optarg, NULL, 10);
236 if (sleep_duration < 0)
237 break;
238 print_header(1);
239 print_purge_info_summary(sleep_duration);
240 break;
241 case '?':
242 case 'h':
243 default:
cf37c299 244 printf("%s", USAGE);
fc6d9e4b
A
245 }
246 break;
247 }
248 if (noargs)
249 printf("%s", USAGE);
250 return 0;
251}