xref: /titanic_50/usr/src/cmd/stat/common/acquire.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "statcommon.h"
30*7c478bd9Sstevel@tonic-gate #include "dsr.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
34*7c478bd9Sstevel@tonic-gate #include <unistd.h>
35*7c478bd9Sstevel@tonic-gate #include <strings.h>
36*7c478bd9Sstevel@tonic-gate #include <errno.h>
37*7c478bd9Sstevel@tonic-gate #include <poll.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #define	ARRAY_SIZE(a)	(sizeof (a) / sizeof (*a))
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate  * The time we delay before retrying after an allocation
43*7c478bd9Sstevel@tonic-gate  * failure, in milliseconds
44*7c478bd9Sstevel@tonic-gate  */
45*7c478bd9Sstevel@tonic-gate #define	RETRY_DELAY 200
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate static char *cpu_states[] = {
48*7c478bd9Sstevel@tonic-gate 	"cpu_ticks_idle",
49*7c478bd9Sstevel@tonic-gate 	"cpu_ticks_user",
50*7c478bd9Sstevel@tonic-gate 	"cpu_ticks_kernel",
51*7c478bd9Sstevel@tonic-gate 	"cpu_ticks_wait"
52*7c478bd9Sstevel@tonic-gate };
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate extern char cmdname[];
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate static kstat_t *
57*7c478bd9Sstevel@tonic-gate kstat_lookup_read(kstat_ctl_t *kc, char *module,
58*7c478bd9Sstevel@tonic-gate 		int instance, char *name)
59*7c478bd9Sstevel@tonic-gate {
60*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp = kstat_lookup(kc, module, instance, name);
61*7c478bd9Sstevel@tonic-gate 	if (ksp == NULL)
62*7c478bd9Sstevel@tonic-gate 		return (NULL);
63*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1)
64*7c478bd9Sstevel@tonic-gate 		return (NULL);
65*7c478bd9Sstevel@tonic-gate 	return (ksp);
66*7c478bd9Sstevel@tonic-gate }
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate /*
69*7c478bd9Sstevel@tonic-gate  * Note: the following helpers do not clean up on the failure case,
70*7c478bd9Sstevel@tonic-gate  * because it is left to the free_snapshot() in the acquire_snapshot()
71*7c478bd9Sstevel@tonic-gate  * failure path.
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate static int
75*7c478bd9Sstevel@tonic-gate acquire_cpus(struct snapshot *ss, kstat_ctl_t *kc)
76*7c478bd9Sstevel@tonic-gate {
77*7c478bd9Sstevel@tonic-gate 	size_t i;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	ss->s_nr_cpus = sysconf(_SC_CPUID_MAX) + 1;
80*7c478bd9Sstevel@tonic-gate 	ss->s_cpus = calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot));
81*7c478bd9Sstevel@tonic-gate 	if (ss->s_cpus == NULL)
82*7c478bd9Sstevel@tonic-gate 		goto out;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ss->s_nr_cpus; i++) {
85*7c478bd9Sstevel@tonic-gate 		kstat_t *ksp;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 		ss->s_cpus[i].cs_id = ID_NO_CPU;
88*7c478bd9Sstevel@tonic-gate 		ss->s_cpus[i].cs_state = p_online(i, P_STATUS);
89*7c478bd9Sstevel@tonic-gate 		/* If no valid CPU is present, move on to the next one */
90*7c478bd9Sstevel@tonic-gate 		if (ss->s_cpus[i].cs_state == -1)
91*7c478bd9Sstevel@tonic-gate 			continue;
92*7c478bd9Sstevel@tonic-gate 		ss->s_cpus[i].cs_id = i;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 		if ((ksp = kstat_lookup_read(kc, "cpu_info", i, NULL)) == NULL)
95*7c478bd9Sstevel@tonic-gate 			goto out;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 		(void) pset_assign(PS_QUERY, i, &ss->s_cpus[i].cs_pset_id);
98*7c478bd9Sstevel@tonic-gate 		if (ss->s_cpus[i].cs_pset_id == PS_NONE)
99*7c478bd9Sstevel@tonic-gate 			ss->s_cpus[i].cs_pset_id = ID_NO_PSET;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 		if (!CPU_ACTIVE(&ss->s_cpus[i]))
102*7c478bd9Sstevel@tonic-gate 			continue;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 		if ((ksp = kstat_lookup_read(kc, "cpu", i, "vm")) == NULL)
105*7c478bd9Sstevel@tonic-gate 			goto out;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 		if (kstat_copy(ksp, &ss->s_cpus[i].cs_vm))
108*7c478bd9Sstevel@tonic-gate 			goto out;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 		if ((ksp = kstat_lookup_read(kc, "cpu", i, "sys")) == NULL)
111*7c478bd9Sstevel@tonic-gate 			goto out;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 		if (kstat_copy(ksp, &ss->s_cpus[i].cs_sys))
114*7c478bd9Sstevel@tonic-gate 			goto out;
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	errno = 0;
118*7c478bd9Sstevel@tonic-gate out:
119*7c478bd9Sstevel@tonic-gate 	return (errno);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate static int
123*7c478bd9Sstevel@tonic-gate acquire_psets(struct snapshot *ss)
124*7c478bd9Sstevel@tonic-gate {
125*7c478bd9Sstevel@tonic-gate 	psetid_t *pids = NULL;
126*7c478bd9Sstevel@tonic-gate 	struct pset_snapshot *ps;
127*7c478bd9Sstevel@tonic-gate 	size_t pids_nr;
128*7c478bd9Sstevel@tonic-gate 	size_t i, j;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/*
131*7c478bd9Sstevel@tonic-gate 	 * Careful in this code. We have to use pset_list
132*7c478bd9Sstevel@tonic-gate 	 * twice, but inbetween pids_nr can change at will.
133*7c478bd9Sstevel@tonic-gate 	 * We delay the setting of s_nr_psets until we have
134*7c478bd9Sstevel@tonic-gate 	 * the "final" value of pids_nr.
135*7c478bd9Sstevel@tonic-gate 	 */
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	if (pset_list(NULL, &pids_nr) < 0)
138*7c478bd9Sstevel@tonic-gate 		return (errno);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	if ((pids = calloc(pids_nr, sizeof (psetid_t))) == NULL)
141*7c478bd9Sstevel@tonic-gate 		goto out;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	if (pset_list(pids, &pids_nr) < 0)
144*7c478bd9Sstevel@tonic-gate 		goto out;
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	ss->s_psets = calloc(pids_nr + 1, sizeof (struct pset_snapshot));
147*7c478bd9Sstevel@tonic-gate 	if (ss->s_psets == NULL)
148*7c478bd9Sstevel@tonic-gate 		goto out;
149*7c478bd9Sstevel@tonic-gate 	ss->s_nr_psets = pids_nr + 1;
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	/* CPUs not in any actual pset */
152*7c478bd9Sstevel@tonic-gate 	ps = &ss->s_psets[0];
153*7c478bd9Sstevel@tonic-gate 	ps->ps_id = 0;
154*7c478bd9Sstevel@tonic-gate 	ps->ps_cpus = calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot *));
155*7c478bd9Sstevel@tonic-gate 	if (ps->ps_cpus == NULL)
156*7c478bd9Sstevel@tonic-gate 		goto out;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	/* CPUs in a a pset */
159*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < ss->s_nr_psets; i++) {
160*7c478bd9Sstevel@tonic-gate 		ps = &ss->s_psets[i];
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 		ps->ps_id = pids[i - 1];
163*7c478bd9Sstevel@tonic-gate 		ps->ps_cpus =
164*7c478bd9Sstevel@tonic-gate 			calloc(ss->s_nr_cpus, sizeof (struct cpu_snapshot *));
165*7c478bd9Sstevel@tonic-gate 		if (ps->ps_cpus == NULL)
166*7c478bd9Sstevel@tonic-gate 			goto out;
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ss->s_nr_psets; i++) {
170*7c478bd9Sstevel@tonic-gate 		ps = &ss->s_psets[i];
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < ss->s_nr_cpus; j++) {
173*7c478bd9Sstevel@tonic-gate 			if (!CPU_ACTIVE(&ss->s_cpus[j]))
174*7c478bd9Sstevel@tonic-gate 				continue;
175*7c478bd9Sstevel@tonic-gate 			if (ss->s_cpus[j].cs_pset_id != ps->ps_id)
176*7c478bd9Sstevel@tonic-gate 				continue;
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 			ps->ps_cpus[ps->ps_nr_cpus++] = &ss->s_cpus[j];
179*7c478bd9Sstevel@tonic-gate 		}
180*7c478bd9Sstevel@tonic-gate 	}
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	errno = 0;
183*7c478bd9Sstevel@tonic-gate out:
184*7c478bd9Sstevel@tonic-gate 	free(pids);
185*7c478bd9Sstevel@tonic-gate 	return (errno);
186*7c478bd9Sstevel@tonic-gate }
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate static int
189*7c478bd9Sstevel@tonic-gate acquire_intrs(struct snapshot *ss, kstat_ctl_t *kc)
190*7c478bd9Sstevel@tonic-gate {
191*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
192*7c478bd9Sstevel@tonic-gate 	size_t i = 0;
193*7c478bd9Sstevel@tonic-gate 	kstat_t *sys_misc;
194*7c478bd9Sstevel@tonic-gate 	kstat_named_t *clock;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	/* clock interrupt */
197*7c478bd9Sstevel@tonic-gate 	ss->s_nr_intrs = 1;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
200*7c478bd9Sstevel@tonic-gate 		if (ksp->ks_type == KSTAT_TYPE_INTR)
201*7c478bd9Sstevel@tonic-gate 			ss->s_nr_intrs++;
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	ss->s_intrs = calloc(ss->s_nr_intrs, sizeof (struct intr_snapshot));
205*7c478bd9Sstevel@tonic-gate 	if (ss->s_intrs == NULL)
206*7c478bd9Sstevel@tonic-gate 		return (errno);
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	sys_misc = kstat_lookup_read(kc, "unix", 0, "system_misc");
209*7c478bd9Sstevel@tonic-gate 	if (sys_misc == NULL)
210*7c478bd9Sstevel@tonic-gate 		goto out;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	clock = (kstat_named_t *)kstat_data_lookup(sys_misc, "clk_intr");
213*7c478bd9Sstevel@tonic-gate 	if (clock == NULL)
214*7c478bd9Sstevel@tonic-gate 		goto out;
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(ss->s_intrs[0].is_name, "clock", KSTAT_STRLEN);
217*7c478bd9Sstevel@tonic-gate 	ss->s_intrs[0].is_total = clock->value.ui32;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	i = 1;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
222*7c478bd9Sstevel@tonic-gate 		kstat_intr_t *ki;
223*7c478bd9Sstevel@tonic-gate 		int j;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_INTR)
226*7c478bd9Sstevel@tonic-gate 			continue;
227*7c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, ksp, NULL) == -1)
228*7c478bd9Sstevel@tonic-gate 			goto out;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 		ki = KSTAT_INTR_PTR(ksp);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(ss->s_intrs[i].is_name, ksp->ks_name,
233*7c478bd9Sstevel@tonic-gate 			KSTAT_STRLEN);
234*7c478bd9Sstevel@tonic-gate 		ss->s_intrs[i].is_total = 0;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < KSTAT_NUM_INTRS; j++)
237*7c478bd9Sstevel@tonic-gate 			ss->s_intrs[i].is_total += ki->intrs[j];
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 		i++;
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	errno = 0;
243*7c478bd9Sstevel@tonic-gate out:
244*7c478bd9Sstevel@tonic-gate 	return (errno);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate int
248*7c478bd9Sstevel@tonic-gate acquire_sys(struct snapshot *ss, kstat_ctl_t *kc)
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate 	size_t i;
251*7c478bd9Sstevel@tonic-gate 	kstat_named_t *knp;
252*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, "unix", 0, "sysinfo")) == NULL)
255*7c478bd9Sstevel@tonic-gate 		return (errno);
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, &ss->s_sys.ss_sysinfo) == -1)
258*7c478bd9Sstevel@tonic-gate 		return (errno);
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, "unix", 0, "vminfo")) == NULL)
261*7c478bd9Sstevel@tonic-gate 		return (errno);
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, &ss->s_sys.ss_vminfo) == -1)
264*7c478bd9Sstevel@tonic-gate 		return (errno);
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, "unix", 0, "dnlcstats")) == NULL)
267*7c478bd9Sstevel@tonic-gate 		return (errno);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, &ss->s_sys.ss_nc) == -1)
270*7c478bd9Sstevel@tonic-gate 		return (errno);
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, "unix", 0, "system_misc")) == NULL)
273*7c478bd9Sstevel@tonic-gate 		return (errno);
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1)
276*7c478bd9Sstevel@tonic-gate 		return (errno);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	knp = (kstat_named_t *)kstat_data_lookup(ksp, "clk_intr");
279*7c478bd9Sstevel@tonic-gate 	if (knp == NULL)
280*7c478bd9Sstevel@tonic-gate 		return (errno);
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	ss->s_sys.ss_ticks = knp->value.l;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	knp = (kstat_named_t *)kstat_data_lookup(ksp, "deficit");
285*7c478bd9Sstevel@tonic-gate 	if (knp == NULL)
286*7c478bd9Sstevel@tonic-gate 		return (errno);
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	ss->s_sys.ss_deficit = knp->value.l;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ss->s_nr_cpus; i++) {
291*7c478bd9Sstevel@tonic-gate 		if (!CPU_ACTIVE(&ss->s_cpus[i]))
292*7c478bd9Sstevel@tonic-gate 			continue;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 		if (kstat_add(&ss->s_cpus[i].cs_sys, &ss->s_sys.ss_agg_sys))
295*7c478bd9Sstevel@tonic-gate 			return (errno);
296*7c478bd9Sstevel@tonic-gate 		if (kstat_add(&ss->s_cpus[i].cs_vm, &ss->s_sys.ss_agg_vm))
297*7c478bd9Sstevel@tonic-gate 			return (errno);
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	return (0);
301*7c478bd9Sstevel@tonic-gate }
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate struct snapshot *
304*7c478bd9Sstevel@tonic-gate acquire_snapshot(kstat_ctl_t *kc, int types, struct iodev_filter *iodev_filter)
305*7c478bd9Sstevel@tonic-gate {
306*7c478bd9Sstevel@tonic-gate 	struct snapshot *ss = NULL;
307*7c478bd9Sstevel@tonic-gate 	int err;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate retry:
310*7c478bd9Sstevel@tonic-gate 	err = 0;
311*7c478bd9Sstevel@tonic-gate 	/* ensure any partial resources are freed on a retry */
312*7c478bd9Sstevel@tonic-gate 	free_snapshot(ss);
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	ss = safe_alloc(sizeof (struct snapshot));
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	(void) memset(ss, 0, sizeof (struct snapshot));
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	ss->s_types = types;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/* wait for a possibly up-to-date chain */
321*7c478bd9Sstevel@tonic-gate 	while (kstat_chain_update(kc) == -1) {
322*7c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
323*7c478bd9Sstevel@tonic-gate 			(void) poll(NULL, 0, RETRY_DELAY);
324*7c478bd9Sstevel@tonic-gate 		else
325*7c478bd9Sstevel@tonic-gate 			fail(1, "kstat_chain_update failed");
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	if (types & SNAP_FLUSHES) {
329*7c478bd9Sstevel@tonic-gate 		kstat_t *ksp;
330*7c478bd9Sstevel@tonic-gate 		ksp = kstat_lookup(kc, "unix", 0, "flushmeter");
331*7c478bd9Sstevel@tonic-gate 		if (ksp == NULL) {
332*7c478bd9Sstevel@tonic-gate 			fail(0, "This machine does not have "
333*7c478bd9Sstevel@tonic-gate 				"a virtual address cache");
334*7c478bd9Sstevel@tonic-gate 		}
335*7c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, ksp, &ss->s_flushes) == -1)
336*7c478bd9Sstevel@tonic-gate 			err = errno;
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if (!err && (types & SNAP_INTERRUPTS))
340*7c478bd9Sstevel@tonic-gate 		err = acquire_intrs(ss, kc);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if (!err && (types & (SNAP_CPUS | SNAP_SYSTEM | SNAP_PSETS)))
343*7c478bd9Sstevel@tonic-gate 		err = acquire_cpus(ss, kc);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (!err && (types & SNAP_PSETS))
346*7c478bd9Sstevel@tonic-gate 		err = acquire_psets(ss);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	if (!err && (types & (SNAP_IODEVS | SNAP_CONTROLLERS | SNAP_IOPATHS)))
349*7c478bd9Sstevel@tonic-gate 		err = acquire_iodevs(ss, kc, iodev_filter);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	if (!err && (types & SNAP_SYSTEM))
352*7c478bd9Sstevel@tonic-gate 		err = acquire_sys(ss, kc);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	switch (err) {
355*7c478bd9Sstevel@tonic-gate 		case 0:
356*7c478bd9Sstevel@tonic-gate 			break;
357*7c478bd9Sstevel@tonic-gate 		case EAGAIN:
358*7c478bd9Sstevel@tonic-gate 			(void) poll(NULL, 0, RETRY_DELAY);
359*7c478bd9Sstevel@tonic-gate 		/* a kstat disappeared from under us */
360*7c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
361*7c478bd9Sstevel@tonic-gate 		case ENXIO:
362*7c478bd9Sstevel@tonic-gate 		case ENOENT:
363*7c478bd9Sstevel@tonic-gate 			goto retry;
364*7c478bd9Sstevel@tonic-gate 		default:
365*7c478bd9Sstevel@tonic-gate 			fail(1, "acquiring snapshot failed");
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	return (ss);
369*7c478bd9Sstevel@tonic-gate }
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate void
372*7c478bd9Sstevel@tonic-gate free_snapshot(struct snapshot *ss)
373*7c478bd9Sstevel@tonic-gate {
374*7c478bd9Sstevel@tonic-gate 	size_t i;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	if (ss == NULL)
377*7c478bd9Sstevel@tonic-gate 		return;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	while (ss->s_iodevs) {
380*7c478bd9Sstevel@tonic-gate 		struct iodev_snapshot *tmp = ss->s_iodevs;
381*7c478bd9Sstevel@tonic-gate 		ss->s_iodevs = ss->s_iodevs->is_next;
382*7c478bd9Sstevel@tonic-gate 		free_iodev(tmp);
383*7c478bd9Sstevel@tonic-gate 	}
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	if (ss->s_cpus) {
386*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ss->s_nr_cpus; i++) {
387*7c478bd9Sstevel@tonic-gate 			free(ss->s_cpus[i].cs_vm.ks_data);
388*7c478bd9Sstevel@tonic-gate 			free(ss->s_cpus[i].cs_sys.ks_data);
389*7c478bd9Sstevel@tonic-gate 		}
390*7c478bd9Sstevel@tonic-gate 		free(ss->s_cpus);
391*7c478bd9Sstevel@tonic-gate 	}
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	if (ss->s_psets) {
394*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ss->s_nr_psets; i++)
395*7c478bd9Sstevel@tonic-gate 			free(ss->s_psets[i].ps_cpus);
396*7c478bd9Sstevel@tonic-gate 		free(ss->s_psets);
397*7c478bd9Sstevel@tonic-gate 	}
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	free(ss->s_sys.ss_agg_sys.ks_data);
400*7c478bd9Sstevel@tonic-gate 	free(ss->s_sys.ss_agg_vm.ks_data);
401*7c478bd9Sstevel@tonic-gate 	free(ss);
402*7c478bd9Sstevel@tonic-gate }
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate kstat_ctl_t *
405*7c478bd9Sstevel@tonic-gate open_kstat(void)
406*7c478bd9Sstevel@tonic-gate {
407*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t *kc;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	while ((kc = kstat_open()) == NULL) {
410*7c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
411*7c478bd9Sstevel@tonic-gate 			(void) poll(NULL, 0, RETRY_DELAY);
412*7c478bd9Sstevel@tonic-gate 		else
413*7c478bd9Sstevel@tonic-gate 			fail(1, "kstat_open failed");
414*7c478bd9Sstevel@tonic-gate 	}
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	return (kc);
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
420*7c478bd9Sstevel@tonic-gate void
421*7c478bd9Sstevel@tonic-gate fail(int do_perror, char *message, ...)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	va_list args;
424*7c478bd9Sstevel@tonic-gate 	int save_errno = errno;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	va_start(args, message);
427*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", cmdname);
428*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, message, args);
429*7c478bd9Sstevel@tonic-gate 	va_end(args);
430*7c478bd9Sstevel@tonic-gate 	if (do_perror)
431*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, ": %s", strerror(save_errno));
432*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
433*7c478bd9Sstevel@tonic-gate 	exit(2);
434*7c478bd9Sstevel@tonic-gate }
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate void *
437*7c478bd9Sstevel@tonic-gate safe_alloc(size_t size)
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate 	void *ptr;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	while ((ptr = malloc(size)) == NULL) {
442*7c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
443*7c478bd9Sstevel@tonic-gate 			(void) poll(NULL, 0, RETRY_DELAY);
444*7c478bd9Sstevel@tonic-gate 		else
445*7c478bd9Sstevel@tonic-gate 			fail(1, "malloc failed");
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 	return (ptr);
448*7c478bd9Sstevel@tonic-gate }
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate char *
451*7c478bd9Sstevel@tonic-gate safe_strdup(char *str)
452*7c478bd9Sstevel@tonic-gate {
453*7c478bd9Sstevel@tonic-gate 	char *ret;
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	if (str == NULL)
456*7c478bd9Sstevel@tonic-gate 		return (NULL);
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	while ((ret = strdup(str)) == NULL) {
459*7c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
460*7c478bd9Sstevel@tonic-gate 			(void) poll(NULL, 0, RETRY_DELAY);
461*7c478bd9Sstevel@tonic-gate 		else
462*7c478bd9Sstevel@tonic-gate 			fail(1, "malloc failed");
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 	return (ret);
465*7c478bd9Sstevel@tonic-gate }
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate uint64_t
468*7c478bd9Sstevel@tonic-gate kstat_delta(kstat_t *old, kstat_t *new, char *name)
469*7c478bd9Sstevel@tonic-gate {
470*7c478bd9Sstevel@tonic-gate 	kstat_named_t *knew = kstat_data_lookup(new, name);
471*7c478bd9Sstevel@tonic-gate 	if (old && old->ks_data) {
472*7c478bd9Sstevel@tonic-gate 		kstat_named_t *kold = kstat_data_lookup(old, name);
473*7c478bd9Sstevel@tonic-gate 		return (knew->value.ui64 - kold->value.ui64);
474*7c478bd9Sstevel@tonic-gate 	}
475*7c478bd9Sstevel@tonic-gate 	return (knew->value.ui64);
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate int
479*7c478bd9Sstevel@tonic-gate kstat_copy(const kstat_t *src, kstat_t *dst)
480*7c478bd9Sstevel@tonic-gate {
481*7c478bd9Sstevel@tonic-gate 	*dst = *src;
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	if (src->ks_data != NULL) {
484*7c478bd9Sstevel@tonic-gate 		if ((dst->ks_data = malloc(src->ks_data_size)) == NULL)
485*7c478bd9Sstevel@tonic-gate 			return (-1);
486*7c478bd9Sstevel@tonic-gate 		bcopy(src->ks_data, dst->ks_data, src->ks_data_size);
487*7c478bd9Sstevel@tonic-gate 	} else {
488*7c478bd9Sstevel@tonic-gate 		dst->ks_data = NULL;
489*7c478bd9Sstevel@tonic-gate 		dst->ks_data_size = 0;
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 	return (0);
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate int
495*7c478bd9Sstevel@tonic-gate kstat_add(const kstat_t *src, kstat_t *dst)
496*7c478bd9Sstevel@tonic-gate {
497*7c478bd9Sstevel@tonic-gate 	size_t i;
498*7c478bd9Sstevel@tonic-gate 	kstat_named_t *from;
499*7c478bd9Sstevel@tonic-gate 	kstat_named_t *to;
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	if (dst->ks_data == NULL)
502*7c478bd9Sstevel@tonic-gate 		return (kstat_copy(src, dst));
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	from = src->ks_data;
505*7c478bd9Sstevel@tonic-gate 	to = dst->ks_data;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < src->ks_ndata; i++) {
508*7c478bd9Sstevel@tonic-gate 		/* "addition" makes little sense for strings */
509*7c478bd9Sstevel@tonic-gate 		if (from->data_type != KSTAT_DATA_CHAR &&
510*7c478bd9Sstevel@tonic-gate 			from->data_type != KSTAT_DATA_STRING)
511*7c478bd9Sstevel@tonic-gate 			(to)->value.ui64 += (from)->value.ui64;
512*7c478bd9Sstevel@tonic-gate 		from++;
513*7c478bd9Sstevel@tonic-gate 		to++;
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	return (0);
517*7c478bd9Sstevel@tonic-gate }
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate uint64_t
520*7c478bd9Sstevel@tonic-gate cpu_ticks_delta(kstat_t *old, kstat_t *new)
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	uint64_t ticks = 0;
523*7c478bd9Sstevel@tonic-gate 	size_t i;
524*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ARRAY_SIZE(cpu_states); i++)
525*7c478bd9Sstevel@tonic-gate 		ticks += kstat_delta(old, new, cpu_states[i]);
526*7c478bd9Sstevel@tonic-gate 	return (ticks);
527*7c478bd9Sstevel@tonic-gate }
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate int
530*7c478bd9Sstevel@tonic-gate nr_active_cpus(struct snapshot *ss)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 	size_t i;
533*7c478bd9Sstevel@tonic-gate 	int count = 0;
534*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ss->s_nr_cpus; i++) {
535*7c478bd9Sstevel@tonic-gate 		if (CPU_ACTIVE(&ss->s_cpus[i]))
536*7c478bd9Sstevel@tonic-gate 			count++;
537*7c478bd9Sstevel@tonic-gate 	}
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	return (count);
540*7c478bd9Sstevel@tonic-gate }
541