xref: /illumos-gate/usr/src/cmd/kvmstat/kvmstat.c (revision 7aa76ffc594f84c1c092911a84f85a79ddb44c73)
1*7aa76ffcSBryan Cantrill /*
2*7aa76ffcSBryan Cantrill  * CDDL HEADER START
3*7aa76ffcSBryan Cantrill  *
4*7aa76ffcSBryan Cantrill  * The contents of this file are subject to the terms of the
5*7aa76ffcSBryan Cantrill  * Common Development and Distribution License (the "License").
6*7aa76ffcSBryan Cantrill  * You may not use this file except in compliance with the License.
7*7aa76ffcSBryan Cantrill  *
8*7aa76ffcSBryan Cantrill  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7aa76ffcSBryan Cantrill  * or http://www.opensolaris.org/os/licensing.
10*7aa76ffcSBryan Cantrill  * See the License for the specific language governing permissions
11*7aa76ffcSBryan Cantrill  * and limitations under the License.
12*7aa76ffcSBryan Cantrill  *
13*7aa76ffcSBryan Cantrill  * When distributing Covered Code, include this CDDL HEADER in each
14*7aa76ffcSBryan Cantrill  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7aa76ffcSBryan Cantrill  * If applicable, add the following below this CDDL HEADER, with the
16*7aa76ffcSBryan Cantrill  * fields enclosed by brackets "[]" replaced with your own identifying
17*7aa76ffcSBryan Cantrill  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7aa76ffcSBryan Cantrill  *
19*7aa76ffcSBryan Cantrill  * CDDL HEADER END
20*7aa76ffcSBryan Cantrill  */
21*7aa76ffcSBryan Cantrill 
22*7aa76ffcSBryan Cantrill /*
23*7aa76ffcSBryan Cantrill  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
24*7aa76ffcSBryan Cantrill  */
25*7aa76ffcSBryan Cantrill 
26*7aa76ffcSBryan Cantrill #include <sys/kstat.h>
27*7aa76ffcSBryan Cantrill #include <kstat.h>
28*7aa76ffcSBryan Cantrill #include <stdlib.h>
29*7aa76ffcSBryan Cantrill #include <unistd.h>
30*7aa76ffcSBryan Cantrill #include <assert.h>
31*7aa76ffcSBryan Cantrill #include <errno.h>
32*7aa76ffcSBryan Cantrill #include <stdio.h>
33*7aa76ffcSBryan Cantrill #include <string.h>
34*7aa76ffcSBryan Cantrill #include <strings.h>
35*7aa76ffcSBryan Cantrill #include <alloca.h>
36*7aa76ffcSBryan Cantrill #include <signal.h>
37*7aa76ffcSBryan Cantrill #include <sys/varargs.h>
38*7aa76ffcSBryan Cantrill #include <sys/int_limits.h>
39*7aa76ffcSBryan Cantrill 
40*7aa76ffcSBryan Cantrill #define	KSTAT_FIELD_USEINSTANCE		0x01
41*7aa76ffcSBryan Cantrill #define	KSTAT_FIELD_NODELTA		0x02
42*7aa76ffcSBryan Cantrill #define	KSTAT_FIELD_FILLER		0x04
43*7aa76ffcSBryan Cantrill 
44*7aa76ffcSBryan Cantrill typedef struct kstat_field {
45*7aa76ffcSBryan Cantrill 	char *ksf_header;		/* header for field */
46*7aa76ffcSBryan Cantrill 	char *ksf_name;			/* name of stat, if any */
47*7aa76ffcSBryan Cantrill 	int ksf_width;			/* width for field in output line */
48*7aa76ffcSBryan Cantrill 	uint32_t ksf_flags;		/* flags for this field, if any */
49*7aa76ffcSBryan Cantrill 	int ksf_hint;			/* index hint for field in kstat */
50*7aa76ffcSBryan Cantrill } kstat_field_t;
51*7aa76ffcSBryan Cantrill 
52*7aa76ffcSBryan Cantrill typedef struct kstat_instance {
53*7aa76ffcSBryan Cantrill 	char ksi_name[KSTAT_STRLEN];	/* name of the underlying kstat */
54*7aa76ffcSBryan Cantrill 	int ksi_instance;		/* instance identifer of this kstat */
55*7aa76ffcSBryan Cantrill 	kstat_t *ksi_ksp;		/* pointer to the kstat */
56*7aa76ffcSBryan Cantrill 	uint64_t *ksi_data[2];		/* pointer to two generations of data */
57*7aa76ffcSBryan Cantrill 	hrtime_t ksi_snaptime[2];	/* hrtime for data generations */
58*7aa76ffcSBryan Cantrill 	int ksi_gen;			/* current generation */
59*7aa76ffcSBryan Cantrill 	struct kstat_instance *ksi_next; /* next in instance list */
60*7aa76ffcSBryan Cantrill } kstat_instance_t;
61*7aa76ffcSBryan Cantrill 
62*7aa76ffcSBryan Cantrill const char *g_cmd = "kvmstat";
63*7aa76ffcSBryan Cantrill 
64*7aa76ffcSBryan Cantrill static void
fatal(char * fmt,...)65*7aa76ffcSBryan Cantrill fatal(char *fmt, ...)
66*7aa76ffcSBryan Cantrill {
67*7aa76ffcSBryan Cantrill 	va_list ap;
68*7aa76ffcSBryan Cantrill 	int error = errno;
69*7aa76ffcSBryan Cantrill 
70*7aa76ffcSBryan Cantrill 	va_start(ap, fmt);
71*7aa76ffcSBryan Cantrill 
72*7aa76ffcSBryan Cantrill 	(void) fprintf(stderr, "%s: ", g_cmd);
73*7aa76ffcSBryan Cantrill 	/*LINTED*/
74*7aa76ffcSBryan Cantrill 	(void) vfprintf(stderr, fmt, ap);
75*7aa76ffcSBryan Cantrill 
76*7aa76ffcSBryan Cantrill 	if (fmt[strlen(fmt) - 1] != '\n')
77*7aa76ffcSBryan Cantrill 		(void) fprintf(stderr, ": %s\n", strerror(error));
78*7aa76ffcSBryan Cantrill 
79*7aa76ffcSBryan Cantrill 	exit(EXIT_FAILURE);
80*7aa76ffcSBryan Cantrill }
81*7aa76ffcSBryan Cantrill 
82*7aa76ffcSBryan Cantrill int
kstat_field_hint(kstat_t * ksp,kstat_field_t * field)83*7aa76ffcSBryan Cantrill kstat_field_hint(kstat_t *ksp, kstat_field_t *field)
84*7aa76ffcSBryan Cantrill {
85*7aa76ffcSBryan Cantrill 	kstat_named_t *nm = KSTAT_NAMED_PTR(ksp);
86*7aa76ffcSBryan Cantrill 	int i;
87*7aa76ffcSBryan Cantrill 
88*7aa76ffcSBryan Cantrill 	assert(ksp->ks_type == KSTAT_TYPE_NAMED);
89*7aa76ffcSBryan Cantrill 
90*7aa76ffcSBryan Cantrill 	for (i = 0; i < ksp->ks_ndata; i++) {
91*7aa76ffcSBryan Cantrill 		if (strcmp(field->ksf_name, nm[i].name) == 0)
92*7aa76ffcSBryan Cantrill 			return (field->ksf_hint = i);
93*7aa76ffcSBryan Cantrill 	}
94*7aa76ffcSBryan Cantrill 
95*7aa76ffcSBryan Cantrill 	fatal("could not find field '%s' in %s:%d\n",
96*7aa76ffcSBryan Cantrill 	    field->ksf_name, ksp->ks_name, ksp->ks_instance);
97*7aa76ffcSBryan Cantrill 
98*7aa76ffcSBryan Cantrill 	return (0);
99*7aa76ffcSBryan Cantrill }
100*7aa76ffcSBryan Cantrill 
101*7aa76ffcSBryan Cantrill int
kstat_instances_compare(const void * lhs,const void * rhs)102*7aa76ffcSBryan Cantrill kstat_instances_compare(const void *lhs, const void *rhs)
103*7aa76ffcSBryan Cantrill {
104*7aa76ffcSBryan Cantrill 	kstat_instance_t *l = *((kstat_instance_t **)lhs);
105*7aa76ffcSBryan Cantrill 	kstat_instance_t *r = *((kstat_instance_t **)rhs);
106*7aa76ffcSBryan Cantrill 	int rval;
107*7aa76ffcSBryan Cantrill 
108*7aa76ffcSBryan Cantrill 	if ((rval = strcmp(l->ksi_name, r->ksi_name)) != 0)
109*7aa76ffcSBryan Cantrill 		return (rval);
110*7aa76ffcSBryan Cantrill 
111*7aa76ffcSBryan Cantrill 	if (l->ksi_instance < r->ksi_instance)
112*7aa76ffcSBryan Cantrill 		return (-1);
113*7aa76ffcSBryan Cantrill 
114*7aa76ffcSBryan Cantrill 	if (l->ksi_instance > r->ksi_instance)
115*7aa76ffcSBryan Cantrill 		return (1);
116*7aa76ffcSBryan Cantrill 
117*7aa76ffcSBryan Cantrill 	return (0);
118*7aa76ffcSBryan Cantrill }
119*7aa76ffcSBryan Cantrill 
120*7aa76ffcSBryan Cantrill void
kstat_instances_update(kstat_ctl_t * kcp,kstat_instance_t ** head,boolean_t (* interested)(kstat_t *))121*7aa76ffcSBryan Cantrill kstat_instances_update(kstat_ctl_t *kcp, kstat_instance_t **head,
122*7aa76ffcSBryan Cantrill     boolean_t (*interested)(kstat_t *))
123*7aa76ffcSBryan Cantrill {
124*7aa76ffcSBryan Cantrill 	int ninstances = 0, i;
125*7aa76ffcSBryan Cantrill 	kstat_instance_t **sorted, *ksi, *next;
126*7aa76ffcSBryan Cantrill 	kstat_t *ksp;
127*7aa76ffcSBryan Cantrill 	kid_t kid;
128*7aa76ffcSBryan Cantrill 
129*7aa76ffcSBryan Cantrill 	if ((kid = kstat_chain_update(kcp)) == 0 && *head != NULL)
130*7aa76ffcSBryan Cantrill 		return;
131*7aa76ffcSBryan Cantrill 
132*7aa76ffcSBryan Cantrill 	if (kid == -1)
133*7aa76ffcSBryan Cantrill 		fatal("failed to update kstat chain");
134*7aa76ffcSBryan Cantrill 
135*7aa76ffcSBryan Cantrill 	for (ksi = *head; ksi != NULL; ksi = ksi->ksi_next)
136*7aa76ffcSBryan Cantrill 		ksi->ksi_ksp = NULL;
137*7aa76ffcSBryan Cantrill 
138*7aa76ffcSBryan Cantrill 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
139*7aa76ffcSBryan Cantrill 		kstat_instance_t *last = NULL;
140*7aa76ffcSBryan Cantrill 
141*7aa76ffcSBryan Cantrill 		if (!interested(ksp))
142*7aa76ffcSBryan Cantrill 			continue;
143*7aa76ffcSBryan Cantrill 
144*7aa76ffcSBryan Cantrill 		/*
145*7aa76ffcSBryan Cantrill 		 * Now look to see if we have this instance and name.  (Yes,
146*7aa76ffcSBryan Cantrill 		 * this is a linear search; we're assuming that this list is
147*7aa76ffcSBryan Cantrill 		 * modest in size.)
148*7aa76ffcSBryan Cantrill 		 */
149*7aa76ffcSBryan Cantrill 		for (ksi = *head; ksi != NULL; ksi = ksi->ksi_next) {
150*7aa76ffcSBryan Cantrill 			last = ksi;
151*7aa76ffcSBryan Cantrill 
152*7aa76ffcSBryan Cantrill 			if (ksi->ksi_instance != ksp->ks_instance)
153*7aa76ffcSBryan Cantrill 				continue;
154*7aa76ffcSBryan Cantrill 
155*7aa76ffcSBryan Cantrill 			if (strcmp(ksi->ksi_name, ksp->ks_name) != 0)
156*7aa76ffcSBryan Cantrill 				continue;
157*7aa76ffcSBryan Cantrill 
158*7aa76ffcSBryan Cantrill 			ksi->ksi_ksp = ksp;
159*7aa76ffcSBryan Cantrill 			ninstances++;
160*7aa76ffcSBryan Cantrill 			break;
161*7aa76ffcSBryan Cantrill 		}
162*7aa76ffcSBryan Cantrill 
163*7aa76ffcSBryan Cantrill 		if (ksi != NULL)
164*7aa76ffcSBryan Cantrill 			continue;
165*7aa76ffcSBryan Cantrill 
166*7aa76ffcSBryan Cantrill 		if ((ksi = malloc(sizeof (kstat_instance_t))) == NULL)
167*7aa76ffcSBryan Cantrill 			fatal("could not allocate memory for stat instance");
168*7aa76ffcSBryan Cantrill 
169*7aa76ffcSBryan Cantrill 		bzero(ksi, sizeof (kstat_instance_t));
170*7aa76ffcSBryan Cantrill 		(void) strlcpy(ksi->ksi_name, ksp->ks_name, KSTAT_STRLEN);
171*7aa76ffcSBryan Cantrill 		ksi->ksi_instance = ksp->ks_instance;
172*7aa76ffcSBryan Cantrill 		ksi->ksi_ksp = ksp;
173*7aa76ffcSBryan Cantrill 		ksi->ksi_next = NULL;
174*7aa76ffcSBryan Cantrill 
175*7aa76ffcSBryan Cantrill 		if (last == NULL) {
176*7aa76ffcSBryan Cantrill 			assert(*head == NULL);
177*7aa76ffcSBryan Cantrill 			*head = ksi;
178*7aa76ffcSBryan Cantrill 		} else {
179*7aa76ffcSBryan Cantrill 			last->ksi_next = ksi;
180*7aa76ffcSBryan Cantrill 		}
181*7aa76ffcSBryan Cantrill 
182*7aa76ffcSBryan Cantrill 		ninstances++;
183*7aa76ffcSBryan Cantrill 	}
184*7aa76ffcSBryan Cantrill 
185*7aa76ffcSBryan Cantrill 	/*
186*7aa76ffcSBryan Cantrill 	 * Now we know how many instances we have; iterate back over them,
187*7aa76ffcSBryan Cantrill 	 * pruning the stale ones and adding the active ones to a holding
188*7aa76ffcSBryan Cantrill 	 * array in which to sort them.
189*7aa76ffcSBryan Cantrill 	 */
190*7aa76ffcSBryan Cantrill 	sorted = (void *)alloca(ninstances * sizeof (kstat_instance_t *));
191*7aa76ffcSBryan Cantrill 	ninstances = 0;
192*7aa76ffcSBryan Cantrill 
193*7aa76ffcSBryan Cantrill 	for (ksi = *head; ksi != NULL; ksi = next) {
194*7aa76ffcSBryan Cantrill 		next = ksi->ksi_next;
195*7aa76ffcSBryan Cantrill 
196*7aa76ffcSBryan Cantrill 		if (ksi->ksi_ksp == NULL) {
197*7aa76ffcSBryan Cantrill 			free(ksi);
198*7aa76ffcSBryan Cantrill 		} else {
199*7aa76ffcSBryan Cantrill 			sorted[ninstances++] = ksi;
200*7aa76ffcSBryan Cantrill 		}
201*7aa76ffcSBryan Cantrill 	}
202*7aa76ffcSBryan Cantrill 
203*7aa76ffcSBryan Cantrill 	if (ninstances == 0) {
204*7aa76ffcSBryan Cantrill 		*head = NULL;
205*7aa76ffcSBryan Cantrill 		return;
206*7aa76ffcSBryan Cantrill 	}
207*7aa76ffcSBryan Cantrill 
208*7aa76ffcSBryan Cantrill 	qsort(sorted, ninstances, sizeof (kstat_instance_t *),
209*7aa76ffcSBryan Cantrill 	    kstat_instances_compare);
210*7aa76ffcSBryan Cantrill 
211*7aa76ffcSBryan Cantrill 	*head = sorted[0];
212*7aa76ffcSBryan Cantrill 
213*7aa76ffcSBryan Cantrill 	for (i = 0; i < ninstances; i++) {
214*7aa76ffcSBryan Cantrill 		ksi = sorted[i];
215*7aa76ffcSBryan Cantrill 		ksi->ksi_next = i < ninstances - 1 ? sorted[i + 1] : NULL;
216*7aa76ffcSBryan Cantrill 	}
217*7aa76ffcSBryan Cantrill }
218*7aa76ffcSBryan Cantrill 
219*7aa76ffcSBryan Cantrill void
kstat_instances_read(kstat_ctl_t * kcp,kstat_instance_t * instances,kstat_field_t * fields)220*7aa76ffcSBryan Cantrill kstat_instances_read(kstat_ctl_t *kcp, kstat_instance_t *instances,
221*7aa76ffcSBryan Cantrill     kstat_field_t *fields)
222*7aa76ffcSBryan Cantrill {
223*7aa76ffcSBryan Cantrill 	kstat_instance_t *ksi;
224*7aa76ffcSBryan Cantrill 	int i, nfields;
225*7aa76ffcSBryan Cantrill 
226*7aa76ffcSBryan Cantrill 	for (nfields = 0; fields[nfields].ksf_header != NULL; nfields++)
227*7aa76ffcSBryan Cantrill 		continue;
228*7aa76ffcSBryan Cantrill 
229*7aa76ffcSBryan Cantrill 	for (ksi = instances; ksi != NULL; ksi = ksi->ksi_next) {
230*7aa76ffcSBryan Cantrill 		kstat_t *ksp = ksi->ksi_ksp;
231*7aa76ffcSBryan Cantrill 
232*7aa76ffcSBryan Cantrill 		if (ksp == NULL)
233*7aa76ffcSBryan Cantrill 			continue;
234*7aa76ffcSBryan Cantrill 
235*7aa76ffcSBryan Cantrill 		if (kstat_read(kcp, ksp, NULL) == -1) {
236*7aa76ffcSBryan Cantrill 			if (errno == ENXIO) {
237*7aa76ffcSBryan Cantrill 				/*
238*7aa76ffcSBryan Cantrill 				 * Our kstat has been removed since the update;
239*7aa76ffcSBryan Cantrill 				 * NULL it out to prevent us from trying to read
240*7aa76ffcSBryan Cantrill 				 * it again (and to indicate that it should not
241*7aa76ffcSBryan Cantrill 				 * be displayed) and drive on.
242*7aa76ffcSBryan Cantrill 				 */
243*7aa76ffcSBryan Cantrill 				ksi->ksi_ksp = NULL;
244*7aa76ffcSBryan Cantrill 				continue;
245*7aa76ffcSBryan Cantrill 			}
246*7aa76ffcSBryan Cantrill 
247*7aa76ffcSBryan Cantrill 			fatal("failed to read kstat %s:%d",
248*7aa76ffcSBryan Cantrill 			    ksi->ksi_name, ksi->ksi_instance);
249*7aa76ffcSBryan Cantrill 		}
250*7aa76ffcSBryan Cantrill 
251*7aa76ffcSBryan Cantrill 		if (ksp->ks_type != KSTAT_TYPE_NAMED) {
252*7aa76ffcSBryan Cantrill 			fatal("%s:%d is not a named kstat", ksi->ksi_name,
253*7aa76ffcSBryan Cantrill 			    ksi->ksi_instance);
254*7aa76ffcSBryan Cantrill 		}
255*7aa76ffcSBryan Cantrill 
256*7aa76ffcSBryan Cantrill 		if (ksi->ksi_data[0] == NULL) {
257*7aa76ffcSBryan Cantrill 			size_t size = nfields * sizeof (uint64_t) * 2;
258*7aa76ffcSBryan Cantrill 			uint64_t *data;
259*7aa76ffcSBryan Cantrill 
260*7aa76ffcSBryan Cantrill 			if ((data = malloc(size)) == NULL)
261*7aa76ffcSBryan Cantrill 				fatal("could not allocate memory");
262*7aa76ffcSBryan Cantrill 
263*7aa76ffcSBryan Cantrill 			bzero(data, size);
264*7aa76ffcSBryan Cantrill 			ksi->ksi_data[0] = data;
265*7aa76ffcSBryan Cantrill 			ksi->ksi_data[1] = &data[nfields];
266*7aa76ffcSBryan Cantrill 		}
267*7aa76ffcSBryan Cantrill 
268*7aa76ffcSBryan Cantrill 		for (i = 0; i < nfields; i++) {
269*7aa76ffcSBryan Cantrill 			kstat_named_t *nm = KSTAT_NAMED_PTR(ksp);
270*7aa76ffcSBryan Cantrill 			kstat_field_t *field = &fields[i];
271*7aa76ffcSBryan Cantrill 			int hint = field->ksf_hint;
272*7aa76ffcSBryan Cantrill 
273*7aa76ffcSBryan Cantrill 			if (field->ksf_name == NULL)
274*7aa76ffcSBryan Cantrill 				continue;
275*7aa76ffcSBryan Cantrill 
276*7aa76ffcSBryan Cantrill 			if (hint < 0 || hint >= ksp->ks_ndata ||
277*7aa76ffcSBryan Cantrill 			    strcmp(field->ksf_name, nm[hint].name) != 0) {
278*7aa76ffcSBryan Cantrill 				hint = kstat_field_hint(ksp, field);
279*7aa76ffcSBryan Cantrill 			}
280*7aa76ffcSBryan Cantrill 
281*7aa76ffcSBryan Cantrill 			ksi->ksi_data[ksi->ksi_gen][i] = nm[hint].value.ui64;
282*7aa76ffcSBryan Cantrill 		}
283*7aa76ffcSBryan Cantrill 
284*7aa76ffcSBryan Cantrill 		ksi->ksi_snaptime[ksi->ksi_gen] = ksp->ks_snaptime;
285*7aa76ffcSBryan Cantrill 		ksi->ksi_gen ^= 1;
286*7aa76ffcSBryan Cantrill 	}
287*7aa76ffcSBryan Cantrill }
288*7aa76ffcSBryan Cantrill 
289*7aa76ffcSBryan Cantrill uint64_t
kstat_instances_delta(kstat_instance_t * ksi,int i)290*7aa76ffcSBryan Cantrill kstat_instances_delta(kstat_instance_t *ksi, int i)
291*7aa76ffcSBryan Cantrill {
292*7aa76ffcSBryan Cantrill 	int gen = ksi->ksi_gen;
293*7aa76ffcSBryan Cantrill 	uint64_t delta = ksi->ksi_data[gen ^ 1][i] - ksi->ksi_data[gen][i];
294*7aa76ffcSBryan Cantrill 	uint64_t tdelta = ksi->ksi_snaptime[gen ^ 1] - ksi->ksi_snaptime[gen];
295*7aa76ffcSBryan Cantrill 
296*7aa76ffcSBryan Cantrill 	return (((delta * (uint64_t)NANOSEC) + (tdelta / 2)) / tdelta);
297*7aa76ffcSBryan Cantrill }
298*7aa76ffcSBryan Cantrill 
299*7aa76ffcSBryan Cantrill void
kstat_instances_print(kstat_instance_t * instances,kstat_field_t * fields,boolean_t header)300*7aa76ffcSBryan Cantrill kstat_instances_print(kstat_instance_t *instances, kstat_field_t *fields,
301*7aa76ffcSBryan Cantrill     boolean_t header)
302*7aa76ffcSBryan Cantrill {
303*7aa76ffcSBryan Cantrill 	kstat_instance_t *ksi = instances;
304*7aa76ffcSBryan Cantrill 	int i, nfields;
305*7aa76ffcSBryan Cantrill 
306*7aa76ffcSBryan Cantrill 	for (nfields = 0; fields[nfields].ksf_header != NULL; nfields++)
307*7aa76ffcSBryan Cantrill 		continue;
308*7aa76ffcSBryan Cantrill 
309*7aa76ffcSBryan Cantrill 	if (header) {
310*7aa76ffcSBryan Cantrill 		for (i = 0; i < nfields; i++) {
311*7aa76ffcSBryan Cantrill 			(void) printf("%*s%c", fields[i].ksf_width,
312*7aa76ffcSBryan Cantrill 			    fields[i].ksf_header, i < nfields - 1 ? ' ' : '\n');
313*7aa76ffcSBryan Cantrill 		}
314*7aa76ffcSBryan Cantrill 	}
315*7aa76ffcSBryan Cantrill 
316*7aa76ffcSBryan Cantrill 	for (ksi = instances; ksi != NULL; ksi = ksi->ksi_next) {
317*7aa76ffcSBryan Cantrill 		if (ksi->ksi_snaptime[1] == 0 || ksi->ksi_ksp == NULL)
318*7aa76ffcSBryan Cantrill 			continue;
319*7aa76ffcSBryan Cantrill 
320*7aa76ffcSBryan Cantrill 		for (i = 0; i < nfields; i++) {
321*7aa76ffcSBryan Cantrill 			char trailer = i < nfields - 1 ? ' ' : '\n';
322*7aa76ffcSBryan Cantrill 
323*7aa76ffcSBryan Cantrill 			if (fields[i].ksf_flags & KSTAT_FIELD_FILLER) {
324*7aa76ffcSBryan Cantrill 				(void) printf("%*s%c", fields[i].ksf_width,
325*7aa76ffcSBryan Cantrill 				    fields[i].ksf_header, trailer);
326*7aa76ffcSBryan Cantrill 				continue;
327*7aa76ffcSBryan Cantrill 			}
328*7aa76ffcSBryan Cantrill 
329*7aa76ffcSBryan Cantrill 			(void) printf("%*lld%c", fields[i].ksf_width,
330*7aa76ffcSBryan Cantrill 			    fields[i].ksf_flags & KSTAT_FIELD_USEINSTANCE ?
331*7aa76ffcSBryan Cantrill 			    ksi->ksi_instance :
332*7aa76ffcSBryan Cantrill 			    fields[i].ksf_flags & KSTAT_FIELD_NODELTA ?
333*7aa76ffcSBryan Cantrill 			    ksi->ksi_data[ksi->ksi_gen ^ 1][i] :
334*7aa76ffcSBryan Cantrill 			    kstat_instances_delta(ksi, i), trailer);
335*7aa76ffcSBryan Cantrill 		}
336*7aa76ffcSBryan Cantrill 	}
337*7aa76ffcSBryan Cantrill }
338*7aa76ffcSBryan Cantrill 
339*7aa76ffcSBryan Cantrill boolean_t
interested(kstat_t * ksp)340*7aa76ffcSBryan Cantrill interested(kstat_t *ksp)
341*7aa76ffcSBryan Cantrill {
342*7aa76ffcSBryan Cantrill 	const char *module = "kvm";
343*7aa76ffcSBryan Cantrill 	const char *class = "misc";
344*7aa76ffcSBryan Cantrill 	const char *name = "vcpu-";
345*7aa76ffcSBryan Cantrill 
346*7aa76ffcSBryan Cantrill 	if (strcmp(ksp->ks_module, module) != 0)
347*7aa76ffcSBryan Cantrill 		return (B_FALSE);
348*7aa76ffcSBryan Cantrill 
349*7aa76ffcSBryan Cantrill 	if (strcmp(ksp->ks_class, class) != 0)
350*7aa76ffcSBryan Cantrill 		return (B_FALSE);
351*7aa76ffcSBryan Cantrill 
352*7aa76ffcSBryan Cantrill 	if (strstr(ksp->ks_name, name) != ksp->ks_name)
353*7aa76ffcSBryan Cantrill 		return (B_FALSE);
354*7aa76ffcSBryan Cantrill 
355*7aa76ffcSBryan Cantrill 	return (B_TRUE);
356*7aa76ffcSBryan Cantrill }
357*7aa76ffcSBryan Cantrill 
358*7aa76ffcSBryan Cantrill /* BEGIN CSTYLED */
359*7aa76ffcSBryan Cantrill char *g_usage = "Usage: kvmstat [interval [count]]\n"
360*7aa76ffcSBryan Cantrill     "\n"
361*7aa76ffcSBryan Cantrill     "  Displays statistics for running kernel virtual machines, with one line\n"
362*7aa76ffcSBryan Cantrill     "  per virtual CPU.  All statistics are reported as per-second rates.\n"
363*7aa76ffcSBryan Cantrill     "\n"
364*7aa76ffcSBryan Cantrill     "  The columns are as follows:\n"
365*7aa76ffcSBryan Cantrill     "\n"
366*7aa76ffcSBryan Cantrill     "    pid    =>  identifier of process controlling the virtual CPU\n"
367*7aa76ffcSBryan Cantrill     "    vcpu   =>  virtual CPU identifier relative to its virtual machine\n"
368*7aa76ffcSBryan Cantrill     "    exits  =>  virtual machine exits for the virtual CPU\n"
369*7aa76ffcSBryan Cantrill     "    haltx  =>  virtual machine exits due to the HLT instruction\n"
370*7aa76ffcSBryan Cantrill     "    irqx   =>  virtual machine exits due to a pending external interrupt\n"
371*7aa76ffcSBryan Cantrill     "    irqwx  =>  virtual machine exits due to an open interrupt window\n"
372*7aa76ffcSBryan Cantrill     "    iox    =>  virtual machine exits due to an I/O instruction\n"
373*7aa76ffcSBryan Cantrill     "    mmiox  =>  virtual machine exits due to memory mapped I/O \n"
374*7aa76ffcSBryan Cantrill     "    irqs   =>  interrupts injected into the virtual CPU\n"
375*7aa76ffcSBryan Cantrill     "    emul   =>  instructions emulated in the kernel\n"
376*7aa76ffcSBryan Cantrill     "    eptv   =>  extended page table violations\n"
377*7aa76ffcSBryan Cantrill     "\n";
378*7aa76ffcSBryan Cantrill /* END CSTYLED */
379*7aa76ffcSBryan Cantrill 
380*7aa76ffcSBryan Cantrill void
usage()381*7aa76ffcSBryan Cantrill usage()
382*7aa76ffcSBryan Cantrill {
383*7aa76ffcSBryan Cantrill 	(void) fprintf(stderr, "%s", g_usage);
384*7aa76ffcSBryan Cantrill 	exit(EXIT_FAILURE);
385*7aa76ffcSBryan Cantrill }
386*7aa76ffcSBryan Cantrill 
387*7aa76ffcSBryan Cantrill /*ARGSUSED*/
388*7aa76ffcSBryan Cantrill void
intr(int sig)389*7aa76ffcSBryan Cantrill intr(int sig)
390*7aa76ffcSBryan Cantrill {}
391*7aa76ffcSBryan Cantrill 
392*7aa76ffcSBryan Cantrill /*ARGSUSED*/
393*7aa76ffcSBryan Cantrill int
main(int argc,char ** argv)394*7aa76ffcSBryan Cantrill main(int argc, char **argv)
395*7aa76ffcSBryan Cantrill {
396*7aa76ffcSBryan Cantrill 	kstat_ctl_t *kcp;
397*7aa76ffcSBryan Cantrill 	kstat_instance_t *instances = NULL;
398*7aa76ffcSBryan Cantrill 	int i = 0;
399*7aa76ffcSBryan Cantrill 	int interval = 1;
400*7aa76ffcSBryan Cantrill 	int count = INT32_MAX;
401*7aa76ffcSBryan Cantrill 	struct itimerval itimer;
402*7aa76ffcSBryan Cantrill 	struct sigaction act;
403*7aa76ffcSBryan Cantrill 	sigset_t set;
404*7aa76ffcSBryan Cantrill 	char *endp;
405*7aa76ffcSBryan Cantrill 
406*7aa76ffcSBryan Cantrill 	kstat_field_t fields[] =  {
407*7aa76ffcSBryan Cantrill 		{ "pid", "pid", 6, KSTAT_FIELD_NODELTA },
408*7aa76ffcSBryan Cantrill 		{ "vcpu", NULL, 4, KSTAT_FIELD_USEINSTANCE },
409*7aa76ffcSBryan Cantrill 		{ "|", NULL, 1, KSTAT_FIELD_FILLER },
410*7aa76ffcSBryan Cantrill 		{ "exits", "exits", 6 },
411*7aa76ffcSBryan Cantrill 		{ ":", NULL, 1, KSTAT_FIELD_FILLER },
412*7aa76ffcSBryan Cantrill 		{ "haltx", "halt-exits", 6 },
413*7aa76ffcSBryan Cantrill 		{ "irqx", "irq-exits", 6 },
414*7aa76ffcSBryan Cantrill 		{ "irqwx", "irq-window-exits", 6 },
415*7aa76ffcSBryan Cantrill 		{ "iox", "io-exits", 6 },
416*7aa76ffcSBryan Cantrill 		{ "mmiox", "mmio-exits", 6 },
417*7aa76ffcSBryan Cantrill 		{ "|", NULL, 1, KSTAT_FIELD_FILLER },
418*7aa76ffcSBryan Cantrill 		{ "irqs", "irq-injections", 6 },
419*7aa76ffcSBryan Cantrill 		{ "emul", "insn-emulation", 6 },
420*7aa76ffcSBryan Cantrill 		{ "eptv", "pf-fixed", 6 },
421*7aa76ffcSBryan Cantrill 		{ NULL }
422*7aa76ffcSBryan Cantrill 	};
423*7aa76ffcSBryan Cantrill 
424*7aa76ffcSBryan Cantrill 	if (argc > 1) {
425*7aa76ffcSBryan Cantrill 		interval = strtol(argv[1], &endp, 10);
426*7aa76ffcSBryan Cantrill 
427*7aa76ffcSBryan Cantrill 		if (*endp != '\0' || interval <= 0)
428*7aa76ffcSBryan Cantrill 			usage();
429*7aa76ffcSBryan Cantrill 	}
430*7aa76ffcSBryan Cantrill 
431*7aa76ffcSBryan Cantrill 	if (argc > 2) {
432*7aa76ffcSBryan Cantrill 		count = strtol(argv[2], &endp, 10);
433*7aa76ffcSBryan Cantrill 
434*7aa76ffcSBryan Cantrill 		if (*endp != '\0' || count <= 0)
435*7aa76ffcSBryan Cantrill 			usage();
436*7aa76ffcSBryan Cantrill 	}
437*7aa76ffcSBryan Cantrill 
438*7aa76ffcSBryan Cantrill 	if ((kcp = kstat_open()) == NULL)
439*7aa76ffcSBryan Cantrill 		fatal("could not open /dev/kstat");
440*7aa76ffcSBryan Cantrill 
441*7aa76ffcSBryan Cantrill 	(void) sigemptyset(&act.sa_mask);
442*7aa76ffcSBryan Cantrill 	act.sa_flags = 0;
443*7aa76ffcSBryan Cantrill 	act.sa_handler = intr;
444*7aa76ffcSBryan Cantrill 	(void) sigaction(SIGALRM, &act, NULL);
445*7aa76ffcSBryan Cantrill 
446*7aa76ffcSBryan Cantrill 	(void) sigemptyset(&set);
447*7aa76ffcSBryan Cantrill 	(void) sigaddset(&set, SIGALRM);
448*7aa76ffcSBryan Cantrill 	(void) sigprocmask(SIG_BLOCK, &set, NULL);
449*7aa76ffcSBryan Cantrill 
450*7aa76ffcSBryan Cantrill 	bzero(&itimer, sizeof (itimer));
451*7aa76ffcSBryan Cantrill 	itimer.it_value.tv_sec = interval;
452*7aa76ffcSBryan Cantrill 	itimer.it_interval.tv_sec = interval;
453*7aa76ffcSBryan Cantrill 
454*7aa76ffcSBryan Cantrill 	if (setitimer(ITIMER_REAL, &itimer, NULL) != 0) {
455*7aa76ffcSBryan Cantrill 		fatal("could not set timer to %d second%s", interval,
456*7aa76ffcSBryan Cantrill 		    interval == 1 ? "" : "s");
457*7aa76ffcSBryan Cantrill 	}
458*7aa76ffcSBryan Cantrill 
459*7aa76ffcSBryan Cantrill 	(void) sigemptyset(&set);
460*7aa76ffcSBryan Cantrill 
461*7aa76ffcSBryan Cantrill 	for (;;) {
462*7aa76ffcSBryan Cantrill 		kstat_instances_update(kcp, &instances, interested);
463*7aa76ffcSBryan Cantrill 		kstat_instances_read(kcp, instances, fields);
464*7aa76ffcSBryan Cantrill 
465*7aa76ffcSBryan Cantrill 		if (i++ > 0) {
466*7aa76ffcSBryan Cantrill 			kstat_instances_print(instances, fields,
467*7aa76ffcSBryan Cantrill 			    instances != NULL && instances->ksi_next == NULL ?
468*7aa76ffcSBryan Cantrill 			    (((i - 2) % 20) == 0) : B_TRUE);
469*7aa76ffcSBryan Cantrill 		}
470*7aa76ffcSBryan Cantrill 
471*7aa76ffcSBryan Cantrill 		if (i > count)
472*7aa76ffcSBryan Cantrill 			break;
473*7aa76ffcSBryan Cantrill 
474*7aa76ffcSBryan Cantrill 		(void) sigsuspend(&set);
475*7aa76ffcSBryan Cantrill 	}
476*7aa76ffcSBryan Cantrill 
477*7aa76ffcSBryan Cantrill 	/*NOTREACHED*/
478*7aa76ffcSBryan Cantrill 	return (0);
479*7aa76ffcSBryan Cantrill }
480