psrinfo.c revision a3477ee4728af4a4c3c6869e248aa735d52cbefb
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
*/
/*
* This implements psrinfo(1M), a utility to report various information
* about processors, cores, and threads (virtual cpus). This is mostly
* intended for human consumption - this utility doesn't do much more than
* simply process kstats for human readability.
*
* All the relevant kstats are in the cpu_info kstat module.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <kstat.h>
#include <libintl.h>
#include <locale.h>
#include <libgen.h>
#include <ctype.h>
#include <errno.h>
#define _(x) gettext(x)
#if XGETTEXT
/* These CPU states are here for benefit of xgettext */
_("on-line")
_("off-line")
_("faulted")
_("powered-off")
_("no-intr")
_("spare")
_("unknown")
#endif
/*
* We deal with sorted linked lists, where the sort key is usually the
* cpu id, core id, or chip id. We generalize this with simple node.
*/
struct link {
long l_id;
void *l_ptr;
};
/*
* A physical chip. A chip can contain multiple cores and virtual cpus.
*/
struct pchip {
int p_ncore;
int p_nvcpu;
int p_doit;
};
struct core {
struct link c_link_pchip;
int c_nvcpu;
int c_doit;
};
struct vcpu {
struct link v_link_core;
struct link v_link_pchip;
int v_doit;
char *v_state;
long v_state_begin;
char *v_cpu_type;
char *v_fpu_type;
long v_clock_mhz;
long v_pchip_id; /* 1 per socket */
char *v_impl;
char *v_brand;
long v_core_id; /* n per chip_id */
};
static const char *cmdname;
static void
{
"\t%s [-v] [-p] [processor_id ...]\n" \
exit(2);
}
/* like perror, but includes the command name */
static void
{
exit(2);
}
static char *
{
char *dst;
die(_("strdup() failed"));
return (dst);
}
static void *
{
void *ptr;
die(_("calloc() failed"));
return (ptr);
}
/*
* Insert a new node on a list, at the insertion point given.
*/
static void
{
}
/*
* Find an id on a sorted list. If the requested id is not found,
* then the insertpt will be set (if not null) to the location where
* a new node should be inserted with ins_link (see above).
*/
static void *
{
struct link *l;
return (l->l_ptr);
break;
}
return (NULL);
}
/*
* Print the linked list of ids in parens, taking care to collapse
* ranges, so instead of (0 1 2 3) it should print (0-3).
*/
static void
print_links(struct link *l)
{
int start = -1;
int end = 0;
(void) printf(" (");
while (l != NULL) {
if (start < 0) {
}
/* end of the contiguous group */
} else {
}
if (l->l_next)
(void) printf(" ");
start = -1;
}
l = l->l_next;
}
(void) printf(")");
}
static const char *
timestr(long t)
{
static char buffer[256];
localtime(&t));
return (buffer);
}
static void
{
int len;
continue;
/*
* Note that some of the way these strings are broken up are
* to accommodate the legacy translations so that we won't
* have to retranslate for this utility.
*/
(void) printf(_("%s has %d virtual %s"),
_("The physical processor"),
_("processors") :
_("processor"));
} else {
(void) printf(_("%s has %d %s and %d virtual %s"),
_("The physical processor"),
_("processors") : _("processor"));
}
(void) putchar('\n');
}
(void) putchar('\n');
} else {
(void) printf(_(" %s has %d virtual %s"),
_("The core"),
_("processors") : _("processor"));
(void) putchar('\n');
}
}
}
}
}
static void
print_ps(void)
{
int online = 1;
struct pchip *p;
struct vcpu *v;
struct link *l;
/*
* Report "1" if all cpus colocated on the same chip are online.
*/
p = l->l_ptr;
if (p->p_doit)
break;
}
if (p == NULL)
return; /* should never happen! */
v = l->l_ptr;
online = 0;
break;
}
}
}
static void
print_s(void)
{
struct link *l;
/*
* Find the processor (there will be only one) that we selected,
* and report whether or not it is online.
*/
if (v->v_doit) {
(void) printf("%d\n",
return;
}
}
}
static void
{
int online = 0;
/*
* Print the number of physical packages with at least one processor
* online.
*/
online++;
break;
}
}
}
}
}
static void
{
struct link *l;
continue;
(void) printf(_("Status of virtual processor %d as of: "),
l->l_id);
(void) printf(_(" %s since %s.\n"),
if (v->v_clock_mhz) {
(void) printf(
_(" The %s processor operates at %llu MHz,\n"),
v->v_cpu_type, (unsigned long long)v->v_clock_mhz);
} else {
(void) printf(
_(" The %s processor operates at " \
"an unknown frequency,\n"), v->v_cpu_type);
}
switch (*v->v_fpu_type) {
case '\0':
(void) printf(
_("\tand has no floating point processor.\n"));
break;
case 'a': case 'A':
case 'e': case 'E':
case 'i': case 'I':
case 'o': case 'O':
case 'u': case 'U':
case 'y': case 'Y':
(void) printf(
_("\tand has an %s floating point processor.\n"),
v->v_fpu_type);
break;
default:
(void) printf(
_("\tand has a %s floating point processor.\n"),
v->v_fpu_type);
break;
}
}
}
static void
print_normal(int nspec)
{
struct link *l;
struct vcpu *v;
v = l->l_ptr;
(void) printf(_("%d\t%-8s since %s\n"),
}
}
}
int
{
char *s;
int nspec;
int optc;
int opt_s = 0;
int opt_p = 0;
int opt_v = 0;
int ex = 0;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
/* collect the kstats */
die(_("kstat_open() failed"));
die(_("kstat_lookup() failed"));
continue;
die(_("kstat_read() failed"));
}
} else {
}
}
}
}
}
} else {
}
} else {
}
/*
* Legacy code removed the chipid and cpuid fields... we
* do the same for compatibility. Note that the original
* pattern is a bit strange, and we have to emulate this because
* on SPARC we *do* emit these. The original pattern we are
* emulating is: $impl =~ s/(cpuid|chipid)\s*\w+\s+//;
*/
char *x = s + strlen("chipid");
while (isspace(*x))
x++;
if ((!isalnum(*x)) && (*x != '_'))
goto nochipid;
while (isalnum(*x) || (*x == '_'))
x++;
if (!isspace(*x))
goto nochipid;
while (isspace(*x))
x++;
(void) strcpy(s, x);
}
char *x = s + strlen("cpuid");
while (isspace(*x))
x++;
if ((!isalnum(*x)) && (*x != '_'))
goto nocpuid;
while (isalnum(*x) || (*x == '_'))
x++;
if (!isspace(*x))
goto nocpuid;
while (isspace(*x))
x++;
(void) strcpy(s, x);
}
}
&ins);
}
/* now put other linkages in place */
}
(void) kstat_close(kc);
nspec = 0;
switch (optc) {
case 's':
opt_s = 1;
break;
case 'p':
opt_p = 1;
break;
case 'v':
opt_v = 1;
break;
default:
}
}
long id;
char *eptr;
struct link *l;
_("%s: processor %s: Invalid argument\n"),
ex = 2;
} else {
}
nspec++;
optind++;
}
usage(_("options -s and -v are mutually exclusive"));
}
usage(_("must specify exactly one processor if -s used"));
}
print_ps();
} else if (opt_p) {
} else if (opt_v) {
} else if (opt_s) {
print_s();
} else {
}
return (ex);
}