2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
29 #include <mach/mach.h>
30 #include <mach/mach_types.h>
31 #include <mach/task.h>
33 #include <mach/vm_purgable.h>
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
39 #define PURGEABLE_PRIO_LEVELS VM_VOLATILE_GROUP_SHIFT
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
);
50 static inline int purge_info_size_adjust(uint64_t size
)
57 static inline char purge_info_unit(uint64_t size
)
59 char sizes
[] = {'B', 'K', 'M', 'G', 'T'};
69 void print_header(int summary_view
)
72 printf("%20s ", "Process-Name");
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",
78 "LIFO-P0", "LIFO-P1", "LIFO-P2", "LIFO-P3",
79 "LIFO-P4", "LIFO-P5", "LIFO-P6", "LIFO-P7"
83 int get_task_from_pid(int pid
, task_t
*task
)
87 fprintf(stderr
, "%s\n", PRIV_ERR_MSG
);
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
);
98 int get_system_tasks(task_array_t
*tasks
, mach_msg_type_number_t
*count
)
100 processor_set_name_array_t psets
;
101 mach_msg_type_number_t psetCount
;
102 mach_port_t pset_priv
;
105 if (geteuid() != 0) {
106 fprintf(stderr
, "%s\n", PRIV_ERR_MSG
);
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
));
115 if (psetCount
!= 1) {
116 fprintf(stderr
, "Assertion Failure: pset count greater than one (%d)\n", psetCount
);
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
));
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
));
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
));
135 mach_port_deallocate(mach_task_self(), pset_priv
);
139 void print_purge_info_task(task_t task
, int pid
)
141 task_purgable_info_t info
;
144 char pname
[PROC_NAME_LEN
];
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
));
151 if (0 == proc_name(pid
, pname
, PROC_NAME_LEN
))
152 strncpy(pname
, "Unknown", 7);
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
));
164 void print_purge_info_task_array(task_array_t tasks
, mach_msg_type_number_t count
)
169 for (i
=0; i
<count
; i
++) {
170 if (KERN_SUCCESS
!= pid_for_task(tasks
[i
], &pid
))
172 print_purge_info_task(tasks
[i
], pid
);
177 void print_purge_info_summary(int sleep_duration
)
179 host_purgable_info_data_t info
;
180 mach_msg_type_number_t count
;
181 kern_return_t result
;
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
)
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
));
195 sleep(sleep_duration
);
200 int main(int argc
, char *argv
[])
208 mach_msg_type_number_t taskCount
;
212 ch
= getopt(argc
, argv
, "ahp:s:");
218 if (get_system_tasks(&tasks
, &taskCount
) < 0)
221 print_purge_info_task_array(tasks
, taskCount
);
225 pid
= (int)strtol(optarg
, NULL
, 10);
228 if (get_task_from_pid(pid
, &task
) < 0)
231 print_purge_info_task(task
, pid
);
234 sleep_duration
= (int)strtol(optarg
, NULL
, 10);
235 if (sleep_duration
< 0)
238 print_purge_info_summary(sleep_duration
);