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 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 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 * 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 * 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 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 * 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 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 * 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 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 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 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 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 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 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 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