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#include <mach/vm_page_size.h>
54
55vm_statistics64_data_t	vm_stat, last;
56char	*pgmname;
57mach_port_t myHost;
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 (delay == 0.0) {
108		snapshot();
109	} else {
110		print_stats();
111		for (int i = 1; i < count || count == 0; i++ ){
112			usleep((int)(delay * USEC_PER_SEC));
113			print_stats();
114		}
115	}
116	exit(EXIT_SUCCESS);
117}
118
119void
120usage(void)
121{
122	fprintf(stderr, "usage: %s [[-c count] interval]\n", pgmname);
123	exit(EXIT_FAILURE);
124}
125
126void
127snapshot(void)
128{
129
130	get_stats(&vm_stat);
131	printf("Mach Virtual Memory Statistics: (page size of %llu bytes)\n", (mach_vm_size_t)vm_kernel_page_size);
132
133	sspstat("Pages free:", (uint64_t) (vm_stat.free_count - vm_stat.speculative_count));
134	sspstat("Pages active:", (uint64_t) (vm_stat.active_count));
135	sspstat("Pages inactive:", (uint64_t) (vm_stat.inactive_count));
136	sspstat("Pages speculative:", (uint64_t) (vm_stat.speculative_count));
137	sspstat("Pages throttled:", (uint64_t) (vm_stat.throttled_count));
138	sspstat("Pages wired down:", (uint64_t) (vm_stat.wire_count));
139	sspstat("Pages purgeable:", (uint64_t) (vm_stat.purgeable_count));
140	sspstat("\"Translation faults\":", (uint64_t) (vm_stat.faults));
141	sspstat("Pages copy-on-write:", (uint64_t) (vm_stat.cow_faults));
142	sspstat("Pages zero filled:", (uint64_t) (vm_stat.zero_fill_count));
143	sspstat("Pages reactivated:", (uint64_t) (vm_stat.reactivations));
144	sspstat("Pages purged:", (uint64_t) (vm_stat.purges));
145	sspstat("File-backed pages:", (uint64_t) (vm_stat.external_page_count));
146	sspstat("Anonymous pages:", (uint64_t) (vm_stat.internal_page_count));
147	sspstat("Pages stored in compressor:", (uint64_t) (vm_stat.total_uncompressed_pages_in_compressor));
148	sspstat("Pages occupied by compressor:", (uint64_t) (vm_stat.compressor_page_count));
149	sspstat("Decompressions:", (uint64_t) (vm_stat.decompressions));
150	sspstat("Compressions:", (uint64_t) (vm_stat.compressions));
151	sspstat("Pageins:", (uint64_t) (vm_stat.pageins));
152	sspstat("Pageouts:", (uint64_t) (vm_stat.pageouts));
153	sspstat("Swapins:", (uint64_t) (vm_stat.swapins));
154	sspstat("Swapouts:", (uint64_t) (vm_stat.swapouts));
155}
156
157void
158sspstat(char *str, uint64_t n)
159{
160	printf("%-30s %16llu.\n", str, n);
161}
162
163void
164banner(void)
165{
166	get_stats(&vm_stat);
167	printf("Mach Virtual Memory Statistics: ");
168	printf("(page size of %llu bytes)\n", (mach_vm_size_t)vm_kernel_page_size);
169	printf("%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %11s %9s %8s %8s %8s %8s %8s %8s %8s %8s\n",
170	       "free",
171	       "active",
172	       "specul",
173	       "inactive",
174	       "throttle",
175	       "wired",
176	       "prgable",
177	       "faults",
178	       "copy",
179	       "0fill",
180	       "reactive",
181	       "purged",
182	       "file-backed",
183	       "anonymous",
184	       "cmprssed",
185	       "cmprssor",
186	       "dcomprs",
187	       "comprs",
188	       "pageins",
189	       "pageout",
190	       "swapins",
191	       "swapouts");
192	bzero(&last, sizeof(last));
193}
194
195void
196print_stats(void)
197{
198	static int count = 0;
199
200	if (count++ == 0)
201		banner();
202
203	if (count > 20)
204		count = 0;
205
206	get_stats(&vm_stat);
207	pstat((uint64_t) (vm_stat.free_count - vm_stat.speculative_count), 8);
208	pstat((uint64_t) (vm_stat.active_count), 8);
209	pstat((uint64_t) (vm_stat.speculative_count), 8);
210	pstat((uint64_t) (vm_stat.inactive_count), 8);
211	pstat((uint64_t) (vm_stat.throttled_count), 8);
212	pstat((uint64_t) (vm_stat.wire_count), 8);
213	pstat((uint64_t) (vm_stat.purgeable_count), 8);
214	pstat((uint64_t) (vm_stat.faults - last.faults), 8);
215	pstat((uint64_t) (vm_stat.cow_faults - last.cow_faults), 8);
216	pstat((uint64_t) (vm_stat.zero_fill_count - last.zero_fill_count), 8);
217	pstat((uint64_t) (vm_stat.reactivations - last.reactivations), 8);
218	pstat((uint64_t) (vm_stat.purges - last.purges), 8);
219	pstat((uint64_t) (vm_stat.external_page_count), 11);
220	pstat((uint64_t) (vm_stat.internal_page_count), 9);
221	pstat((uint64_t) (vm_stat.total_uncompressed_pages_in_compressor), 8);
222	pstat((uint64_t) (vm_stat.compressor_page_count), 8);
223	pstat((uint64_t) (vm_stat.decompressions - last.decompressions), 8);
224	pstat((uint64_t) (vm_stat.compressions - last.compressions), 8);
225	pstat((uint64_t) (vm_stat.pageins - last.pageins), 8);
226	pstat((uint64_t) (vm_stat.pageouts - last.pageouts), 8);
227	pstat((uint64_t) (vm_stat.swapins - last.swapins), 8);
228	pstat((uint64_t) (vm_stat.swapouts - last.swapouts), 8);
229	putchar('\n');
230	last = vm_stat;
231}
232
233void
234pstat(uint64_t n, int width)
235{
236	char buf[80];
237	if (width >= sizeof(buf)) {
238		width = sizeof(buf) -1;
239	}
240
241	/* Now that we have the speculative field, there is really not enough
242	 space, but we were actually overflowing three or four fields before
243	 anyway.  So any field that overflows we drop some insignifigant
244	 digets and slap on the appropriate suffix
245	*/
246	int w = snprintf(buf, sizeof(buf), "%*llu", width, n);
247	if (w > width) {
248		w = snprintf(buf, sizeof(buf), "%*lluK", width -1, n / 1000);
249		if (w > width) {
250			w = snprintf(buf, sizeof(buf), "%*lluM", width -1, n / 1000000);
251			if (w > width) {
252				w = snprintf(buf, sizeof(buf), "%*lluG", width -1, n / 1000000000);
253			}
254		}
255	}
256	fputs(buf, stdout);
257	putchar(' ');
258}
259
260void
261get_stats(vm_statistics64_t stat)
262{
263	unsigned int count = HOST_VM_INFO64_COUNT;
264	kern_return_t ret;
265	if ((ret = host_statistics64(myHost, HOST_VM_INFO64, (host_info64_t)stat, &count) != KERN_SUCCESS)) {
266		fprintf(stderr, "%s: failed to get statistics. error %d\n", pgmname, ret);
267		exit(EXIT_FAILURE);
268	}
269}
270