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