Home | History | Annotate | Download | only in intrstat
      1      0      stevel /*
      2      0      stevel  * CDDL HEADER START
      3      0      stevel  *
      4      0      stevel  * The contents of this file are subject to the terms of the
      5   8605    Jonathan  * Common Development and Distribution License (the "License").
      6   8605    Jonathan  * You may not use this file except in compliance with the License.
      7      0      stevel  *
      8      0      stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0      stevel  * or http://www.opensolaris.org/os/licensing.
     10      0      stevel  * See the License for the specific language governing permissions
     11      0      stevel  * and limitations under the License.
     12      0      stevel  *
     13      0      stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0      stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0      stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0      stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0      stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0      stevel  *
     19      0      stevel  * CDDL HEADER END
     20      0      stevel  */
     21      0      stevel /*
     22   8605    Jonathan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0      stevel  * Use is subject to license terms.
     24      0      stevel  */
     25      0      stevel 
     26      0      stevel #include <stdio.h>
     27      0      stevel #include <stdarg.h>
     28      0      stevel #include <dtrace.h>
     29      0      stevel #include <errno.h>
     30      0      stevel #include <string.h>
     31      0      stevel #include <stdlib.h>
     32      0      stevel #include <unistd.h>
     33      0      stevel #include <limits.h>
     34      0      stevel #include <strings.h>
     35      0      stevel #include <termio.h>
     36      0      stevel #include <signal.h>
     37  10265  Krishnendu #include <locale.h>
     38  10265  Krishnendu 
     39  10265  Krishnendu #include "statcommon.h"
     40      0      stevel 
     41      0      stevel #define	INTRSTAT_COLUMN_OFFS		14
     42      0      stevel #define	INTRSTAT_COLUMNS_PER_CPU	15
     43      0      stevel #define	INTRSTAT_CPUS_PER_LINE(w)	\
     44      0      stevel 	(((w) - INTRSTAT_COLUMN_OFFS) / INTRSTAT_COLUMNS_PER_CPU)
     45  10265  Krishnendu #define	INTRSTAT_OPTSTR			"x:c:C:T:"
     46  10265  Krishnendu 
     47  10265  Krishnendu static uint_t timestamp_fmt = NODATE;
     48  10265  Krishnendu 
     49  10265  Krishnendu #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
     50  10265  Krishnendu #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it isn't */
     51  10265  Krishnendu #endif
     52      0      stevel 
     53      0      stevel static dtrace_hdl_t *g_dtp;
     54      0      stevel static int *g_present;
     55      0      stevel static int g_max_cpus;
     56      0      stevel static int g_start, g_end;
     57      0      stevel static int g_header;
     58      0      stevel static long g_sleeptime = 1;
     59      0      stevel static hrtime_t g_interval = NANOSEC;
     60      0      stevel static int g_intr;
     61      0      stevel static psetid_t g_pset = PS_NONE;
     62      0      stevel static processorid_t *g_pset_cpus;
     63      0      stevel static uint_t g_pset_ncpus;
     64      0      stevel static int g_cpus_per_line = INTRSTAT_CPUS_PER_LINE(80);
     65      0      stevel 
     66      0      stevel static const char *g_pname = "intrstat";
     67      0      stevel static const char *g_prog =
     68      0      stevel "interrupt-start"
     69    191         ahl "/arg0 != NULL/"
     70      0      stevel "{"
     71      0      stevel "	self->ts = vtimestamp;"
     72      0      stevel "}"
     73      0      stevel ""
     74      0      stevel "interrupt-complete"
     75      0      stevel "/self->ts/"
     76      0      stevel "{"
     77      0      stevel "	this->devi = (struct dev_info *)arg0;"
     78      0      stevel "	@counts[stringof(`devnamesp[this->devi->devi_major].dn_name),"
     79      0      stevel "	     this->devi->devi_instance] = count();"
     80      0      stevel "	@times[stringof(`devnamesp[this->devi->devi_major].dn_name),"
     81      0      stevel "	     this->devi->devi_instance] = sum(vtimestamp - self->ts);"
     82      0      stevel "	self->ts = 0;"
     83      0      stevel "}";
     84      0      stevel 
     85      0      stevel static void
     86      0      stevel usage(void)
     87      0      stevel {
     88      0      stevel 	(void) fprintf(stderr,
     89   8605    Jonathan 	    "usage:  intrstat [ -C psrset | -c cpulist ]  [-x opt[=val]] "
     90  10265  Krishnendu 	    "[-T d|u] [interval [ count]]\n");
     91      0      stevel 
     92      0      stevel 	exit(EXIT_FAILURE);
     93      0      stevel }
     94      0      stevel 
     95      0      stevel static void
     96      0      stevel fatal(const char *fmt, ...)
     97      0      stevel {
     98      0      stevel 	va_list ap;
     99      0      stevel 
    100      0      stevel 	va_start(ap, fmt);
    101      0      stevel 
    102      0      stevel 	(void) fprintf(stderr, "%s: ", g_pname);
    103      0      stevel 	(void) vfprintf(stderr, fmt, ap);
    104      0      stevel 
    105      0      stevel 	if (fmt[strlen(fmt) - 1] != '\n')
    106      0      stevel 		(void) fprintf(stderr, ": %s\n",
    107      0      stevel 		    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
    108      0      stevel 
    109      0      stevel 	exit(EXIT_FAILURE);
    110      0      stevel }
    111      0      stevel 
    112      0      stevel /*ARGSUSED*/
    113      0      stevel static void
    114      0      stevel intr(int signo)
    115      0      stevel {
    116      0      stevel 	g_intr++;
    117      0      stevel }
    118      0      stevel 
    119      0      stevel static void
    120      0      stevel status(void)
    121      0      stevel {}
    122      0      stevel 
    123      0      stevel static void
    124      0      stevel set_width(void)
    125      0      stevel {
    126      0      stevel 	struct winsize win;
    127      0      stevel 
    128      0      stevel 	if (!isatty(fileno(stdout)))
    129      0      stevel 		return;
    130      0      stevel 
    131      0      stevel 	if (ioctl(fileno(stdout), TIOCGWINSZ, &win) == -1)
    132      0      stevel 		return;
    133      0      stevel 
    134      0      stevel 	if (win.ws_col == 0) {
    135      0      stevel 		/*
    136      0      stevel 		 * If TIOCGWINSZ returned 0 for the columns, just return --
    137      0      stevel 		 * thereby using the default value of g_cpus_per_line.  (This
    138      0      stevel 		 * happens, e.g., when running over a tip line.)
    139      0      stevel 		 */
    140      0      stevel 		return;
    141      0      stevel 	}
    142      0      stevel 
    143      0      stevel 	g_cpus_per_line = INTRSTAT_CPUS_PER_LINE(win.ws_col);
    144      0      stevel 
    145      0      stevel 	if (g_cpus_per_line < 1)
    146      0      stevel 		g_cpus_per_line = 1;
    147      0      stevel }
    148      0      stevel 
    149      0      stevel static void
    150      0      stevel print_header()
    151      0      stevel {
    152      0      stevel 	int i, j;
    153      0      stevel 	char c[256];
    154      0      stevel 
    155      0      stevel 	if (!g_header)
    156      0      stevel 		return;
    157      0      stevel 
    158      0      stevel 	(void) printf("\n%12s |", "device");
    159      0      stevel 	for (i = g_start, j = 0; i < g_max_cpus; i++) {
    160      0      stevel 		if (!g_present[i])
    161      0      stevel 			continue;
    162      0      stevel 
    163      0      stevel 		(void) sprintf(c, "cpu%d", i);
    164      0      stevel 		(void) printf(" %9s %%tim", c);
    165      0      stevel 
    166      0      stevel 		if (++j >= g_cpus_per_line)
    167      0      stevel 			break;
    168      0      stevel 	}
    169      0      stevel 
    170      0      stevel 	(void) printf("\n-------------+");
    171      0      stevel 
    172      0      stevel 	while (j--)
    173      0      stevel 		(void) printf("---------------");
    174      0      stevel 
    175      0      stevel 	(void) printf("\n");
    176      0      stevel 	g_header = 0;
    177      0      stevel }
    178      0      stevel 
    179      0      stevel /*ARGSUSED*/
    180      0      stevel static int
    181    457         bmc walk(const dtrace_aggdata_t *data, void *arg)
    182      0      stevel {
    183      0      stevel 	dtrace_aggdesc_t *aggdesc = data->dtada_desc;
    184      0      stevel 	dtrace_recdesc_t *nrec, *irec;
    185      0      stevel 	char *name, c[256];
    186      0      stevel 	int32_t *instance;
    187    457         bmc 	static const dtrace_aggdata_t *count;
    188      0      stevel 	int i, j;
    189      0      stevel 
    190      0      stevel 	if (count == NULL) {
    191      0      stevel 		count = data;
    192      0      stevel 		return (DTRACE_AGGWALK_NEXT);
    193      0      stevel 	}
    194      0      stevel 
    195      0      stevel 	nrec = &aggdesc->dtagd_rec[1];
    196      0      stevel 	irec = &aggdesc->dtagd_rec[2];
    197      0      stevel 
    198      0      stevel 	name = data->dtada_data + nrec->dtrd_offset;
    199      0      stevel 	/* LINTED - alignment */
    200      0      stevel 	instance = (int32_t *)(data->dtada_data + irec->dtrd_offset);
    201      0      stevel 
    202      0      stevel 	for (i = g_start, j = 0; i < g_max_cpus && j < g_cpus_per_line; i++) {
    203      0      stevel 		/* LINTED - alignment */
    204      0      stevel 		uint64_t time = *((uint64_t *)(data->dtada_percpu[i]));
    205      0      stevel 		/* LINTED - alignment */
    206      0      stevel 		uint64_t n = *((uint64_t *)(count->dtada_percpu[i]));
    207      0      stevel 
    208      0      stevel 		if (!g_present[i])
    209      0      stevel 			continue;
    210      0      stevel 
    211      0      stevel 		if (j++ == 0) {
    212      0      stevel 			print_header();
    213      0      stevel 			(void) snprintf(c, sizeof (c), "%s#%d",
    214   8605    Jonathan 			    name, *instance);
    215      0      stevel 			(void) printf("%12s |", c);
    216      0      stevel 		}
    217      0      stevel 
    218      0      stevel 		(void) printf(" %9lld %4.1f",
    219      0      stevel 		    (unsigned long long)((double)n /
    220      0      stevel 		    ((double)g_interval / (double)NANOSEC)),
    221      0      stevel 		    ((double)time * (double)100.0) / (double)g_interval);
    222      0      stevel 	}
    223      0      stevel 
    224      0      stevel 	(void) printf(j ? "\n" : "");
    225      0      stevel 	g_end = i;
    226      0      stevel 	count = NULL;
    227      0      stevel 	return (DTRACE_AGGWALK_NEXT);
    228      0      stevel }
    229      0      stevel 
    230      0      stevel static void
    231      0      stevel select_cpu(processorid_t cpu)
    232      0      stevel {
    233      0      stevel 	if (g_pset != PS_NONE)
    234      0      stevel 		fatal("cannot specify both a processor set and a processor\n");
    235      0      stevel 
    236      0      stevel 	if (cpu < 0 || cpu >= g_max_cpus)
    237      0      stevel 		fatal("cpu %d out of range\n", cpu);
    238      0      stevel 
    239      0      stevel 	if (p_online(cpu, P_STATUS) == -1) {
    240      0      stevel 		if (errno != EINVAL)
    241      0      stevel 			fatal("could not get status for cpu %d", cpu);
    242      0      stevel 		fatal("cpu %d not present\n", cpu);
    243      0      stevel 	}
    244      0      stevel 
    245      0      stevel 	g_present[cpu] = 1;
    246      0      stevel }
    247      0      stevel 
    248      0      stevel static void
    249      0      stevel select_cpus(processorid_t low, processorid_t high)
    250      0      stevel {
    251      0      stevel 	if (g_pset != PS_NONE)
    252      0      stevel 		fatal("cannot specify both a processor set and processors\n");
    253      0      stevel 
    254      0      stevel 	if (low < 0 || low >= g_max_cpus)
    255      0      stevel 		fatal("invalid cpu '%d'\n", low);
    256      0      stevel 
    257      0      stevel 	if (high < 0 || high >= g_max_cpus)
    258      0      stevel 		fatal("invalid cpu '%d'\n", high);
    259      0      stevel 
    260      0      stevel 	if (low >= high)
    261      0      stevel 		fatal("invalid range '%d' to '%d'\n", low, high);
    262      0      stevel 
    263      0      stevel 	do {
    264      0      stevel 		if (p_online(low, P_STATUS) != -1)
    265      0      stevel 			g_present[low] = 1;
    266      0      stevel 	} while (++low <= high);
    267      0      stevel }
    268      0      stevel 
    269      0      stevel static void
    270      0      stevel select_pset(psetid_t pset)
    271      0      stevel {
    272      0      stevel 	processorid_t i;
    273      0      stevel 
    274      0      stevel 	if (pset < 0)
    275      0      stevel 		fatal("processor set %d is out of range\n", pset);
    276      0      stevel 
    277      0      stevel 	/*
    278      0      stevel 	 * Only one processor set can be specified.
    279      0      stevel 	 */
    280      0      stevel 	if (g_pset != PS_NONE)
    281      0      stevel 		fatal("at most one processor set may be specified\n");
    282      0      stevel 
    283      0      stevel 	/*
    284      0      stevel 	 * One cannot select processors _and_ a processor set.
    285      0      stevel 	 */
    286      0      stevel 	for (i = 0; i < g_max_cpus; i++)
    287      0      stevel 		if (g_present[i])
    288      0      stevel 			break;
    289      0      stevel 
    290      0      stevel 	if (i != g_max_cpus)
    291      0      stevel 		fatal("cannot specify both a processor and a processor set\n");
    292      0      stevel 
    293      0      stevel 	g_pset = pset;
    294      0      stevel 	g_pset_ncpus = g_max_cpus;
    295      0      stevel 
    296      0      stevel 	if (pset_info(g_pset, NULL, &g_pset_ncpus, g_pset_cpus) == -1)
    297      0      stevel 		fatal("invalid processor set: %d\n", g_pset);
    298      0      stevel 
    299      0      stevel 	if (g_pset_ncpus == 0)
    300      0      stevel 		fatal("processor set %d empty\n", g_pset);
    301      0      stevel 
    302      0      stevel 	for (i = 0; i < g_pset_ncpus; i++)
    303      0      stevel 		g_present[g_pset_cpus[i]] = 1;
    304      0      stevel }
    305      0      stevel 
    306      0      stevel static void
    307      0      stevel check_pset(void)
    308      0      stevel {
    309      0      stevel 	uint_t ncpus = g_max_cpus;
    310      0      stevel 	processorid_t i;
    311      0      stevel 
    312      0      stevel 	if (g_pset == PS_NONE)
    313      0      stevel 		return;
    314      0      stevel 
    315      0      stevel 	if (pset_info(g_pset, NULL, &ncpus, g_pset_cpus) == -1) {
    316      0      stevel 		if (errno == EINVAL)
    317      0      stevel 			fatal("processor set %d destroyed\n", g_pset);
    318      0      stevel 
    319      0      stevel 		fatal("couldn't get info for processor set %d", g_pset);
    320      0      stevel 	}
    321      0      stevel 
    322      0      stevel 	if (ncpus == 0)
    323      0      stevel 		fatal("processor set %d empty\n", g_pset);
    324      0      stevel 
    325      0      stevel 	if (ncpus == g_pset_ncpus) {
    326      0      stevel 		for (i = 0; i < g_pset_ncpus; i++) {
    327      0      stevel 			if (!g_present[g_pset_cpus[i]])
    328      0      stevel 				break;
    329      0      stevel 		}
    330      0      stevel 
    331      0      stevel 		/*
    332      0      stevel 		 * If the number of CPUs hasn't changed, and every CPU
    333      0      stevel 		 * in the processor set is also selected, we know that the
    334      0      stevel 		 * processor set itself hasn't changed.
    335      0      stevel 		 */
    336      0      stevel 		if (i == g_pset_ncpus)
    337      0      stevel 			return;
    338      0      stevel 	}
    339      0      stevel 
    340      0      stevel 	/*
    341      0      stevel 	 * If we're here, we have a new processor set.  First, we need
    342      0      stevel 	 * to zero out the present array.
    343      0      stevel 	 */
    344      0      stevel 	bzero(g_present, sizeof (processorid_t) * g_max_cpus);
    345      0      stevel 
    346      0      stevel 	g_pset_ncpus = ncpus;
    347      0      stevel 
    348      0      stevel 	for (i = 0; i < g_pset_ncpus; i++)
    349      0      stevel 		g_present[g_pset_cpus[i]] = 1;
    350      0      stevel }
    351      0      stevel 
    352      0      stevel int
    353      0      stevel main(int argc, char **argv)
    354      0      stevel {
    355      0      stevel 	dtrace_prog_t *prog;
    356      0      stevel 	dtrace_proginfo_t info;
    357      0      stevel 	int err, i, indefinite = 1;
    358      0      stevel 	long iter;
    359      0      stevel 	processorid_t id;
    360      0      stevel 	struct sigaction act;
    361      0      stevel 	struct itimerspec ts;
    362      0      stevel 	struct sigevent ev;
    363      0      stevel 	sigset_t set;
    364      0      stevel 	timer_t tid;
    365   8605    Jonathan 	char *end, *p;
    366      0      stevel 	char c;
    367      0      stevel 	hrtime_t last, now;
    368      0      stevel 	dtrace_optval_t statustime;
    369      0      stevel 
    370  10265  Krishnendu 	(void) setlocale(LC_ALL, "");
    371  10265  Krishnendu 	(void) textdomain(TEXT_DOMAIN);
    372  10265  Krishnendu 
    373      0      stevel 	(void) sigemptyset(&act.sa_mask);
    374      0      stevel 	act.sa_flags = 0;
    375      0      stevel 	act.sa_handler = set_width;
    376      0      stevel 	(void) sigaction(SIGWINCH, &act, NULL);
    377      0      stevel 
    378      0      stevel 	(void) sigemptyset(&act.sa_mask);
    379      0      stevel 	act.sa_flags = 0;
    380      0      stevel 	act.sa_handler = intr;
    381      0      stevel 	(void) sigaction(SIGUSR1, &act, NULL);
    382      0      stevel 
    383      0      stevel 	(void) sigemptyset(&act.sa_mask);
    384      0      stevel 	act.sa_flags = 0;
    385      0      stevel 	act.sa_handler = status;
    386      0      stevel 	(void) sigaction(SIGUSR2, &act, NULL);
    387      0      stevel 
    388      0      stevel 	act.sa_handler = set_width;
    389      0      stevel 	(void) sigaction(SIGWINCH, &act, NULL);
    390      0      stevel 	set_width();
    391      0      stevel 
    392      0      stevel 	(void) sigemptyset(&set);
    393      0      stevel 	(void) sigaddset(&set, SIGUSR1);
    394      0      stevel 	(void) sigaddset(&set, SIGWINCH);
    395      0      stevel 	(void) sigprocmask(SIG_BLOCK, &set, NULL);
    396      0      stevel 
    397      0      stevel 	ev.sigev_notify = SIGEV_SIGNAL;
    398      0      stevel 	ev.sigev_signo = SIGUSR1;
    399      0      stevel 
    400      0      stevel 	if (timer_create(CLOCK_REALTIME, &ev, &tid) == -1)
    401      0      stevel 		fatal("cannot create CLOCK_HIGHRES timer");
    402      0      stevel 
    403      0      stevel 	g_max_cpus = sysconf(_SC_CPUID_MAX) + 1;
    404      0      stevel 
    405      0      stevel 	if ((g_present = malloc(sizeof (processorid_t) * g_max_cpus)) == NULL)
    406      0      stevel 		fatal("could not allocate g_present array\n");
    407      0      stevel 
    408      0      stevel 	bzero(g_present, sizeof (processorid_t) * g_max_cpus);
    409      0      stevel 
    410      0      stevel 	g_pset_cpus = malloc(sizeof (processorid_t) * g_max_cpus);
    411      0      stevel 	if (g_pset_cpus == NULL)
    412      0      stevel 		fatal("could not allocate g_pset_cpus");
    413      0      stevel 
    414      0      stevel 	bzero(g_pset_cpus, sizeof (processorid_t) * g_max_cpus);
    415      0      stevel 
    416   8605    Jonathan 	while ((c = getopt(argc, argv, INTRSTAT_OPTSTR)) != EOF) {
    417      0      stevel 		switch (c) {
    418      0      stevel 		case 'c': {
    419      0      stevel 			/*
    420      0      stevel 			 * We allow CPUs to be specified as an optionally
    421      0      stevel 			 * comma separated list of either CPU IDs or ranges
    422      0      stevel 			 * of CPU IDs.
    423      0      stevel 			 */
    424      0      stevel 			char *s = strtok(optarg, ",");
    425      0      stevel 
    426      0      stevel 			while (s != NULL) {
    427      0      stevel 				id = strtoul(s, &end, 0);
    428      0      stevel 
    429      0      stevel 				if (id == ULONG_MAX && errno == ERANGE) {
    430      0      stevel 					*end = '\0';
    431      0      stevel 					fatal("invalid cpu '%s'\n", s);
    432      0      stevel 				}
    433      0      stevel 
    434      0      stevel 				if (*(s = end) != '\0') {
    435      0      stevel 					processorid_t p;
    436      0      stevel 
    437      0      stevel 					if (*s != '-')
    438      0      stevel 						fatal("invalid cpu '%s'\n", s);
    439      0      stevel 					p = strtoul(++s, &end, 0);
    440      0      stevel 
    441      0      stevel 					if (*end != '\0' ||
    442      0      stevel 					    (p == ULONG_MAX && errno == ERANGE))
    443      0      stevel 						fatal("invalid cpu '%s'\n", s);
    444      0      stevel 
    445      0      stevel 					select_cpus(id, p);
    446      0      stevel 				} else {
    447      0      stevel 					select_cpu(id);
    448      0      stevel 				}
    449      0      stevel 
    450      0      stevel 				s = strtok(NULL, ",");
    451      0      stevel 			}
    452      0      stevel 
    453      0      stevel 			break;
    454      0      stevel 		}
    455      0      stevel 
    456      0      stevel 		case 'C': {
    457      0      stevel 			psetid_t pset = strtoul(optarg, &end, 0);
    458      0      stevel 
    459      0      stevel 			if (*end != '\0' ||
    460      0      stevel 			    (pset == ULONG_MAX && errno == ERANGE))
    461      0      stevel 				fatal("invalid processor set '%s'\n", optarg);
    462      0      stevel 
    463      0      stevel 			select_pset(pset);
    464      0      stevel 			break;
    465      0      stevel 		}
    466  10265  Krishnendu 
    467  10265  Krishnendu 		case 'T':
    468  10265  Krishnendu 			if (optarg) {
    469  10265  Krishnendu 				if (*optarg == 'u')
    470  10265  Krishnendu 					timestamp_fmt = UDATE;
    471  10265  Krishnendu 				else if (*optarg == 'd')
    472  10265  Krishnendu 					timestamp_fmt = DDATE;
    473  10265  Krishnendu 				else
    474  10265  Krishnendu 					usage();
    475  10265  Krishnendu 			} else {
    476  10265  Krishnendu 				usage();
    477  10265  Krishnendu 			}
    478  10265  Krishnendu 			break;
    479      0      stevel 
    480      0      stevel 		default:
    481   8605    Jonathan 			if (strchr(INTRSTAT_OPTSTR, c) == NULL)
    482   8605    Jonathan 				usage();
    483   8605    Jonathan 		}
    484   8605    Jonathan 	}
    485   8605    Jonathan 
    486   8605    Jonathan 	if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
    487   8605    Jonathan 		fatal("cannot open dtrace library: %s\n",
    488   8605    Jonathan 		    dtrace_errmsg(NULL, err));
    489   8605    Jonathan 	}
    490   8605    Jonathan 
    491   8605    Jonathan 	if ((prog = dtrace_program_strcompile(g_dtp, g_prog,
    492   8605    Jonathan 	    DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL)
    493   8605    Jonathan 		fatal("invalid program");
    494   8605    Jonathan 
    495   8605    Jonathan 	if (dtrace_program_exec(g_dtp, prog, &info) == -1)
    496   8605    Jonathan 		fatal("failed to enable probes");
    497   8605    Jonathan 
    498   8605    Jonathan 	if (dtrace_setopt(g_dtp, "aggsize", "128k") == -1)
    499   8605    Jonathan 		fatal("failed to set 'aggsize'");
    500   8605    Jonathan 
    501   8605    Jonathan 	if (dtrace_setopt(g_dtp, "aggrate", "0") == -1)
    502   8605    Jonathan 		fatal("failed to set 'aggrate'");
    503   8605    Jonathan 
    504   8605    Jonathan 	if (dtrace_setopt(g_dtp, "aggpercpu", 0) == -1)
    505   8605    Jonathan 		fatal("failed to set 'aggpercpu'");
    506   8605    Jonathan 
    507   8605    Jonathan 	optind = 1;
    508   8605    Jonathan 	while ((c = getopt(argc, argv, INTRSTAT_OPTSTR)) != EOF) {
    509   8605    Jonathan 		switch (c) {
    510   8605    Jonathan 		case 'x':
    511   8605    Jonathan 			if ((p = strchr(optarg, '=')) != NULL)
    512   8605    Jonathan 				*p++ = '\0';
    513   8605    Jonathan 
    514   8605    Jonathan 			if (dtrace_setopt(g_dtp, optarg, p) != 0)
    515   8605    Jonathan 				fatal("failed to set -x %s", optarg);
    516   8605    Jonathan 			break;
    517      0      stevel 		}
    518      0      stevel 	}
    519      0      stevel 
    520      0      stevel 	if (optind != argc) {
    521      0      stevel 		g_sleeptime = strtol(argv[optind], &end, 10);
    522      0      stevel 
    523      0      stevel 		if (*end != NULL || g_sleeptime == 0)
    524      0      stevel 			fatal("invalid interval '%s'\n", argv[1]);
    525      0      stevel 
    526      0      stevel 		if (g_sleeptime <= 0)
    527      0      stevel 			fatal("interval must be greater than zero.\n");
    528      0      stevel 
    529      0      stevel 		if (g_sleeptime == LONG_MAX && errno == ERANGE)
    530      0      stevel 			fatal("invalid interval '%s'\n", argv[optind]);
    531      0      stevel 
    532      0      stevel 		if (++optind != argc) {
    533      0      stevel 			char *s = argv[optind];
    534      0      stevel 
    535      0      stevel 			iter = strtol(s, &end, 0);
    536      0      stevel 			indefinite = 0;
    537      0      stevel 
    538      0      stevel 			if (*end != '\0' || iter <= 0 ||
    539      0      stevel 			    (iter == LONG_MAX && errno == ERANGE))
    540      0      stevel 				fatal("invalid count '%s'\n", s);
    541      0      stevel 		}
    542      0      stevel 	}
    543      0      stevel 
    544      0      stevel 	ts.it_value.tv_sec = g_sleeptime;
    545      0      stevel 	ts.it_value.tv_nsec = 0;
    546      0      stevel 	ts.it_interval.tv_sec = g_sleeptime;
    547      0      stevel 	ts.it_interval.tv_nsec = 0;
    548      0      stevel 
    549      0      stevel 	if (timer_settime(tid, TIMER_RELTIME, &ts, NULL) == -1)
    550      0      stevel 		fatal("cannot set time on CLOCK_REALTIME timer");
    551      0      stevel 
    552      0      stevel 	for (i = 0; i < g_max_cpus && !g_present[i]; i++)
    553      0      stevel 		continue;
    554      0      stevel 
    555      0      stevel 	if (i == g_max_cpus) {
    556      0      stevel 		for (i = 0; i < g_max_cpus; i++)
    557      0      stevel 			g_present[i] = p_online(i, P_STATUS) == -1 ? 0 : 1;
    558      0      stevel 	}
    559      0      stevel 
    560      0      stevel 	if (dtrace_go(g_dtp) != 0)
    561      0      stevel 		fatal("dtrace_go()");
    562      0      stevel 
    563      0      stevel 	last = gethrtime();
    564      0      stevel 
    565      0      stevel 	if (dtrace_getopt(g_dtp, "statusrate", &statustime) == -1)
    566      0      stevel 		fatal("failed to get 'statusrate'");
    567      0      stevel 
    568      0      stevel 	if (statustime < ((dtrace_optval_t)g_sleeptime * NANOSEC)) {
    569      0      stevel 		ev.sigev_notify = SIGEV_SIGNAL;
    570      0      stevel 		ev.sigev_signo = SIGUSR2;
    571      0      stevel 
    572      0      stevel 		if (timer_create(CLOCK_REALTIME, &ev, &tid) == -1)
    573      0      stevel 			fatal("cannot create status timer");
    574      0      stevel 
    575      0      stevel 		ts.it_value.tv_sec = statustime / NANOSEC;
    576      0      stevel 		ts.it_value.tv_nsec = statustime % NANOSEC;
    577      0      stevel 		ts.it_interval = ts.it_value;
    578      0      stevel 
    579      0      stevel 		if (timer_settime(tid, TIMER_RELTIME, &ts, NULL) == -1)
    580      0      stevel 			fatal("cannot set time on status timer");
    581      0      stevel 	}
    582      0      stevel 
    583      0      stevel 	(void) sigemptyset(&set);
    584      0      stevel 
    585      0      stevel 	while (indefinite || iter) {
    586      0      stevel 
    587      0      stevel 		(void) sigsuspend(&set);
    588      0      stevel 
    589   8605    Jonathan 		if (dtrace_status(g_dtp) == -1)
    590   8605    Jonathan 			fatal("dtrace_status()");
    591      0      stevel 
    592      0      stevel 		if (g_intr == 0)
    593      0      stevel 			continue;
    594      0      stevel 
    595      0      stevel 		iter--;
    596      0      stevel 		g_intr--;
    597      0      stevel 		check_pset();
    598      0      stevel 
    599      0      stevel 		now = gethrtime();
    600      0      stevel 		g_interval = now - last;
    601      0      stevel 		last = now;
    602      0      stevel 
    603      0      stevel 		if (dtrace_aggregate_snap(g_dtp) != 0)
    604      0      stevel 			fatal("failed to add to aggregate");
    605      0      stevel 
    606      0      stevel 		g_start = g_end = 0;
    607      0      stevel 
    608  10265  Krishnendu 		if (timestamp_fmt != NODATE)
    609  10265  Krishnendu 			print_timestamp(timestamp_fmt);
    610  10265  Krishnendu 
    611      0      stevel 		do {
    612      0      stevel 			g_header = 1;
    613      0      stevel 
    614      0      stevel 			if (dtrace_aggregate_walk_keyvarsorted(g_dtp,
    615      0      stevel 			    walk, NULL) != 0)
    616      0      stevel 				fatal("failed to sort aggregate");
    617      0      stevel 
    618      0      stevel 			if (g_start == g_end)
    619      0      stevel 				break;
    620      0      stevel 		} while ((g_start = g_end) < g_max_cpus);
    621      0      stevel 
    622      0      stevel 		dtrace_aggregate_clear(g_dtp);
    623      0      stevel 	}
    624      0      stevel 
    625      0      stevel 	return (0);
    626      0      stevel }
    627