a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * This file and its contents are supplied under the terms of the
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Common Development and Distribution License ("CDDL"), version 1.0.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * You may only use this file in accordance with the terms of version
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * 1.0 of the CDDL.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * A full copy of the text of the CDDL should have accompanied this
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * source. A copy of the CDDL is also available via the Internet at
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
48ac0edb8d30534ebdebc9500c3ceb27b59257ddHans Rosenfeld * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * This implements psrinfo(1M), a utility to report various information
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * about processors, cores, and threads (virtual cpus). This is mostly
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * intended for human consumption - this utility doesn't do much more than
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * simply process kstats for human readability.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * All the relevant kstats are in the cpu_info kstat module.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore#define _(x) gettext(x)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore/* These CPU states are here for benefit of xgettext */
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore_("powered-off")
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * We deal with sorted linked lists, where the sort key is usually the
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * cpu id, core id, or chip id. We generalize this with simple node.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * A physical chip. A chip can contain multiple cores and virtual cpus.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) fprintf(stderr, "%s: %s\n", cmdname, msg);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore "\t%s [-v] [-p] [processor_id ...]\n" \
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore "\t%s -s [-p] processor_id\n"), cmdname, cmdname);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore/* like perror, but includes the command name */
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) fprintf(stderr, "%s: %s: %s\n", cmdname, msg, strerror(errno));
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Insert a new node on a list, at the insertion point given.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amoreins_link(struct link **ins, struct link *item)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Find an id on a sorted list. If the requested id is not found,
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * then the insertpt will be set (if not null) to the location where
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * a new node should be inserted with ins_link (see above).
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amorefind_link(void *list, int id, struct link ***insertpt)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Print the linked list of ids in parens, taking care to collapse
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * ranges, so instead of (0 1 2 3) it should print (0-3).
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore while (l != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore /* end of the contiguous group */
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amorestatic const char *
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) strftime(buffer, sizeof (buffer), _("%m/%d/%Y %T"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Note that some of the way these strings are broken up are
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * to accommodate the legacy translations so that we won't
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * have to retranslate for this utility.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((chip->p_ncore == 1) || (chip->p_ncore == chip->p_nvcpu)) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("The physical processor"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("processors") :
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("processor"));
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) printf(_("%s has %d %s and %d virtual %s"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("The physical processor"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((chip->p_ncore == 1) || (chip->p_ncore == chip->p_nvcpu)) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (strncmp(vcpu->v_brand, vcpu->v_impl, len) != 0))
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore for (l2 = chip->p_cores; l2; l2 = l2->l_next) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("The core"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (strncmp(vcpu->v_brand, vcpu->v_impl, len) != 0))
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Report "1" if all cpus colocated on the same chip are online.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore for (l = pchips; l != NULL; l = l->l_next) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore return; /* should never happen! */
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore for (l = p->p_vcpus; l != NULL; l = l->l_next) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Find the processor (there will be only one) that we selected,
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * and report whether or not it is online.
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore strcmp(v->v_state, "on-line") == 0 ? 1 : 0);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Print the number of physical packages with at least one processor
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore for (l1 = pchips; l1 != NULL; l1 = l1->l_next) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore for (l2 = p->p_vcpus; l2 != NULL; l2 = l2->l_next) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) printf(_("Status of virtual processor %d as of: "),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _(" The %s processor operates at %llu MHz,\n"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore v->v_cpu_type, (unsigned long long)v->v_clock_mhz);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _(" The %s processor operates at " \
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("\tand has no floating point processor.\n"));
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("\tand has an %s floating point processor.\n"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("\tand has a %s floating point processor.\n"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore l->l_id, _(v->v_state), timestr(v->v_state_begin));
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore /* collect the kstats */
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((ksp = kstat_lookup(kc, "cpu_info", -1, NULL)) == NULL)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if (strcmp(ksp->ks_module, "cpu_info") != 0)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore vc = find_link(&vcpus, ksp->ks_instance, &ins);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "state")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "cpu_type")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "fpu_type")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "state_begin")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "clock_MHz")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "brand")) == NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore vc->v_brand = mystrdup(knp->value.str.addr.ptr);
48ac0edb8d30534ebdebc9500c3ceb27b59257ddHans Rosenfeld if ((knp = kstat_data_lookup(ksp, "socket_type")) == NULL) {
48ac0edb8d30534ebdebc9500c3ceb27b59257ddHans Rosenfeld vc->v_socket = mystrdup(knp->value.str.addr.ptr);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "implementation")) == NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore vc->v_impl = mystrdup(knp->value.str.addr.ptr);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * Legacy code removed the chipid and cpuid fields... we
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * do the same for compatibility. Note that the original
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * pattern is a bit strange, and we have to emulate this because
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * on SPARC we *do* emit these. The original pattern we are
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore * emulating is: $impl =~ s/(cpuid|chipid)\s*\w+\s+//;
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((s = strstr(vc->v_impl, "chipid")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((s = strstr(vc->v_impl, "cpuid")) != NULL) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "chip_id")) != NULL)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore chip = find_link(&pchips, vc->v_pchip_id, &ins);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore if ((knp = kstat_data_lookup(ksp, "core_id")) != NULL)
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore core = find_link(&cores, vc->v_core_id, &ins);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) find_link(&chip->p_cores, core->c_link.l_id,
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore /* now put other linkages in place */
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) find_link(&chip->p_vcpus, vc->v_link.l_id, &ins);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore (void) find_link(&core->c_vcpus, vc->v_link.l_id, &ins);
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore while ((optc = getopt(argc, argv, "pvs")) != EOF) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore _("%s: processor %s: Invalid argument\n"),
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore ((struct vcpu *)l->l_ptr)->v_pchip->p_doit = 1;
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore ((struct vcpu *)l->l_ptr)->v_core->c_doit = 1;
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore usage(_("options -s and -v are mutually exclusive"));
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore usage(_("must specify exactly one processor if -s used"));
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore } else if (opt_p) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore } else if (opt_v) {
a3477ee4728af4a4c3c6869e248aa735d52cbefbGarrett D'Amore } else if (opt_s) {