xref: /titanic_53/usr/src/cmd/psrinfo/psrinfo.c (revision a3477ee4728af4a4c3c6869e248aa735d52cbefb)
1*a3477ee4SGarrett D'Amore /*
2*a3477ee4SGarrett D'Amore  * This file and its contents are supplied under the terms of the
3*a3477ee4SGarrett D'Amore  * Common Development and Distribution License ("CDDL"), version 1.0.
4*a3477ee4SGarrett D'Amore  * You may only use this file in accordance with the terms of version
5*a3477ee4SGarrett D'Amore  * 1.0 of the CDDL.
6*a3477ee4SGarrett D'Amore  *
7*a3477ee4SGarrett D'Amore  * A full copy of the text of the CDDL should have accompanied this
8*a3477ee4SGarrett D'Amore  * source.  A copy of the CDDL is also available via the Internet at
9*a3477ee4SGarrett D'Amore  * http://www.illumos.org/license/CDDL.
10*a3477ee4SGarrett D'Amore  */
11*a3477ee4SGarrett D'Amore 
12*a3477ee4SGarrett D'Amore /*
13*a3477ee4SGarrett D'Amore  * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
14*a3477ee4SGarrett D'Amore  */
15*a3477ee4SGarrett D'Amore 
16*a3477ee4SGarrett D'Amore /*
17*a3477ee4SGarrett D'Amore  * This implements psrinfo(1M), a utility to report various information
18*a3477ee4SGarrett D'Amore  * about processors, cores, and threads (virtual cpus).  This is mostly
19*a3477ee4SGarrett D'Amore  * intended for human consumption - this utility doesn't do much more than
20*a3477ee4SGarrett D'Amore  * simply process kstats for human readability.
21*a3477ee4SGarrett D'Amore  *
22*a3477ee4SGarrett D'Amore  * All the relevant kstats are in the cpu_info kstat module.
23*a3477ee4SGarrett D'Amore  */
24*a3477ee4SGarrett D'Amore 
25*a3477ee4SGarrett D'Amore #include <stdio.h>
26*a3477ee4SGarrett D'Amore #include <stdlib.h>
27*a3477ee4SGarrett D'Amore #include <unistd.h>
28*a3477ee4SGarrett D'Amore #include <string.h>
29*a3477ee4SGarrett D'Amore #include <kstat.h>
30*a3477ee4SGarrett D'Amore #include <libintl.h>
31*a3477ee4SGarrett D'Amore #include <locale.h>
32*a3477ee4SGarrett D'Amore #include <libgen.h>
33*a3477ee4SGarrett D'Amore #include <ctype.h>
34*a3477ee4SGarrett D'Amore #include <errno.h>
35*a3477ee4SGarrett D'Amore 
36*a3477ee4SGarrett D'Amore #define	_(x)	gettext(x)
37*a3477ee4SGarrett D'Amore #if XGETTEXT
38*a3477ee4SGarrett D'Amore /* These CPU states are here for benefit of xgettext */
39*a3477ee4SGarrett D'Amore _("on-line")
40*a3477ee4SGarrett D'Amore _("off-line")
41*a3477ee4SGarrett D'Amore _("faulted")
42*a3477ee4SGarrett D'Amore _("powered-off")
43*a3477ee4SGarrett D'Amore _("no-intr")
44*a3477ee4SGarrett D'Amore _("spare")
45*a3477ee4SGarrett D'Amore _("unknown")
46*a3477ee4SGarrett D'Amore #endif
47*a3477ee4SGarrett D'Amore 
48*a3477ee4SGarrett D'Amore /*
49*a3477ee4SGarrett D'Amore  * We deal with sorted linked lists, where the sort key is usually the
50*a3477ee4SGarrett D'Amore  * cpu id, core id, or chip id.  We generalize this with simple node.
51*a3477ee4SGarrett D'Amore  */
52*a3477ee4SGarrett D'Amore struct link {
53*a3477ee4SGarrett D'Amore 	long		l_id;
54*a3477ee4SGarrett D'Amore 	struct link	*l_next;
55*a3477ee4SGarrett D'Amore 	void		*l_ptr;
56*a3477ee4SGarrett D'Amore };
57*a3477ee4SGarrett D'Amore 
58*a3477ee4SGarrett D'Amore /*
59*a3477ee4SGarrett D'Amore  * A physical chip.  A chip can contain multiple cores and virtual cpus.
60*a3477ee4SGarrett D'Amore  */
61*a3477ee4SGarrett D'Amore struct pchip {
62*a3477ee4SGarrett D'Amore 	struct link	p_link;
63*a3477ee4SGarrett D'Amore 	int		p_ncore;
64*a3477ee4SGarrett D'Amore 	int		p_nvcpu;
65*a3477ee4SGarrett D'Amore 	struct link	*p_cores;
66*a3477ee4SGarrett D'Amore 	struct link	*p_vcpus;
67*a3477ee4SGarrett D'Amore 	int		p_doit;
68*a3477ee4SGarrett D'Amore };
69*a3477ee4SGarrett D'Amore 
70*a3477ee4SGarrett D'Amore struct core {
71*a3477ee4SGarrett D'Amore 	struct link	c_link;
72*a3477ee4SGarrett D'Amore 	struct link	c_link_pchip;
73*a3477ee4SGarrett D'Amore 
74*a3477ee4SGarrett D'Amore 	int		c_nvcpu;
75*a3477ee4SGarrett D'Amore 	int		c_doit;
76*a3477ee4SGarrett D'Amore 
77*a3477ee4SGarrett D'Amore 	struct pchip	*c_pchip;
78*a3477ee4SGarrett D'Amore 	struct link	*c_vcpus;
79*a3477ee4SGarrett D'Amore };
80*a3477ee4SGarrett D'Amore 
81*a3477ee4SGarrett D'Amore struct vcpu {
82*a3477ee4SGarrett D'Amore 	struct link	v_link;
83*a3477ee4SGarrett D'Amore 
84*a3477ee4SGarrett D'Amore 	struct link	v_link_core;
85*a3477ee4SGarrett D'Amore 	struct link	v_link_pchip;
86*a3477ee4SGarrett D'Amore 
87*a3477ee4SGarrett D'Amore 	int		v_doit;
88*a3477ee4SGarrett D'Amore 
89*a3477ee4SGarrett D'Amore 	struct pchip	*v_pchip;
90*a3477ee4SGarrett D'Amore 	struct core	*v_core;
91*a3477ee4SGarrett D'Amore 
92*a3477ee4SGarrett D'Amore 	char		*v_state;
93*a3477ee4SGarrett D'Amore 	long		v_state_begin;
94*a3477ee4SGarrett D'Amore 	char		*v_cpu_type;
95*a3477ee4SGarrett D'Amore 	char		*v_fpu_type;
96*a3477ee4SGarrett D'Amore 	long		v_clock_mhz;
97*a3477ee4SGarrett D'Amore 	long		v_pchip_id;	/* 1 per socket */
98*a3477ee4SGarrett D'Amore 	char		*v_impl;
99*a3477ee4SGarrett D'Amore 	char		*v_brand;
100*a3477ee4SGarrett D'Amore 	long		v_core_id;	/* n per chip_id */
101*a3477ee4SGarrett D'Amore };
102*a3477ee4SGarrett D'Amore 
103*a3477ee4SGarrett D'Amore static struct link *pchips = NULL;
104*a3477ee4SGarrett D'Amore static struct link *cores = NULL;
105*a3477ee4SGarrett D'Amore static struct link *vcpus = NULL;
106*a3477ee4SGarrett D'Amore 
107*a3477ee4SGarrett D'Amore static const char *cmdname;
108*a3477ee4SGarrett D'Amore 
109*a3477ee4SGarrett D'Amore static void
110*a3477ee4SGarrett D'Amore usage(char *msg)
111*a3477ee4SGarrett D'Amore {
112*a3477ee4SGarrett D'Amore 	if (msg != NULL)
113*a3477ee4SGarrett D'Amore 		(void) fprintf(stderr, "%s: %s\n", cmdname, msg);
114*a3477ee4SGarrett D'Amore 	(void) fprintf(stderr, _("usage: \n" \
115*a3477ee4SGarrett D'Amore 	    "\t%s [-v] [-p] [processor_id ...]\n" \
116*a3477ee4SGarrett D'Amore 	    "\t%s -s [-p] processor_id\n"), cmdname, cmdname);
117*a3477ee4SGarrett D'Amore 	exit(2);
118*a3477ee4SGarrett D'Amore }
119*a3477ee4SGarrett D'Amore 
120*a3477ee4SGarrett D'Amore /* like perror, but includes the command name */
121*a3477ee4SGarrett D'Amore static void
122*a3477ee4SGarrett D'Amore die(const char *msg)
123*a3477ee4SGarrett D'Amore {
124*a3477ee4SGarrett D'Amore 	(void) fprintf(stderr, "%s: %s: %s\n", cmdname, msg, strerror(errno));
125*a3477ee4SGarrett D'Amore 	exit(2);
126*a3477ee4SGarrett D'Amore }
127*a3477ee4SGarrett D'Amore 
128*a3477ee4SGarrett D'Amore static char *
129*a3477ee4SGarrett D'Amore mystrdup(const char *src)
130*a3477ee4SGarrett D'Amore {
131*a3477ee4SGarrett D'Amore 	char *dst;
132*a3477ee4SGarrett D'Amore 
133*a3477ee4SGarrett D'Amore 	if ((dst = strdup(src)) == NULL)
134*a3477ee4SGarrett D'Amore 		die(_("strdup() failed"));
135*a3477ee4SGarrett D'Amore 	return (dst);
136*a3477ee4SGarrett D'Amore }
137*a3477ee4SGarrett D'Amore 
138*a3477ee4SGarrett D'Amore static void *
139*a3477ee4SGarrett D'Amore zalloc(size_t size)
140*a3477ee4SGarrett D'Amore {
141*a3477ee4SGarrett D'Amore 	void *ptr;
142*a3477ee4SGarrett D'Amore 
143*a3477ee4SGarrett D'Amore 	if ((ptr = calloc(1, size)) == NULL)
144*a3477ee4SGarrett D'Amore 		die(_("calloc() failed"));
145*a3477ee4SGarrett D'Amore 	return (ptr);
146*a3477ee4SGarrett D'Amore }
147*a3477ee4SGarrett D'Amore 
148*a3477ee4SGarrett D'Amore /*
149*a3477ee4SGarrett D'Amore  * Insert a new node on a list, at the insertion point given.
150*a3477ee4SGarrett D'Amore  */
151*a3477ee4SGarrett D'Amore static void
152*a3477ee4SGarrett D'Amore ins_link(struct link **ins, struct link *item)
153*a3477ee4SGarrett D'Amore {
154*a3477ee4SGarrett D'Amore 	item->l_next = *ins;
155*a3477ee4SGarrett D'Amore 	*ins = item;
156*a3477ee4SGarrett D'Amore }
157*a3477ee4SGarrett D'Amore 
158*a3477ee4SGarrett D'Amore /*
159*a3477ee4SGarrett D'Amore  * Find an id on a sorted list.  If the requested id is not found,
160*a3477ee4SGarrett D'Amore  * then the insertpt will be set (if not null) to the location where
161*a3477ee4SGarrett D'Amore  * a new node should be inserted with ins_link (see above).
162*a3477ee4SGarrett D'Amore  */
163*a3477ee4SGarrett D'Amore static void *
164*a3477ee4SGarrett D'Amore find_link(void *list, int id, struct link ***insertpt)
165*a3477ee4SGarrett D'Amore {
166*a3477ee4SGarrett D'Amore 	struct link **ins = list;
167*a3477ee4SGarrett D'Amore 	struct link *l;
168*a3477ee4SGarrett D'Amore 
169*a3477ee4SGarrett D'Amore 	while ((l = *ins) != NULL) {
170*a3477ee4SGarrett D'Amore 		if (l->l_id == id)
171*a3477ee4SGarrett D'Amore 			return (l->l_ptr);
172*a3477ee4SGarrett D'Amore 		if (l->l_id > id)
173*a3477ee4SGarrett D'Amore 			break;
174*a3477ee4SGarrett D'Amore 		ins = &l->l_next;
175*a3477ee4SGarrett D'Amore 	}
176*a3477ee4SGarrett D'Amore 	if (insertpt != NULL)
177*a3477ee4SGarrett D'Amore 		*insertpt = ins;
178*a3477ee4SGarrett D'Amore 	return (NULL);
179*a3477ee4SGarrett D'Amore }
180*a3477ee4SGarrett D'Amore 
181*a3477ee4SGarrett D'Amore /*
182*a3477ee4SGarrett D'Amore  * Print the linked list of ids in parens, taking care to collapse
183*a3477ee4SGarrett D'Amore  * ranges, so instead of (0 1 2 3) it should print (0-3).
184*a3477ee4SGarrett D'Amore  */
185*a3477ee4SGarrett D'Amore static void
186*a3477ee4SGarrett D'Amore print_links(struct link *l)
187*a3477ee4SGarrett D'Amore {
188*a3477ee4SGarrett D'Amore 	int	start = -1;
189*a3477ee4SGarrett D'Amore 	int	end = 0;
190*a3477ee4SGarrett D'Amore 
191*a3477ee4SGarrett D'Amore 	(void) printf(" (");
192*a3477ee4SGarrett D'Amore 	while (l != NULL) {
193*a3477ee4SGarrett D'Amore 		if (start < 0) {
194*a3477ee4SGarrett D'Amore 			start = l->l_id;
195*a3477ee4SGarrett D'Amore 		}
196*a3477ee4SGarrett D'Amore 		end = l->l_id;
197*a3477ee4SGarrett D'Amore 		if ((l->l_next == NULL) ||
198*a3477ee4SGarrett D'Amore 		    (l->l_next->l_id > (l->l_id + 1))) {
199*a3477ee4SGarrett D'Amore 			/* end of the contiguous group */
200*a3477ee4SGarrett D'Amore 			if (start == end) {
201*a3477ee4SGarrett D'Amore 				(void) printf("%d", start);
202*a3477ee4SGarrett D'Amore 			} else {
203*a3477ee4SGarrett D'Amore 				(void) printf("%d-%d", start, end);
204*a3477ee4SGarrett D'Amore 			}
205*a3477ee4SGarrett D'Amore 			if (l->l_next)
206*a3477ee4SGarrett D'Amore 				(void) printf(" ");
207*a3477ee4SGarrett D'Amore 			start = -1;
208*a3477ee4SGarrett D'Amore 		}
209*a3477ee4SGarrett D'Amore 		l = l->l_next;
210*a3477ee4SGarrett D'Amore 	}
211*a3477ee4SGarrett D'Amore 	(void) printf(")");
212*a3477ee4SGarrett D'Amore }
213*a3477ee4SGarrett D'Amore 
214*a3477ee4SGarrett D'Amore static const char *
215*a3477ee4SGarrett D'Amore timestr(long t)
216*a3477ee4SGarrett D'Amore {
217*a3477ee4SGarrett D'Amore 	static char buffer[256];
218*a3477ee4SGarrett D'Amore 	(void) strftime(buffer, sizeof (buffer), _("%m/%d/%Y %T"),
219*a3477ee4SGarrett D'Amore 	    localtime(&t));
220*a3477ee4SGarrett D'Amore 	return (buffer);
221*a3477ee4SGarrett D'Amore }
222*a3477ee4SGarrett D'Amore 
223*a3477ee4SGarrett D'Amore static void
224*a3477ee4SGarrett D'Amore print_vp(int nspec)
225*a3477ee4SGarrett D'Amore {
226*a3477ee4SGarrett D'Amore 	struct pchip *chip;
227*a3477ee4SGarrett D'Amore 	struct core *core;
228*a3477ee4SGarrett D'Amore 	struct vcpu *vcpu;
229*a3477ee4SGarrett D'Amore 	struct link *l1, *l2;
230*a3477ee4SGarrett D'Amore 	int len;
231*a3477ee4SGarrett D'Amore 	for (l1 = pchips; l1; l1 = l1->l_next) {
232*a3477ee4SGarrett D'Amore 
233*a3477ee4SGarrett D'Amore 		chip = l1->l_ptr;
234*a3477ee4SGarrett D'Amore 
235*a3477ee4SGarrett D'Amore 		if ((nspec != 0) && (chip->p_doit == 0))
236*a3477ee4SGarrett D'Amore 			continue;
237*a3477ee4SGarrett D'Amore 
238*a3477ee4SGarrett D'Amore 		vcpu = chip->p_vcpus->l_ptr;
239*a3477ee4SGarrett D'Amore 
240*a3477ee4SGarrett D'Amore 		/*
241*a3477ee4SGarrett D'Amore 		 * Note that some of the way these strings are broken up are
242*a3477ee4SGarrett D'Amore 		 * to accommodate the legacy translations so that we won't
243*a3477ee4SGarrett D'Amore 		 * have to retranslate for this utility.
244*a3477ee4SGarrett D'Amore 		 */
245*a3477ee4SGarrett D'Amore 		if ((chip->p_ncore == 1) || (chip->p_ncore == chip->p_nvcpu)) {
246*a3477ee4SGarrett D'Amore 			(void) printf(_("%s has %d virtual %s"),
247*a3477ee4SGarrett D'Amore 			    _("The physical processor"),
248*a3477ee4SGarrett D'Amore 			    chip->p_nvcpu,
249*a3477ee4SGarrett D'Amore 			    chip->p_nvcpu > 1 ?
250*a3477ee4SGarrett D'Amore 			    _("processors") :
251*a3477ee4SGarrett D'Amore 			    _("processor"));
252*a3477ee4SGarrett D'Amore 		} else {
253*a3477ee4SGarrett D'Amore 			(void) printf(_("%s has %d %s and %d virtual %s"),
254*a3477ee4SGarrett D'Amore 			    _("The physical processor"),
255*a3477ee4SGarrett D'Amore 			    chip->p_ncore, _("cores"),
256*a3477ee4SGarrett D'Amore 			    chip->p_nvcpu,
257*a3477ee4SGarrett D'Amore 			    chip->p_nvcpu > 1 ?
258*a3477ee4SGarrett D'Amore 			    _("processors") : _("processor"));
259*a3477ee4SGarrett D'Amore 		}
260*a3477ee4SGarrett D'Amore 
261*a3477ee4SGarrett D'Amore 		print_links(chip->p_vcpus);
262*a3477ee4SGarrett D'Amore 		(void) putchar('\n');
263*a3477ee4SGarrett D'Amore 
264*a3477ee4SGarrett D'Amore 		if ((chip->p_ncore == 1) || (chip->p_ncore == chip->p_nvcpu)) {
265*a3477ee4SGarrett D'Amore 			if (strlen(vcpu->v_impl)) {
266*a3477ee4SGarrett D'Amore 				(void) printf("  %s\n", vcpu->v_impl);
267*a3477ee4SGarrett D'Amore 			}
268*a3477ee4SGarrett D'Amore 			if (((len = strlen(vcpu->v_brand)) != 0) &&
269*a3477ee4SGarrett D'Amore 			    (strncmp(vcpu->v_brand, vcpu->v_impl, len) != 0))
270*a3477ee4SGarrett D'Amore 				(void) printf("\t%s", vcpu->v_brand);
271*a3477ee4SGarrett D'Amore 			(void) putchar('\n');
272*a3477ee4SGarrett D'Amore 		} else {
273*a3477ee4SGarrett D'Amore 			for (l2 = chip->p_cores; l2; l2 = l2->l_next) {
274*a3477ee4SGarrett D'Amore 				core = l2->l_ptr;
275*a3477ee4SGarrett D'Amore 				(void) printf(_("  %s has %d virtual %s"),
276*a3477ee4SGarrett D'Amore 				    _("The core"),
277*a3477ee4SGarrett D'Amore 				    core->c_nvcpu,
278*a3477ee4SGarrett D'Amore 				    chip->p_nvcpu > 1 ?
279*a3477ee4SGarrett D'Amore 				    _("processors") : _("processor"));
280*a3477ee4SGarrett D'Amore 				print_links(core->c_vcpus);
281*a3477ee4SGarrett D'Amore 				(void) putchar('\n');
282*a3477ee4SGarrett D'Amore 			}
283*a3477ee4SGarrett D'Amore 			if (strlen(vcpu->v_impl)) {
284*a3477ee4SGarrett D'Amore 				(void) printf("    %s\n", vcpu->v_impl);
285*a3477ee4SGarrett D'Amore 			}
286*a3477ee4SGarrett D'Amore 			if (((len = strlen(vcpu->v_brand)) != 0) &&
287*a3477ee4SGarrett D'Amore 			    (strncmp(vcpu->v_brand, vcpu->v_impl, len) != 0))
288*a3477ee4SGarrett D'Amore 				(void) printf("      %s\n", vcpu->v_brand);
289*a3477ee4SGarrett D'Amore 		}
290*a3477ee4SGarrett D'Amore 	}
291*a3477ee4SGarrett D'Amore }
292*a3477ee4SGarrett D'Amore 
293*a3477ee4SGarrett D'Amore static void
294*a3477ee4SGarrett D'Amore print_ps(void)
295*a3477ee4SGarrett D'Amore {
296*a3477ee4SGarrett D'Amore 	int online = 1;
297*a3477ee4SGarrett D'Amore 	struct pchip *p;
298*a3477ee4SGarrett D'Amore 	struct vcpu *v;
299*a3477ee4SGarrett D'Amore 	struct link *l;
300*a3477ee4SGarrett D'Amore 
301*a3477ee4SGarrett D'Amore 	/*
302*a3477ee4SGarrett D'Amore 	 * Report "1" if all cpus colocated on the same chip are online.
303*a3477ee4SGarrett D'Amore 	 */
304*a3477ee4SGarrett D'Amore 	for (l = pchips; l != NULL; l = l->l_next) {
305*a3477ee4SGarrett D'Amore 		p = l->l_ptr;
306*a3477ee4SGarrett D'Amore 		if (p->p_doit)
307*a3477ee4SGarrett D'Amore 			break;
308*a3477ee4SGarrett D'Amore 	}
309*a3477ee4SGarrett D'Amore 	if (p == NULL)
310*a3477ee4SGarrett D'Amore 		return;	/* should never happen! */
311*a3477ee4SGarrett D'Amore 	for (l = p->p_vcpus; l != NULL; l = l->l_next) {
312*a3477ee4SGarrett D'Amore 		v = l->l_ptr;
313*a3477ee4SGarrett D'Amore 		if (strcmp(v->v_state, "on-line") != 0) {
314*a3477ee4SGarrett D'Amore 			online = 0;
315*a3477ee4SGarrett D'Amore 			break;
316*a3477ee4SGarrett D'Amore 		}
317*a3477ee4SGarrett D'Amore 	}
318*a3477ee4SGarrett D'Amore 
319*a3477ee4SGarrett D'Amore 	(void) printf("%d\n", online);
320*a3477ee4SGarrett D'Amore }
321*a3477ee4SGarrett D'Amore 
322*a3477ee4SGarrett D'Amore static void
323*a3477ee4SGarrett D'Amore print_s(void)
324*a3477ee4SGarrett D'Amore {
325*a3477ee4SGarrett D'Amore 	struct link *l;
326*a3477ee4SGarrett D'Amore 
327*a3477ee4SGarrett D'Amore 	/*
328*a3477ee4SGarrett D'Amore 	 * Find the processor (there will be only one) that we selected,
329*a3477ee4SGarrett D'Amore 	 * and report whether or not it is online.
330*a3477ee4SGarrett D'Amore 	 */
331*a3477ee4SGarrett D'Amore 	for (l = vcpus; l != NULL; l = l->l_next) {
332*a3477ee4SGarrett D'Amore 		struct vcpu *v = l->l_ptr;
333*a3477ee4SGarrett D'Amore 		if (v->v_doit) {
334*a3477ee4SGarrett D'Amore 			(void) printf("%d\n",
335*a3477ee4SGarrett D'Amore 			    strcmp(v->v_state, "on-line") == 0 ? 1 : 0);
336*a3477ee4SGarrett D'Amore 			return;
337*a3477ee4SGarrett D'Amore 		}
338*a3477ee4SGarrett D'Amore 	}
339*a3477ee4SGarrett D'Amore }
340*a3477ee4SGarrett D'Amore 
341*a3477ee4SGarrett D'Amore static void
342*a3477ee4SGarrett D'Amore print_p(int nspec)
343*a3477ee4SGarrett D'Amore {
344*a3477ee4SGarrett D'Amore 	struct		link *l1, *l2;
345*a3477ee4SGarrett D'Amore 	int		online = 0;
346*a3477ee4SGarrett D'Amore 
347*a3477ee4SGarrett D'Amore 	/*
348*a3477ee4SGarrett D'Amore 	 * Print the number of physical packages with at least one processor
349*a3477ee4SGarrett D'Amore 	 * online.
350*a3477ee4SGarrett D'Amore 	 */
351*a3477ee4SGarrett D'Amore 	for (l1 = pchips; l1 != NULL; l1 = l1->l_next) {
352*a3477ee4SGarrett D'Amore 		struct pchip *p = l1->l_ptr;
353*a3477ee4SGarrett D'Amore 		if ((nspec == 0) || (p->p_doit)) {
354*a3477ee4SGarrett D'Amore 
355*a3477ee4SGarrett D'Amore 			for (l2 = p->p_vcpus; l2 != NULL; l2 = l2->l_next) {
356*a3477ee4SGarrett D'Amore 				struct vcpu *v = l2->l_ptr;
357*a3477ee4SGarrett D'Amore 				if (strcmp(v->v_state, "on-line") == 0) {
358*a3477ee4SGarrett D'Amore 					online++;
359*a3477ee4SGarrett D'Amore 					break;
360*a3477ee4SGarrett D'Amore 				}
361*a3477ee4SGarrett D'Amore 			}
362*a3477ee4SGarrett D'Amore 		}
363*a3477ee4SGarrett D'Amore 	}
364*a3477ee4SGarrett D'Amore 	(void) printf("%d\n", online);
365*a3477ee4SGarrett D'Amore }
366*a3477ee4SGarrett D'Amore 
367*a3477ee4SGarrett D'Amore static void
368*a3477ee4SGarrett D'Amore print_v(int nspec)
369*a3477ee4SGarrett D'Amore {
370*a3477ee4SGarrett D'Amore 	struct link	*l;
371*a3477ee4SGarrett D'Amore 
372*a3477ee4SGarrett D'Amore 	for (l = vcpus; l != NULL; l = l->l_next) {
373*a3477ee4SGarrett D'Amore 		struct vcpu *v = l->l_ptr;
374*a3477ee4SGarrett D'Amore 
375*a3477ee4SGarrett D'Amore 		if ((nspec != 0) && (!v->v_doit))
376*a3477ee4SGarrett D'Amore 			continue;
377*a3477ee4SGarrett D'Amore 		(void) printf(_("Status of virtual processor %d as of: "),
378*a3477ee4SGarrett D'Amore 		    l->l_id);
379*a3477ee4SGarrett D'Amore 		(void) printf("%s\n", timestr(time(NULL)));
380*a3477ee4SGarrett D'Amore 		(void) printf(_("  %s since %s.\n"),
381*a3477ee4SGarrett D'Amore 		    _(v->v_state), timestr(v->v_state_begin));
382*a3477ee4SGarrett D'Amore 		if (v->v_clock_mhz) {
383*a3477ee4SGarrett D'Amore 			(void) printf(
384*a3477ee4SGarrett D'Amore 			    _("  The %s processor operates at %llu MHz,\n"),
385*a3477ee4SGarrett D'Amore 			    v->v_cpu_type, (unsigned long long)v->v_clock_mhz);
386*a3477ee4SGarrett D'Amore 		} else {
387*a3477ee4SGarrett D'Amore 			(void) printf(
388*a3477ee4SGarrett D'Amore 			    _("  The %s processor operates at " \
389*a3477ee4SGarrett D'Amore 			    "an unknown frequency,\n"), v->v_cpu_type);
390*a3477ee4SGarrett D'Amore 		}
391*a3477ee4SGarrett D'Amore 		switch (*v->v_fpu_type) {
392*a3477ee4SGarrett D'Amore 		case '\0':
393*a3477ee4SGarrett D'Amore 			(void) printf(
394*a3477ee4SGarrett D'Amore 			    _("\tand has no floating point processor.\n"));
395*a3477ee4SGarrett D'Amore 			break;
396*a3477ee4SGarrett D'Amore 		case 'a': case 'A':
397*a3477ee4SGarrett D'Amore 		case 'e': case 'E':
398*a3477ee4SGarrett D'Amore 		case 'i': case 'I':
399*a3477ee4SGarrett D'Amore 		case 'o': case 'O':
400*a3477ee4SGarrett D'Amore 		case 'u': case 'U':
401*a3477ee4SGarrett D'Amore 		case 'y': case 'Y':
402*a3477ee4SGarrett D'Amore 			(void) printf(
403*a3477ee4SGarrett D'Amore 			    _("\tand has an %s floating point processor.\n"),
404*a3477ee4SGarrett D'Amore 			    v->v_fpu_type);
405*a3477ee4SGarrett D'Amore 			break;
406*a3477ee4SGarrett D'Amore 		default:
407*a3477ee4SGarrett D'Amore 			(void) printf(
408*a3477ee4SGarrett D'Amore 			    _("\tand has a %s floating point processor.\n"),
409*a3477ee4SGarrett D'Amore 			    v->v_fpu_type);
410*a3477ee4SGarrett D'Amore 			break;
411*a3477ee4SGarrett D'Amore 		}
412*a3477ee4SGarrett D'Amore 	}
413*a3477ee4SGarrett D'Amore }
414*a3477ee4SGarrett D'Amore 
415*a3477ee4SGarrett D'Amore static void
416*a3477ee4SGarrett D'Amore print_normal(int nspec)
417*a3477ee4SGarrett D'Amore {
418*a3477ee4SGarrett D'Amore 	struct link	*l;
419*a3477ee4SGarrett D'Amore 	struct vcpu	*v;
420*a3477ee4SGarrett D'Amore 
421*a3477ee4SGarrett D'Amore 	for (l = vcpus; l != NULL; l = l->l_next) {
422*a3477ee4SGarrett D'Amore 		v = l->l_ptr;
423*a3477ee4SGarrett D'Amore 		if ((nspec == 0) || (v->v_doit)) {
424*a3477ee4SGarrett D'Amore 			(void) printf(_("%d\t%-8s  since %s\n"),
425*a3477ee4SGarrett D'Amore 			    l->l_id, _(v->v_state), timestr(v->v_state_begin));
426*a3477ee4SGarrett D'Amore 		}
427*a3477ee4SGarrett D'Amore 	}
428*a3477ee4SGarrett D'Amore }
429*a3477ee4SGarrett D'Amore 
430*a3477ee4SGarrett D'Amore int
431*a3477ee4SGarrett D'Amore main(int argc, char **argv)
432*a3477ee4SGarrett D'Amore {
433*a3477ee4SGarrett D'Amore 	kstat_ctl_t	*kc;
434*a3477ee4SGarrett D'Amore 	kstat_t		*ksp;
435*a3477ee4SGarrett D'Amore 	kstat_named_t	*knp;
436*a3477ee4SGarrett D'Amore 	struct vcpu	*vc;
437*a3477ee4SGarrett D'Amore 	struct core	*core;
438*a3477ee4SGarrett D'Amore 	struct pchip	*chip;
439*a3477ee4SGarrett D'Amore 	struct link	**ins;
440*a3477ee4SGarrett D'Amore 	char		*s;
441*a3477ee4SGarrett D'Amore 	int		nspec;
442*a3477ee4SGarrett D'Amore 	int		optc;
443*a3477ee4SGarrett D'Amore 	int		opt_s = 0;
444*a3477ee4SGarrett D'Amore 	int		opt_p = 0;
445*a3477ee4SGarrett D'Amore 	int		opt_v = 0;
446*a3477ee4SGarrett D'Amore 	int		ex = 0;
447*a3477ee4SGarrett D'Amore 
448*a3477ee4SGarrett D'Amore 	cmdname = basename(argv[0]);
449*a3477ee4SGarrett D'Amore 
450*a3477ee4SGarrett D'Amore 
451*a3477ee4SGarrett D'Amore 	(void) setlocale(LC_ALL, "");
452*a3477ee4SGarrett D'Amore #if !defined(TEXT_DOMAIN)
453*a3477ee4SGarrett D'Amore #define	TEXT_DOMAIN	"SYS_TEST"
454*a3477ee4SGarrett D'Amore #endif
455*a3477ee4SGarrett D'Amore 	(void) textdomain(TEXT_DOMAIN);
456*a3477ee4SGarrett D'Amore 
457*a3477ee4SGarrett D'Amore 	/* collect the kstats */
458*a3477ee4SGarrett D'Amore 	if ((kc = kstat_open()) == NULL)
459*a3477ee4SGarrett D'Amore 		die(_("kstat_open() failed"));
460*a3477ee4SGarrett D'Amore 
461*a3477ee4SGarrett D'Amore 	if ((ksp = kstat_lookup(kc, "cpu_info", -1, NULL)) == NULL)
462*a3477ee4SGarrett D'Amore 		die(_("kstat_lookup() failed"));
463*a3477ee4SGarrett D'Amore 
464*a3477ee4SGarrett D'Amore 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
465*a3477ee4SGarrett D'Amore 
466*a3477ee4SGarrett D'Amore 		if (strcmp(ksp->ks_module, "cpu_info") != 0)
467*a3477ee4SGarrett D'Amore 			continue;
468*a3477ee4SGarrett D'Amore 		if (kstat_read(kc, ksp, NULL) == NULL)
469*a3477ee4SGarrett D'Amore 			die(_("kstat_read() failed"));
470*a3477ee4SGarrett D'Amore 
471*a3477ee4SGarrett D'Amore 		vc = find_link(&vcpus, ksp->ks_instance, &ins);
472*a3477ee4SGarrett D'Amore 		if (vc == NULL) {
473*a3477ee4SGarrett D'Amore 			vc = zalloc(sizeof (struct vcpu));
474*a3477ee4SGarrett D'Amore 			vc->v_link.l_id = ksp->ks_instance;
475*a3477ee4SGarrett D'Amore 			vc->v_link_core.l_id = ksp->ks_instance;
476*a3477ee4SGarrett D'Amore 			vc->v_link_pchip.l_id = ksp->ks_instance;
477*a3477ee4SGarrett D'Amore 			vc->v_link.l_ptr = vc;
478*a3477ee4SGarrett D'Amore 			vc->v_link_core.l_ptr = vc;
479*a3477ee4SGarrett D'Amore 			vc->v_link_pchip.l_ptr = vc;
480*a3477ee4SGarrett D'Amore 			ins_link(ins, &vc->v_link);
481*a3477ee4SGarrett D'Amore 		}
482*a3477ee4SGarrett D'Amore 
483*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "state")) != NULL) {
484*a3477ee4SGarrett D'Amore 			vc->v_state = mystrdup(knp->value.c);
485*a3477ee4SGarrett D'Amore 		} else {
486*a3477ee4SGarrett D'Amore 			vc->v_state = "unknown";
487*a3477ee4SGarrett D'Amore 		}
488*a3477ee4SGarrett D'Amore 
489*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "cpu_type")) != NULL) {
490*a3477ee4SGarrett D'Amore 			vc->v_cpu_type = mystrdup(knp->value.c);
491*a3477ee4SGarrett D'Amore 		}
492*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "fpu_type")) != NULL) {
493*a3477ee4SGarrett D'Amore 			vc->v_fpu_type = mystrdup(knp->value.c);
494*a3477ee4SGarrett D'Amore 		}
495*a3477ee4SGarrett D'Amore 
496*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "state_begin")) != NULL) {
497*a3477ee4SGarrett D'Amore 			vc->v_state_begin = knp->value.l;
498*a3477ee4SGarrett D'Amore 		}
499*a3477ee4SGarrett D'Amore 
500*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "clock_MHz")) != NULL) {
501*a3477ee4SGarrett D'Amore 			vc->v_clock_mhz = knp->value.l;
502*a3477ee4SGarrett D'Amore 		}
503*a3477ee4SGarrett D'Amore 
504*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "brand")) == NULL) {
505*a3477ee4SGarrett D'Amore 			vc->v_brand = _("(unknown)");
506*a3477ee4SGarrett D'Amore 		} else {
507*a3477ee4SGarrett D'Amore 			vc->v_brand = mystrdup(knp->value.str.addr.ptr);
508*a3477ee4SGarrett D'Amore 		}
509*a3477ee4SGarrett D'Amore 
510*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "implementation")) == NULL) {
511*a3477ee4SGarrett D'Amore 			vc->v_impl = _("(unknown)");
512*a3477ee4SGarrett D'Amore 		} else {
513*a3477ee4SGarrett D'Amore 			vc->v_impl = mystrdup(knp->value.str.addr.ptr);
514*a3477ee4SGarrett D'Amore 		}
515*a3477ee4SGarrett D'Amore 		/*
516*a3477ee4SGarrett D'Amore 		 * Legacy code removed the chipid and cpuid fields... we
517*a3477ee4SGarrett D'Amore 		 * do the same for compatibility.  Note that the original
518*a3477ee4SGarrett D'Amore 		 * pattern is a bit strange, and we have to emulate this because
519*a3477ee4SGarrett D'Amore 		 * on SPARC we *do* emit these.  The original pattern we are
520*a3477ee4SGarrett D'Amore 		 * emulating is: $impl =~ s/(cpuid|chipid)\s*\w+\s+//;
521*a3477ee4SGarrett D'Amore 		 */
522*a3477ee4SGarrett D'Amore 		if ((s = strstr(vc->v_impl, "chipid")) != NULL) {
523*a3477ee4SGarrett D'Amore 			char *x = s + strlen("chipid");
524*a3477ee4SGarrett D'Amore 			while (isspace(*x))
525*a3477ee4SGarrett D'Amore 				x++;
526*a3477ee4SGarrett D'Amore 			if ((!isalnum(*x)) && (*x != '_'))
527*a3477ee4SGarrett D'Amore 				goto nochipid;
528*a3477ee4SGarrett D'Amore 			while (isalnum(*x) || (*x == '_'))
529*a3477ee4SGarrett D'Amore 				x++;
530*a3477ee4SGarrett D'Amore 			if (!isspace(*x))
531*a3477ee4SGarrett D'Amore 				goto nochipid;
532*a3477ee4SGarrett D'Amore 			while (isspace(*x))
533*a3477ee4SGarrett D'Amore 				x++;
534*a3477ee4SGarrett D'Amore 			(void) strcpy(s, x);
535*a3477ee4SGarrett D'Amore 		}
536*a3477ee4SGarrett D'Amore nochipid:
537*a3477ee4SGarrett D'Amore 		if ((s = strstr(vc->v_impl, "cpuid")) != NULL) {
538*a3477ee4SGarrett D'Amore 			char *x = s + strlen("cpuid");
539*a3477ee4SGarrett D'Amore 			while (isspace(*x))
540*a3477ee4SGarrett D'Amore 				x++;
541*a3477ee4SGarrett D'Amore 			if ((!isalnum(*x)) && (*x != '_'))
542*a3477ee4SGarrett D'Amore 				goto nocpuid;
543*a3477ee4SGarrett D'Amore 			while (isalnum(*x) || (*x == '_'))
544*a3477ee4SGarrett D'Amore 				x++;
545*a3477ee4SGarrett D'Amore 			if (!isspace(*x))
546*a3477ee4SGarrett D'Amore 				goto nocpuid;
547*a3477ee4SGarrett D'Amore 			while (isspace(*x))
548*a3477ee4SGarrett D'Amore 				x++;
549*a3477ee4SGarrett D'Amore 			(void) strcpy(s, x);
550*a3477ee4SGarrett D'Amore 		}
551*a3477ee4SGarrett D'Amore nocpuid:
552*a3477ee4SGarrett D'Amore 
553*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "chip_id")) != NULL)
554*a3477ee4SGarrett D'Amore 			vc->v_pchip_id = knp->value.l;
555*a3477ee4SGarrett D'Amore 		chip = find_link(&pchips, vc->v_pchip_id, &ins);
556*a3477ee4SGarrett D'Amore 		if (chip == NULL) {
557*a3477ee4SGarrett D'Amore 			chip = zalloc(sizeof (struct pchip));
558*a3477ee4SGarrett D'Amore 			chip->p_link.l_id = vc->v_pchip_id;
559*a3477ee4SGarrett D'Amore 			chip->p_link.l_ptr = chip;
560*a3477ee4SGarrett D'Amore 			ins_link(ins, &chip->p_link);
561*a3477ee4SGarrett D'Amore 		}
562*a3477ee4SGarrett D'Amore 		vc->v_pchip = chip;
563*a3477ee4SGarrett D'Amore 
564*a3477ee4SGarrett D'Amore 		if ((knp = kstat_data_lookup(ksp, "core_id")) != NULL)
565*a3477ee4SGarrett D'Amore 			vc->v_core_id = knp->value.l;
566*a3477ee4SGarrett D'Amore 		core = find_link(&cores, vc->v_core_id, &ins);
567*a3477ee4SGarrett D'Amore 		if (core == NULL) {
568*a3477ee4SGarrett D'Amore 			core = zalloc(sizeof (struct core));
569*a3477ee4SGarrett D'Amore 			core->c_link.l_id = vc->v_core_id;
570*a3477ee4SGarrett D'Amore 			core->c_link.l_ptr = core;
571*a3477ee4SGarrett D'Amore 			core->c_link_pchip.l_id = vc->v_core_id;
572*a3477ee4SGarrett D'Amore 			core->c_link_pchip.l_ptr = core;
573*a3477ee4SGarrett D'Amore 			core->c_pchip = chip;
574*a3477ee4SGarrett D'Amore 			ins_link(ins, &core->c_link);
575*a3477ee4SGarrett D'Amore 			chip->p_ncore++;
576*a3477ee4SGarrett D'Amore 			(void) find_link(&chip->p_cores, core->c_link.l_id,
577*a3477ee4SGarrett D'Amore 			    &ins);
578*a3477ee4SGarrett D'Amore 			ins_link(ins, &core->c_link_pchip);
579*a3477ee4SGarrett D'Amore 		}
580*a3477ee4SGarrett D'Amore 		vc->v_core = core;
581*a3477ee4SGarrett D'Amore 
582*a3477ee4SGarrett D'Amore 
583*a3477ee4SGarrett D'Amore 
584*a3477ee4SGarrett D'Amore 		/* now put other linkages in place */
585*a3477ee4SGarrett D'Amore 		(void) find_link(&chip->p_vcpus, vc->v_link.l_id, &ins);
586*a3477ee4SGarrett D'Amore 		ins_link(ins, &vc->v_link_pchip);
587*a3477ee4SGarrett D'Amore 		chip->p_nvcpu++;
588*a3477ee4SGarrett D'Amore 
589*a3477ee4SGarrett D'Amore 		(void) find_link(&core->c_vcpus, vc->v_link.l_id, &ins);
590*a3477ee4SGarrett D'Amore 		ins_link(ins, &vc->v_link_core);
591*a3477ee4SGarrett D'Amore 		core->c_nvcpu++;
592*a3477ee4SGarrett D'Amore 	}
593*a3477ee4SGarrett D'Amore 
594*a3477ee4SGarrett D'Amore 	(void) kstat_close(kc);
595*a3477ee4SGarrett D'Amore 
596*a3477ee4SGarrett D'Amore 	nspec = 0;
597*a3477ee4SGarrett D'Amore 
598*a3477ee4SGarrett D'Amore 	while ((optc = getopt(argc, argv, "pvs")) != EOF) {
599*a3477ee4SGarrett D'Amore 		switch (optc) {
600*a3477ee4SGarrett D'Amore 		case 's':
601*a3477ee4SGarrett D'Amore 			opt_s = 1;
602*a3477ee4SGarrett D'Amore 			break;
603*a3477ee4SGarrett D'Amore 		case 'p':
604*a3477ee4SGarrett D'Amore 			opt_p = 1;
605*a3477ee4SGarrett D'Amore 			break;
606*a3477ee4SGarrett D'Amore 		case 'v':
607*a3477ee4SGarrett D'Amore 			opt_v = 1;
608*a3477ee4SGarrett D'Amore 			break;
609*a3477ee4SGarrett D'Amore 		default:
610*a3477ee4SGarrett D'Amore 			usage(NULL);
611*a3477ee4SGarrett D'Amore 		}
612*a3477ee4SGarrett D'Amore 	}
613*a3477ee4SGarrett D'Amore 
614*a3477ee4SGarrett D'Amore 	while (optind < argc) {
615*a3477ee4SGarrett D'Amore 		long id;
616*a3477ee4SGarrett D'Amore 		char *eptr;
617*a3477ee4SGarrett D'Amore 		struct link *l;
618*a3477ee4SGarrett D'Amore 		id = strtol(argv[optind], &eptr, 10);
619*a3477ee4SGarrett D'Amore 		l = find_link(&vcpus, id, NULL);
620*a3477ee4SGarrett D'Amore 		if ((*eptr != '\0') || (l == NULL)) {
621*a3477ee4SGarrett D'Amore 			(void) fprintf(stderr,
622*a3477ee4SGarrett D'Amore 			    _("%s: processor %s: Invalid argument\n"),
623*a3477ee4SGarrett D'Amore 			    cmdname, argv[optind]);
624*a3477ee4SGarrett D'Amore 			ex = 2;
625*a3477ee4SGarrett D'Amore 		} else {
626*a3477ee4SGarrett D'Amore 			((struct vcpu *)l->l_ptr)->v_doit = 1;
627*a3477ee4SGarrett D'Amore 			((struct vcpu *)l->l_ptr)->v_pchip->p_doit = 1;
628*a3477ee4SGarrett D'Amore 			((struct vcpu *)l->l_ptr)->v_core->c_doit = 1;
629*a3477ee4SGarrett D'Amore 		}
630*a3477ee4SGarrett D'Amore 		nspec++;
631*a3477ee4SGarrett D'Amore 		optind++;
632*a3477ee4SGarrett D'Amore 	}
633*a3477ee4SGarrett D'Amore 
634*a3477ee4SGarrett D'Amore 	if (opt_s && opt_v) {
635*a3477ee4SGarrett D'Amore 		usage(_("options -s and -v are mutually exclusive"));
636*a3477ee4SGarrett D'Amore 	}
637*a3477ee4SGarrett D'Amore 	if (opt_s && nspec != 1) {
638*a3477ee4SGarrett D'Amore 		usage(_("must specify exactly one processor if -s used"));
639*a3477ee4SGarrett D'Amore 	}
640*a3477ee4SGarrett D'Amore 	if (opt_v && opt_p) {
641*a3477ee4SGarrett D'Amore 		print_vp(nspec);
642*a3477ee4SGarrett D'Amore 	} else if (opt_s && opt_p) {
643*a3477ee4SGarrett D'Amore 		print_ps();
644*a3477ee4SGarrett D'Amore 	} else if (opt_p) {
645*a3477ee4SGarrett D'Amore 		print_p(nspec);
646*a3477ee4SGarrett D'Amore 	} else if (opt_v) {
647*a3477ee4SGarrett D'Amore 		print_v(nspec);
648*a3477ee4SGarrett D'Amore 	} else if (opt_s) {
649*a3477ee4SGarrett D'Amore 		print_s();
650*a3477ee4SGarrett D'Amore 	} else {
651*a3477ee4SGarrett D'Amore 		print_normal(nspec);
652*a3477ee4SGarrett D'Amore 	}
653*a3477ee4SGarrett D'Amore 
654*a3477ee4SGarrett D'Amore 	return (ex);
655*a3477ee4SGarrett D'Amore }
656