]> git.saurik.com Git - apple/system_cmds.git/blob - vm_purgeable_stat.tproj/vm_purgeable_stat.c
system_cmds-880.60.2.tar.gz
[apple/system_cmds.git] / vm_purgeable_stat.tproj / vm_purgeable_stat.c
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
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <unistd.h>
29 #include <mach/mach.h>
30 #include <mach/mach_types.h>
31 #include <mach/task.h>
32 #include <libproc.h>
33 #include <mach/vm_purgable.h>
34
35 #define USAGE "Usage: vm_purgeable_stat [-a | -p <pid> | -s <interval>]\n"
36 #define PRIV_ERR_MSG "The option specified needs root priveleges."
37 #define PROC_NAME_LEN 256
38 #define KB 1024
39 #define PURGEABLE_PRIO_LEVELS VM_VOLATILE_GROUP_SHIFT
40
41 static inline int purge_info_size_adjust(uint64_t size);
42 static inline char purge_info_unit(uint64_t size);
43 void print_header(int summary_view);
44 int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count);
45 int get_task_from_pid(int pid, task_t *task);
46 void print_purge_info_task(task_t task, int pid);
47 void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count);
48 void print_purge_info_summary(int sleep_duration);
49
50 static inline int purge_info_size_adjust(uint64_t size)
51 {
52 while(size > KB)
53 size /= KB;
54 return (int)size;
55 }
56
57 static inline char purge_info_unit(uint64_t size)
58 {
59 char sizes[] = {'B', 'K', 'M', 'G', 'T'};
60 int index = 0;
61
62 while(size > KB) {
63 index++;
64 size /= KB;
65 }
66 return sizes[index];
67 }
68
69 void print_header(int summary_view)
70 {
71 if (!summary_view)
72 printf("%20s ", "Process-Name");
73
74 printf("%9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n",
75 "FIFO-P0", "FIFO-P1", "FIFO-P2", "FIFO-P3",
76 "FIFO-P4", "FIFO-P5", "FIFO-P6", "FIFO-P7",
77 "OBSOLETE",
78 "LIFO-P0", "LIFO-P1", "LIFO-P2", "LIFO-P3",
79 "LIFO-P4", "LIFO-P5", "LIFO-P6", "LIFO-P7"
80 );
81 }
82
83 int get_task_from_pid(int pid, task_t *task)
84 {
85 kern_return_t kr;
86 if (geteuid() != 0) {
87 fprintf(stderr, "%s\n", PRIV_ERR_MSG);
88 return -1;
89 }
90 kr = task_for_pid(mach_task_self(), pid, task);
91 if (kr != KERN_SUCCESS) {
92 fprintf(stderr, "Failed to get task port for pid: %d\n", pid);
93 return -1;
94 }
95 return 0;
96 }
97
98 int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count)
99 {
100 processor_set_name_array_t psets;
101 mach_msg_type_number_t psetCount;
102 mach_port_t pset_priv;
103 kern_return_t ret;
104
105 if (geteuid() != 0) {
106 fprintf(stderr, "%s\n", PRIV_ERR_MSG);
107 return -1;
108 }
109
110 ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
111 if (ret != KERN_SUCCESS) {
112 fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
113 return -1;
114 }
115 if (psetCount != 1) {
116 fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
117 return -1;
118 }
119
120 /* convert the processor-set-name port to a privileged port */
121 ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
122 if (ret != KERN_SUCCESS) {
123 fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
124 return -1;
125 }
126 mach_port_deallocate(mach_task_self(), psets[0]);
127 vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
128
129 /* convert the processor-set-priv to a list of tasks for the processor set */
130 ret = processor_set_tasks(pset_priv, tasks, count);
131 if (ret != KERN_SUCCESS) {
132 fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret));
133 return -1;
134 }
135 mach_port_deallocate(mach_task_self(), pset_priv);
136 return 0;
137 }
138
139 void print_purge_info_task(task_t task, int pid)
140 {
141 task_purgable_info_t info;
142 kern_return_t kr;
143 int i;
144 char pname[PROC_NAME_LEN];
145
146 kr = task_purgable_info(task, &info);
147 if (kr != KERN_SUCCESS) {
148 fprintf(stderr, "(pid: %d) task_purgable_info() failed: %s\n", pid, mach_error_string(kr));
149 return;
150 }
151 if (0 == proc_name(pid, pname, PROC_NAME_LEN))
152 strncpy(pname, "Unknown", 7);
153 pname[20] = 0;
154 printf("%20s ", pname);
155 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
156 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));
157 printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
158 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
159 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));
160 printf("\n");
161 return;
162 }
163
164 void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count)
165 {
166 int i;
167 int pid;
168
169 for (i=0; i<count; i++) {
170 if (KERN_SUCCESS != pid_for_task(tasks[i], &pid))
171 continue;
172 print_purge_info_task(tasks[i], pid);
173 }
174 return;
175 }
176
177 void print_purge_info_summary(int sleep_duration)
178 {
179 host_purgable_info_data_t info;
180 mach_msg_type_number_t count;
181 kern_return_t result;
182 int i;
183
184 while(1) {
185 count = HOST_VM_PURGABLE_COUNT;
186 result = host_info(mach_host_self(), HOST_VM_PURGABLE, (host_info_t)&info, &count);
187 if (result != KERN_SUCCESS)
188 break;
189 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
190 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));
191 printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
192 for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
193 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));
194 printf("\n");
195 sleep(sleep_duration);
196 }
197 return;
198 }
199
200 int main(int argc, char *argv[])
201 {
202
203 char ch;
204 int pid;
205 int sleep_duration;
206 task_array_t tasks;
207 task_t task;
208 mach_msg_type_number_t taskCount;
209 int noargs = 1;
210
211 while(1) {
212 ch = getopt(argc, argv, "ahp:s:");
213 if (ch == -1)
214 break;
215 noargs = 0;
216 switch(ch) {
217 case 'a':
218 if (get_system_tasks(&tasks, &taskCount) < 0)
219 break;
220 print_header(0);
221 print_purge_info_task_array(tasks, taskCount);
222 break;
223
224 case 'p':
225 pid = (int)strtol(optarg, NULL, 10);
226 if (pid < 0)
227 break;
228 if (get_task_from_pid(pid, &task) < 0)
229 break;
230 print_header(0);
231 print_purge_info_task(task, pid);
232 break;
233 case 's':
234 sleep_duration = (int)strtol(optarg, NULL, 10);
235 if (sleep_duration < 0)
236 break;
237 print_header(1);
238 print_purge_info_summary(sleep_duration);
239 break;
240 case '?':
241 case 'h':
242 default:
243 printf("%s", USAGE);
244 }
245 break;
246 }
247 if (noargs)
248 printf("%s", USAGE);
249 return 0;
250 }