/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/processor.h>
#include <sys/priocntl.h>
#include <sys/fxpriocntl.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <strings.h>
#include <thread.h>
#include <errno.h>
#include <libintl.h>
#include <locale.h>
#include <kstat.h>
#include <synch.h>
#include <libcpc.h>
#include <sys/resource.h>
#include "cpucmds.h"
#include "statcommon.h"
static struct options {
int debug;
int dotitle;
int dohelp;
int dotick;
int dosoaker;
int doperiod;
char *pgmname;
} __options;
/*
* States for soaker threads.
*/
#define SOAK_PAUSE 0
struct tstate {
int chip_id;
int status;
int soak_state;
};
static int ncpus;
static int max_chip_id;
/*ARGSUSED*/
static void
{
}
static int cpustat(void);
#if !defined(TEXT_DOMAIN)
#endif
int
{
char *errstr;
double period;
char *endp;
(void) textdomain(TEXT_DOMAIN);
else
/* Make sure we can open enough files */
gettext("%s: setrlimit failed - %s\n"),
}
return (1);
}
/*
* Check to see if cpustat needs to be SMT-aware.
*/
/*
* Establish some defaults
*/
return (1);
}
switch (c) {
case 'D': /* enable debugging */
break;
case 'c': /* specify statistics */
break;
case 'n': /* no titles */
break;
case 'p': /* periodic behavior */
if (*endp != '\0') {
optarg);
errcnt++;
}
break;
case 's': /* run soaker thread */
break;
case 't': /* print %tick */
break;
case 'T':
if (optarg) {
if (*optarg == 'u')
else if (*optarg == 'd')
else
errcnt++;
} else {
errcnt++;
}
break;
case 'h': /* help */
break;
case '?':
default:
errcnt++;
break;
}
case 0:
break;
case 2:
if (*endp != '\0') {
gettext("%s: invalid argument \"%s\"\n"),
errcnt++;
break;
}
/*FALLTHROUGH*/
case 1:
if (*endp != '\0') {
gettext("%s: invalid argument \"%s\"\n"),
errcnt++;
}
break;
default:
errcnt++;
break;
}
errcnt++;
"Usage:\n\t%s -c spec [-c spec]... [-p period] [-T u|d]\n"
"\t\t[-sntD] [interval [count]]\n\n"
"\t-c spec\t specify processor events to be monitored\n"
"\t-n\t suppress titles\n"
"\t-p period cycle through event list periodically\n"
"\t-s\t run user soaker thread for system-only events\n"
"\t-t\t include %s register\n"
"\t-T d|u\t Display a timestamp in date (d) or unix "
"time_t (u)\n"
"\t-D\t enable debug mode\n"
"\t-h\t print extended usage information\n\n"
"\tUse cputrack(1) to monitor per-process statistics.\n"),
(void) putchar('\n');
exit(0);
}
exit(2);
}
/*
* If the user requested periodic behavior, calculate the rest time
* between cycles.
*/
if ((int)opts->mseconds_rest < 0)
opts->mseconds_rest = 0;
}
/*
* If no system-mode only sets were created, no soaker threads will be
* needed.
*/
return (ret);
}
static void
{
}
static void
int sibling)
{
int ccnt;
int i;
for (i = 0; i < nreq; i++) {
}
" # %s\n", setname);
else
if (sibling) {
/*
* This sample is being printed for a "sibling" CPU -- that is,
* a CPU which does not have its own CPC set bound. It is being
* measured via a set bound to another CPU sharing its physical
* processor.
*/
char *p;
if (p != NULL) {
*p = '\0';
"# counter shared with CPU %d\n", designee);
}
}
if (timestamp_fmt != NODATE)
if (ccnt > 0)
/*
* If this CPU is the chip designee for any other CPUs, print a line for
* them here.
*/
for (i = 0; i < ncpus; i++) {
}
}
}
static void
{
int i;
ncpus, "total");
for (i = 0; i < nreq; i++) {
}
}
static void *
{
char *errstr;
int nreqs;
/*
* If this CPU is SMT, we run one gtick() thread per _physical_ CPU,
* instead of per cpu_t. The following check returns if it detects that
* this cpu_t has not been designated to do the counting for this
* physical CPU.
*/
return (NULL);
/*
* If we need to run a soaker thread on this CPU, start it here.
*/
goto bad;
NULL) != 0)
goto bad;
goto bad;
/*
* If the soaker needs to pause for the first set, stop it now.
*/
if (cpc_setgrp_sysonly(sgrp) == 0) {
}
}
goto bad;
continue;
/*
* If we're dealing with one set, buffer usage is:
*
* data1 = most recent data snapshot
* data2 = previous data snapshot
* scratch = used for diffing data1 and data2
*
* Save the snapshot from the previous sample in data2
* before putting the current sample in data1.
*/
goto bad;
} else {
/*
* More than one set is in use (multiple -c options
* given). Buffer usage in this case is:
*
* data1 = total counts for this set since program began
* data2 = unused
* scratch = most recent data snapshot
*/
&scratch);
goto bad;
"unbinding on cpu %d - %s\n"),
/*
* If periodic behavior was requested, rest here.
*/
/*
* Stop the soaker while the tool rests.
*/
}
}
/*
* Start or stop the soaker if needed.
*/
if (cpc_setgrp_sysonly(sgrp) &&
/*
* Soaker is paused but the next set is
* sysonly: start the soaker.
*/
} else if (cpc_setgrp_sysonly(sgrp) == 0 &&
/*
* Soaker is running but the next set
* counts user events: stop the soaker.
*/
}
goto bad;
}
}
/*
* We're done, so stop the soaker if needed.
*/
}
return (NULL);
bad:
return (NULL);
}
static int
cpustat(void)
{
int c, i, retval;
int lwps = 0;
char *errstr;
int nreqs;
return (1);
}
return (1);
}
for (i = 0; i < max_chip_id; i++)
chip_designees[i] = -1;
if (smt) {
return (1);
}
}
"%s: couldn't get FX scheduler class: %s\n"),
return (1);
}
/*
* Only include processors that are participating in the system
*/
for (c = 0, i = 0; i < ncpus; c++) {
case P_ONLINE:
case P_NOINTR:
if (smt) {
}
break;
case P_OFFLINE:
case P_POWEROFF:
case P_FAULTED:
case P_SPARE:
break;
default:
gettext("%s: cpu%d in unknown state\n"),
break;
case -1:
break;
}
}
/*
* Examine the processor sets; if we're in one, only attempt
* to report on the set we're in.
*/
} else {
for (i = 0; i < ncpus; i++) {
continue;
if (pset_assign(PS_QUERY,
gettext("%s: pset_assign - %s\n"),
continue;
}
}
}
zerotime();
for (i = 0; i < ncpus; i++) {
continue;
continue;
}
lwps++;
else {
gettext("%s: cannot create thread for cpu%d\n"),
}
}
if (lwps != 0)
for (i = 0; i < ncpus; i++)
return (1);
}
retval = 0;
for (i = 0; i < ncpus; i++) {
continue;
retval = 1;
}
do {
return (retval);
}
static int
{
kstat_named_t *k;
return (-1);
gettext("%s: kstat_read() failed for cpu %d: %s\n"),
return (-1);
}
gettext("%s: chip_id not found for cpu %d: %s\n"),
return (-1);
}
}
static void *
{
/*
* Put the soaker thread in the fixed priority (FX) class so it runs
* at the lowest possible global priority.
*/
fx->fx_uprilim = 0;
/*
* Let the parent thread know we're ready to roll.
*/
for (;;) {
spin:
goto spin;
}
}
/*NOTREACHED*/
return (NULL);
}