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