]> git.saurik.com Git - apple/system_cmds.git/blame - vm_purgeable_stat.tproj/vm_purgeable_stat.c
system_cmds-735.20.1.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
fc6d9e4b
A
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
41static inline int purge_info_size_adjust(uint64_t size);
42static inline char purge_info_unit(uint64_t size);
43void print_header(int summary_view);
44int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count);
45int get_task_from_pid(int pid, task_t *task);
46void print_purge_info_task(task_t task, int pid);
47void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count);
48void print_purge_info_summary(int sleep_duration);
49
50static inline int purge_info_size_adjust(uint64_t size)
51{
52 while(size > KB)
53 size /= KB;
54 return (int)size;
55}
56
57static 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
69void 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
83int 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
98int 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 }
cf37c299 109
fc6d9e4b
A
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
139void 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
164void 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
177void 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
200int main(int argc, char *argv[])
201{
cf37c299 202
fc6d9e4b
A
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:
cf37c299 243 printf("%s", USAGE);
fc6d9e4b
A
244 }
245 break;
246 }
247 if (noargs)
248 printf("%s", USAGE);
249 return 0;
250}