1/*
2 * Copyright (c) 1999-2009 Apple Computer, 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 *	File:	vm_stat.c
26 *	Author:	Avadis Tevanian, Jr.
27 *
28 *	Copyright (C) 1986, Avadis Tevanian, Jr.
29 *
30 *
31 *	Display Mach VM statistics.
32 *
33 ************************************************************************
34 * HISTORY
35 *  6-Jun-86  Avadis Tevanian, Jr. (avie) at Carnegie-Mellon University
36 *	Use official Mach interface.
37 *
38 *  25-mar-99	A.Ramesh at Apple
39 *		Ported to MacOS X
40 *
41 *  22-Jan-09	R.Branche at Apple
42 *  		Changed some fields to 64-bit to alleviate overflows
43 ************************************************************************
44 */
45
46#include <err.h>
47#include <stddef.h>
48#include <stdlib.h>
49#include <unistd.h>
50#include <stdio.h>
51
52#include <mach/mach.h>
53
54vm_statistics64_data_t	vm_stat, last;
55char	*pgmname;
56mach_port_t myHost;
57vm_size_t pageSize = 4096; 	/* set to 4k default */
58
59void usage(void);
60void snapshot(void);
61void sspstat(char *str, uint64_t n);
62void banner(void);
63void print_stats(void);
64void get_stats(vm_statistics64_t stat);
65
66void pstat(uint64_t n, int width);
67
68int
69main(int argc, char *argv[])
70{
71
72	double delay = 0.0;
73	int count = 0;
74
75	pgmname = argv[0];
76
77	setlinebuf (stdout);
78
79	int c;
80	while ((c = getopt (argc, argv, "c:")) != -1) {
81		switch (c) {
82			case 'c':
83				count = (int)strtol(optarg, NULL, 10);
84				if (count < 1) {
85					warnx("count must be positive");
86					usage();
87				}
88				break;
89			default:
90				usage();
91				break;
92		}
93	}
94
95	argc -= optind; argv += optind;
96
97	if (argc == 1) {
98		delay = strtod(argv[0], NULL);
99		if (delay < 0.0)
100			usage();
101	} else if (argc > 1) {
102		usage();
103	}
104
105	myHost = mach_host_self();
106
107	if(host_page_size(mach_host_self(), &pageSize) != KERN_SUCCESS) {
108		fprintf(stderr, "%s: failed to get pagesize; defaulting to 4K.\n", pgmname);
109		pageSize = 4096;
110	}
111
112	if (delay == 0.0) {
113		snapshot();
114	} else {
115		print_stats();
116		for (int i = 1; i < count || count == 0; i++ ){
117			usleep((int)(delay * USEC_PER_SEC));
118			print_stats();
119		}
120	}
121	exit(EXIT_SUCCESS);
122}
123
124void
125usage(void)
126{
127	fprintf(stderr, "usage: %s [[-c count] interval]\n", pgmname);
128	exit(EXIT_FAILURE);
129}
130
131void
132snapshot(void)
133{
134
135	get_stats(&vm_stat);
136	printf("Mach Virtual Memory Statistics: (page size of %d bytes)\n",
137				(int) (pageSize));
138
139	sspstat("Pages free:", (uint64_t) (vm_stat.free_count - vm_stat.speculative_count));
140	sspstat("Pages active:", (uint64_t) (vm_stat.active_count));
141	sspstat("Pages inactive:", (uint64_t) (vm_stat.inactive_count));
142	sspstat("Pages speculative:", (uint64_t) (vm_stat.speculative_count));
143	sspstat("Pages throttled:", (uint64_t) (vm_stat.throttled_count));
144	sspstat("Pages wired down:", (uint64_t) (vm_stat.wire_count));
145	sspstat("Pages purgeable:", (uint64_t) (vm_stat.purgeable_count));
146	sspstat("\"Translation faults\":", (uint64_t) (vm_stat.faults));
147	sspstat("Pages copy-on-write:", (uint64_t) (vm_stat.cow_faults));
148	sspstat("Pages zero filled:", (uint64_t) (vm_stat.zero_fill_count));
149	sspstat("Pages reactivated:", (uint64_t) (vm_stat.reactivations));
150	sspstat("Pages purged:", (uint64_t) (vm_stat.purges));
151	sspstat("File-backed pages:", (uint64_t) (vm_stat.external_page_count));
152	sspstat("Anonymous pages:", (uint64_t) (vm_stat.internal_page_count));
153	sspstat("Pages stored in compressor:", (uint64_t) (vm_stat.total_uncompressed_pages_in_compressor));
154	sspstat("Pages occupied by compressor:", (uint64_t) (vm_stat.compressor_page_count));
155	sspstat("Decompressions:", (uint64_t) (vm_stat.decompressions));
156	sspstat("Compressions:", (uint64_t) (vm_stat.compressions));
157	sspstat("Pageins:", (uint64_t) (vm_stat.pageins));
158	sspstat("Pageouts:", (uint64_t) (vm_stat.pageouts));
159	sspstat("Swapins:", (uint64_t) (vm_stat.swapins));
160	sspstat("Swapouts:", (uint64_t) (vm_stat.swapouts));
161}
162
163void
164sspstat(char *str, uint64_t n)
165{
166	printf("%-30s %16llu.\n", str, n);
167}
168
169void
170banner(void)
171{
172	get_stats(&vm_stat);
173	printf("Mach Virtual Memory Statistics: ");
174	printf("(page size of %d bytes)\n",
175				(int) (pageSize));
176	printf("%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %11s %9s %8s %8s %8s %8s %8s %8s %8s %8s\n",
177	       "free",
178	       "active",
179	       "specul",
180	       "inactive",
181	       "throttle",
182	       "wired",
183	       "prgable",
184	       "faults",
185	       "copy",
186	       "0fill",
187	       "reactive",
188	       "purged",
189	       "file-backed",
190	       "anonymous",
191	       "cmprssed",
192	       "cmprssor",
193	       "dcomprs",
194	       "comprs",
195	       "pageins",
196	       "pageout",
197	       "swapins",
198	       "swapouts");
199	bzero(&last, sizeof(last));
200}
201
202void
203print_stats(void)
204{
205	static int count = 0;
206
207	if (count++ == 0)
208		banner();
209
210	if (count > 20)
211		count = 0;
212
213	get_stats(&vm_stat);
214	pstat((uint64_t) (vm_stat.free_count - vm_stat.speculative_count), 8);
215	pstat((uint64_t) (vm_stat.active_count), 8);
216	pstat((uint64_t) (vm_stat.speculative_count), 8);
217	pstat((uint64_t) (vm_stat.inactive_count), 8);
218	pstat((uint64_t) (vm_stat.throttled_count), 8);
219	pstat((uint64_t) (vm_stat.wire_count), 8);
220	pstat((uint64_t) (vm_stat.purgeable_count), 8);
221	pstat((uint64_t) (vm_stat.faults - last.faults), 8);
222	pstat((uint64_t) (vm_stat.cow_faults - last.cow_faults), 8);
223	pstat((uint64_t) (vm_stat.zero_fill_count - last.zero_fill_count), 8);
224	pstat((uint64_t) (vm_stat.reactivations - last.reactivations), 8);
225	pstat((uint64_t) (vm_stat.purges - last.purges), 8);
226	pstat((uint64_t) (vm_stat.external_page_count), 11);
227	pstat((uint64_t) (vm_stat.internal_page_count), 9);
228	pstat((uint64_t) (vm_stat.total_uncompressed_pages_in_compressor), 8);
229	pstat((uint64_t) (vm_stat.compressor_page_count), 8);
230	pstat((uint64_t) (vm_stat.decompressions - last.decompressions), 8);
231	pstat((uint64_t) (vm_stat.compressions - last.compressions), 8);
232	pstat((uint64_t) (vm_stat.pageins - last.pageins), 8);
233	pstat((uint64_t) (vm_stat.pageouts - last.pageouts), 8);
234	pstat((uint64_t) (vm_stat.swapins - last.swapins), 8);
235	pstat((uint64_t) (vm_stat.swapouts - last.swapouts), 8);
236	putchar('\n');
237	last = vm_stat;
238}
239
240void
241pstat(uint64_t n, int width)
242{
243	char buf[80];
244	if (width >= sizeof(buf)) {
245		width = sizeof(buf) -1;
246	}
247
248	/* Now that we have the speculative field, there is really not enough
249	 space, but we were actually overflowing three or four fields before
250	 anyway.  So any field that overflows we drop some insignifigant
251	 digets and slap on the appropriate suffix
252	*/
253	int w = snprintf(buf, sizeof(buf), "%*llu", width, n);
254	if (w > width) {
255		w = snprintf(buf, sizeof(buf), "%*lluK", width -1, n / 1000);
256		if (w > width) {
257			w = snprintf(buf, sizeof(buf), "%*lluM", width -1, n / 1000000);
258			if (w > width) {
259				w = snprintf(buf, sizeof(buf), "%*lluG", width -1, n / 1000000000);
260			}
261		}
262	}
263	fputs(buf, stdout);
264	putchar(' ');
265}
266
267void
268get_stats(vm_statistics64_t stat)
269{
270	unsigned int count = HOST_VM_INFO64_COUNT;
271	kern_return_t ret;
272	if ((ret = host_statistics64(myHost, HOST_VM_INFO64, (host_info64_t)stat, &count) != KERN_SUCCESS)) {
273		fprintf(stderr, "%s: failed to get statistics. error %d\n", pgmname, ret);
274		exit(EXIT_FAILURE);
275	}
276}
277