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