Home | History | Annotate | Download | only in busstat
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <strings.h>
     32 #include <time.h>
     33 #include <signal.h>
     34 #include <sys/types.h>
     35 #include <sys/stat.h>
     36 #include <sys/time.h>
     37 #include <sys/modctl.h>
     38 #include <sys/systeminfo.h>
     39 #include <limits.h>
     40 #include <signal.h>
     41 #include <fcntl.h>
     42 #include <unistd.h>
     43 #include <stropts.h>
     44 #include <locale.h>
     45 #include <libintl.h>
     46 #include <libgen.h>
     47 #include <nl_types.h>
     48 #include <kstat.h>
     49 #include <ctype.h>
     50 #include <signal.h>
     51 #include <errno.h>
     52 #include <time.h>
     53 
     54 #include "busstat.h"
     55 
     56 
     57 /* Global defines */
     58 static int		delta = TRUE;
     59 static int		banner = TRUE;
     60 static int		max_pic_num = 1;
     61 static int		initial_read = TRUE;
     62 static char		*pgmname;
     63 static kstat_ctl_t	*kc;			/* libkstat cookie */
     64 static dev_node_t	*dev_list_head	= NULL;
     65 static dev_node_t	*dev_list_tail	= NULL;
     66 
     67 /*
     68  * Global flags.
     69  */
     70 static char	curr_dev_name[KSTAT_STRLEN];
     71 static int	curr_inst_num;
     72 
     73 static void print_evt(void);
     74 static void print_dev(int, char *);
     75 static void parse_cmd(int);
     76 static void parse_dev_inst(char *);
     77 static void parse_pic_evt(char *);
     78 static void add_dev_node(char *, int);
     79 static void add_all_dev_node(char *);
     80 static void add_evt_node(dev_node_t *);
     81 static void modify_evt_node(dev_node_t *, char *);
     82 static void prune_evt_nodes(dev_node_t *);
     83 static void setup_evts(void);
     84 static void set_evt(dev_node_t *);
     85 static void read_evts(void);
     86 static void read_r_evt_node(dev_node_t *, int, kstat_named_t *);
     87 static void read_w_evt_node(dev_node_t *, int, kstat_named_t *);
     88 static void check_dr_ops(void);
     89 static void remove_dev_node(dev_node_t *);
     90 static dev_node_t *find_dev_node(char *, int, int);
     91 static kstat_t *find_pic_kstat(char *, int, char *);
     92 static int64_t is_num(char *);
     93 static void print_banner(void);
     94 static void print_timestamp(void);
     95 static void usage(void);
     96 static void *safe_malloc(size_t);
     97 static void set_timer(int);
     98 static void handle_sig(int);
     99 static int strisnum(const char *);
    100 
    101 int
    102 main(int argc, char **argv)
    103 {
    104 	int		c, i;
    105 	int		interval = 1;	/* Interval between displays */
    106 	int		count = 0;	/* Number of times to sample */
    107 	int		write_evts = FALSE;
    108 	int		pos = 0;
    109 
    110 #if !defined(TEXT_DOMAIN)
    111 #define	TEXT_DOMAIN	"SYS_TEST"
    112 #endif
    113 
    114 	/* For I18N */
    115 	(void) setlocale(LC_ALL, "");
    116 	(void) textdomain(TEXT_DOMAIN);
    117 
    118 	pgmname = basename(argv[0]);
    119 
    120 	if ((kc = kstat_open()) == NULL) {
    121 		(void) fprintf(stderr, gettext("%s: could not "
    122 			"open /dev/kstat\n"), pgmname);
    123 		exit(1);
    124 	}
    125 
    126 	while ((c = getopt(argc, argv, "e:w:r:ahln")) != EOF) {
    127 		switch (c) {
    128 		case 'a':
    129 			delta = FALSE;
    130 			break;
    131 		case 'e':
    132 			(void) print_evt();
    133 			break;
    134 		case 'h':
    135 			usage();
    136 			break;
    137 		case 'l':
    138 			(void) print_dev(argc, argv[argc-1]);
    139 			break;
    140 		case 'n':
    141 			banner = FALSE;
    142 			break;
    143 		case 'r':
    144 			(void) parse_cmd(READ_EVT);
    145 			break;
    146 		case 'w':
    147 			(void) parse_cmd(WRITE_EVT);
    148 			write_evts = TRUE;
    149 			break;
    150 		default:
    151 			(void) fprintf(stderr, gettext("%s: invalid "
    152 				"option\n"), pgmname);
    153 			usage();
    154 			break;
    155 		}
    156 	}
    157 
    158 	if ((argc == 1) || (dev_list_head == NULL))
    159 		usage();
    160 
    161 	/*
    162 	 * validate remaining operands are numeric.
    163 	 */
    164 	pos = optind;
    165 	while (pos < argc) {
    166 		if (strisnum(argv[pos]) == 0) {
    167 			(void) fprintf(stderr,
    168 				gettext("%s: syntax error\n"),
    169 				pgmname);
    170 			usage();
    171 		}
    172 		pos++;
    173 	}
    174 
    175 	if (optind < argc) {
    176 		if ((interval = atoi(argv[optind])) == 0) {
    177 			(void) fprintf(stderr, gettext("%s: invalid "
    178 				"interval value\n"), pgmname);
    179 			exit(1);
    180 		}
    181 
    182 		optind++;
    183 		if (optind < argc)
    184 			if ((count = atoi(argv[optind])) <= 0) {
    185 				(void) fprintf(stderr, gettext("%s: "
    186 					"invalid iteration value.\n"),
    187 					    pgmname);
    188 				exit(1);
    189 			}
    190 	}
    191 
    192 	set_timer(interval);
    193 
    194 	/*
    195 	 * Set events for the first time.
    196 	 */
    197 	if (write_evts == TRUE)
    198 		setup_evts();
    199 
    200 
    201 	if (count > 0) {
    202 		for (i = 0; i < count; i++) {
    203 			if (banner)
    204 				print_banner();
    205 
    206 			check_dr_ops();
    207 			read_evts();
    208 			(void) fflush(stdout);
    209 			(void) pause();
    210 		}
    211 	} else {
    212 		for (;;) {
    213 			if (banner)
    214 				print_banner();
    215 
    216 			check_dr_ops();
    217 			read_evts();
    218 			(void) fflush(stdout);
    219 			(void) pause();
    220 		}
    221 	}
    222 
    223 	read_evts();
    224 	return (0);
    225 }
    226 
    227 
    228 /*
    229  * Display all the events that can be set on a device.
    230  */
    231 void
    232 print_evt()
    233 {
    234 	kstat_t		*cnt_ksp;
    235 	kstat_t		*pic_ksp;
    236 	kstat_named_t	*cnt_data;
    237 	kstat_named_t	*pic_data;
    238 	char		*device = NULL;
    239 	char		*value;
    240 	int		inst_num = -1;
    241 	int		i = 0;
    242 	int		j;
    243 
    244 	value = optarg;
    245 
    246 	/*
    247 	 * Search through the value string for a numeric char which will
    248 	 * be the device instance number, if the user specified one. If
    249 	 * the user did not specify an instance then the return value from
    250 	 * strscpn will be equal to the string length. In this case we
    251 	 * use a default value of -1 for the kstat_lookup which causes
    252 	 * the device number to be ignored during the search.
    253 	 */
    254 	if (((i = strcspn(value, "0123456789")) > 0) && (i != strlen(value))) {
    255 
    256 		device = safe_malloc(sizeof (char) * i+1);
    257 		device[i] = '\0';
    258 		(void) strncpy(device, value, i);
    259 
    260 		value = value + i;
    261 		inst_num = atoi(value);
    262 	}
    263 
    264 	/*
    265 	 * No instance specified.
    266 	 */
    267 	if (device == NULL)
    268 		device = value;
    269 
    270 	/*
    271 	 * Get the "counters" kstat, so that we can get
    272 	 * the names of the "picN" kstats, which hold the
    273 	 * event names.
    274 	 */
    275 	if ((cnt_ksp = kstat_lookup(kc, device, inst_num, "counters"))
    276 								== NULL) {
    277 		(void) fprintf(stderr, gettext("%s: invalid device "
    278 			"name or instance (%s)\n"), pgmname, device);
    279 		exit(1);
    280 	}
    281 
    282 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
    283 		(void) fprintf(stderr, gettext("%s: could not read "
    284 			"kstat.\n"), pgmname);
    285 		exit(1);
    286 	}
    287 
    288 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
    289 
    290 	/*
    291 	 * Start at 1 as the first entry in the "counters"
    292 	 * kstat is the pcr value/name. We are looking for the
    293 	 * name of the "picN" kstats. For each one found store
    294 	 * a pointer to it in pic_data[].
    295 	 */
    296 	if (cnt_ksp->ks_ndata <= 1) {
    297 		(void) fprintf(stderr, gettext("%s: invalid kstat "
    298 			"structure.\n"), pgmname);
    299 		exit(1);
    300 	}
    301 
    302 	for (i = 1; i < cnt_ksp->ks_ndata; i++) {
    303 		if ((pic_ksp = find_pic_kstat(device, inst_num,
    304 			cnt_data[i].name)) == NULL) {
    305 
    306 			(void) fprintf(stderr, gettext("%s: could not read "
    307 				"pic kstat data structure for %s\n"),
    308 				    pgmname, cnt_ksp->ks_module);
    309 
    310 			exit(1);
    311 		}
    312 
    313 		if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
    314 			(void) fprintf(stderr, gettext("%s: could not read "
    315 				"pic kstat.\n"), pgmname);
    316 
    317 			exit(1);
    318 		}
    319 
    320 		pic_data = (kstat_named_t *)pic_ksp->ks_data;
    321 
    322 		(void) printf(gettext("pic%-8d\n"), i-1);
    323 
    324 		for (j = 0; j < pic_ksp->ks_ndata-1; j++) {
    325 			(void) printf("%-30s\n", pic_data[j].name);
    326 		}
    327 
    328 		(void) printf("\n");
    329 	}
    330 
    331 	exit(0);
    332 }
    333 
    334 
    335 /*
    336  * Display the names and instances of the devices on the system
    337  * which can support performance monitoring.
    338  */
    339 void
    340 print_dev(int argc, char *str)
    341 {
    342 	kstat_t	*ksp;
    343 	static int first_time = 1;
    344 
    345 	if ((argc > 2) || (strcmp(str, "-l") != 0)) {
    346 		(void) fprintf(stderr, gettext("%s: no arguments "
    347 			"permitted with -l option.\n"),
    348 			    pgmname);
    349 		usage();
    350 		exit(1);
    351 	}
    352 
    353 	/*
    354 	 * For each device node, print the node name (device
    355 	 * name) and the instance numbers.
    356 	 */
    357 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
    358 		if ((strcmp(ksp->ks_class, "bus") == 0) &&
    359 			(strcmp(ksp->ks_name, "counters") == 0)) {
    360 					if (first_time) {
    361 						(void) printf(gettext("Busstat "
    362 							"Device(s):\n"));
    363 						first_time = 0;
    364 					}
    365 					(void) printf("%s%d ", ksp->ks_module,
    366 						ksp->ks_instance);
    367 		}
    368 	}
    369 
    370 	if (first_time)
    371 		(void) fprintf(stderr, gettext("%s: No devices available "
    372 			"in system."), pgmname);
    373 
    374 	(void) printf("\n");
    375 
    376 	exit(0);
    377 }
    378 
    379 /*
    380  * Parses the cmd line, checks all the values and
    381  * creates the appropiate data structures.
    382  */
    383 void
    384 parse_cmd(int mode)
    385 {
    386 	char		*options = optarg, *value;
    387 	int		arg_num	= 0;
    388 
    389 	while ((value = (char *)strtok(options, ",=")) != NULL) {
    390 		/*
    391 		 * First arg must be device name.
    392 		 */
    393 		if (!arg_num) {
    394 			parse_dev_inst(value);
    395 		} else {
    396 			if (mode == READ_EVT) {
    397 				(void) fprintf(stderr, gettext("%s: "
    398 					"event names or pic values not "
    399 					"permitted with -r option.\n"),
    400 					    pgmname);
    401 					usage();
    402 				exit(1);
    403 			}
    404 			/*
    405 			 * Now dealing with pic values.
    406 			 */
    407 			parse_pic_evt(value);
    408 		}
    409 		/*
    410 		 * After first strtok call, must set first arg
    411 		 * to null if wish to parse rest of string.
    412 		 * See strtok man page.
    413 		 */
    414 		if (options != NULL)
    415 			options = NULL;
    416 		arg_num++;
    417 	}
    418 }
    419 
    420 
    421 /*
    422  * Parse the device name/instance section of the
    423  * command line.
    424  */
    425 void
    426 parse_dev_inst(char *value)
    427 {
    428 	int		i;
    429 	char		*device	= NULL;
    430 	int		malloc_flag = FALSE;
    431 
    432 	if (strlen(value) == 0) {
    433 		(void) fprintf(stderr, gettext("%s: No device name given.\n"),
    434 			pgmname);
    435 		exit(1);
    436 	}
    437 
    438 	/*
    439 	 * Break string into device name and
    440 	 * instance number (if given).
    441 	 */
    442 	if ((i = strcspn(value, "0123456789")) > 0) {
    443 		if (i != strlen(value)) {
    444 			device = safe_malloc(sizeof (char) * i+1);
    445 			device[i] = '\0';
    446 
    447 			(void) strncpy(device, value, i);
    448 			malloc_flag = TRUE;
    449 
    450 			value = value + i;
    451 		}
    452 	}
    453 
    454 	/*
    455 	 * No instance was specified so we assume
    456 	 * the user wants to use ALL instances.
    457 	 */
    458 	if (device == NULL) {
    459 		if ((device = value) == NULL) {
    460 			(void) fprintf(stderr, gettext("%s: no device "
    461 				"specified\n"), pgmname);
    462 			exit(1);
    463 		}
    464 
    465 		/*
    466 		 * Set global flags.
    467 		 */
    468 		(void) strcpy(curr_dev_name, device);
    469 		curr_inst_num = -1;
    470 
    471 		add_all_dev_node(device);
    472 		goto clean_up;
    473 	}
    474 
    475 	/*
    476 	 * Set global flags.
    477 	 */
    478 	(void) strcpy(curr_dev_name, device);
    479 	curr_inst_num = atoi(value);
    480 
    481 	add_dev_node(device, curr_inst_num);
    482 
    483 clean_up:
    484 	if (malloc_flag) {
    485 		free(device);
    486 	}
    487 }
    488 
    489 
    490 /*
    491  * Adds new event nodes to existing ones, modifies existing ones, or
    492  * prunes existing ones.
    493  *
    494  * A specific instance call will overwrite an earlier all
    495  * instances call, but *not* vice-versa.
    496  *
    497  * All the state transitions are given below.
    498  *
    499  *
    500  *                       Call Type
    501  * STATE |  Specific Instance          All Instances.
    502  * ======================================================
    503  * INIT  | Change state to       | Change state to ALL,
    504  *       | INST, add events      | add events.
    505  *       |                       |
    506  * INST  | State unchanged,      | No change.
    507  *       | Add events.           |
    508  *       |                       |
    509  * ALL   | Change state to       | State unchanged,
    510  *       | INST, replace events. | add events.
    511  */
    512 void
    513 parse_pic_evt(char *value)
    514 {
    515 	dev_node_t	*dev_node;
    516 	char		*evt_name;
    517 	int		pic_num;
    518 
    519 	if (strlen(value) <= PIC_STR_LEN) {
    520 		(void) fprintf(stderr, gettext("%s: no pic number "
    521 			"specified.\n"), pgmname);
    522 		exit(1);
    523 	}
    524 
    525 	if (strncmp(value, "pic", PIC_STR_LEN) != 0) {
    526 		(void) fprintf(stderr, gettext("%s: missing pic "
    527 			"specifier\n"), pgmname);
    528 		usage();
    529 	}
    530 
    531 	/*
    532 	 * Step over the 'pic' part of the string to
    533 	 * get the pic number.
    534 	 */
    535 	value = value + PIC_STR_LEN;
    536 	pic_num = atoi(value);
    537 
    538 	if ((pic_num == -1) || (pic_num > max_pic_num -1)) {
    539 		(void) fprintf(stderr, gettext("%s: invalid pic "
    540 			"number.\n"), pgmname);
    541 		exit(1);
    542 	}
    543 
    544 	if ((evt_name = (char *)strtok(NULL, "=,")) == NULL) {
    545 		(void) fprintf(stderr, gettext("%s: no event "
    546 			"specified.\n"), pgmname);
    547 		exit(1);
    548 	}
    549 
    550 	/*
    551 	 * Dealing with a specific instance.
    552 	 */
    553 	if (curr_inst_num >= 0) {
    554 		if ((dev_node = find_dev_node(curr_dev_name,
    555 			curr_inst_num, pic_num)) == NULL) {
    556 			(void) fprintf(stderr, gettext("%s: could not find "
    557 				"data structures for %s\n"),
    558 				    pgmname, curr_dev_name);
    559 			exit(1);
    560 		}
    561 
    562 		if (dev_node->r_w == EVT_READ) {
    563 			modify_evt_node(dev_node, evt_name);
    564 			dev_node->r_w = EVT_WRITE;
    565 			dev_node->state = STATE_INST;
    566 
    567 		} else if ((dev_node->r_w == EVT_WRITE) &&
    568 			(dev_node->state == STATE_ALL)) {
    569 
    570 			prune_evt_nodes(dev_node);
    571 			modify_evt_node(dev_node, evt_name);
    572 			dev_node->state = STATE_INST;
    573 
    574 		} else if ((dev_node->r_w == EVT_WRITE) &&
    575 			(dev_node->state == STATE_INST)) {
    576 
    577 			add_evt_node(dev_node);
    578 			modify_evt_node(dev_node, evt_name);
    579 		}
    580 
    581 		return;
    582 	}
    583 
    584 	/*
    585 	 * Dealing with all instances of a specific device.
    586 	 */
    587 	dev_node = dev_list_head;
    588 	while (dev_node != NULL) {
    589 		if ((strcmp(dev_node->name, curr_dev_name) == 0) &&
    590 			(dev_node->pic_num == pic_num)) {
    591 
    592 			if (dev_node->r_w == EVT_READ) {
    593 				modify_evt_node(dev_node,
    594 					evt_name);
    595 
    596 				dev_node->r_w = EVT_WRITE;
    597 				dev_node->state = STATE_ALL;
    598 
    599 			} else if ((dev_node->r_w == EVT_WRITE) &&
    600 				(dev_node->state == STATE_ALL)) {
    601 
    602 				add_evt_node(dev_node);
    603 				modify_evt_node(dev_node, evt_name);
    604 
    605 			}
    606 		}
    607 		dev_node = dev_node->next;
    608 	}
    609 }
    610 
    611 
    612 /*
    613  * Create a dev_node structure for this device if one does not
    614  * already exist.
    615  */
    616 void
    617 add_dev_node(char *dev_name, int inst_num)
    618 {
    619 	dev_node_t	*new_dev_node;
    620 	kstat_named_t	*cnt_data;
    621 	kstat_t		*cnt_ksp;
    622 	kstat_t		*pic_ksp;
    623 	int		pic_num;
    624 
    625 
    626 	if ((cnt_ksp = kstat_lookup(kc, dev_name,
    627 		inst_num, "counters")) == NULL) {
    628 		(void) fprintf(stderr, gettext("%s: invalid device "
    629 			"name or instance (%s%d)\n"), pgmname,
    630 				dev_name, inst_num);
    631 		exit(1);
    632 	}
    633 
    634 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
    635 		(void) fprintf(stderr, gettext("%s : could not read counters "
    636 			"kstat for device %s.\n"), pgmname, dev_name);
    637 		exit(1);
    638 	}
    639 
    640 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
    641 
    642 	if (cnt_ksp->ks_ndata <= 1) {
    643 		(void) fprintf(stderr, gettext("%s : invalid "
    644 			"kstat structure.\n"), pgmname);
    645 		exit(1);
    646 	}
    647 
    648 	/*
    649 	 * max_pic_num used to format headers correctly
    650 	 * for printing.
    651 	 */
    652 	if (cnt_ksp->ks_ndata-1 > max_pic_num)
    653 		max_pic_num = cnt_ksp->ks_ndata-1;
    654 
    655 	/* for each pic... */
    656 	for (pic_num = 0; pic_num < cnt_ksp->ks_ndata-1; pic_num++) {
    657 		if (find_dev_node(dev_name, inst_num, pic_num) != NULL) {
    658 			/* Node already exists */
    659 			continue;
    660 		}
    661 
    662 		new_dev_node = safe_malloc(sizeof (dev_node_t));
    663 		bzero(new_dev_node, sizeof (dev_node_t));
    664 
    665 		(void) strcpy(new_dev_node->name, dev_name);
    666 		new_dev_node->dev_inst = inst_num;
    667 		new_dev_node->pic_num = pic_num;
    668 
    669 		new_dev_node->cnt_ksp = cnt_ksp;
    670 
    671 		if ((pic_ksp = find_pic_kstat(dev_name, inst_num,
    672 			cnt_data[pic_num+1].name)) == NULL) {
    673 
    674 			(void) fprintf(stderr, gettext("%s: could not find "
    675 				"pic kstat structure for %s.\n"),
    676 				    pgmname, cnt_ksp->ks_module);
    677 			exit(1);
    678 		}
    679 
    680 		new_dev_node->pic_ksp = pic_ksp;
    681 
    682 		add_evt_node(new_dev_node);
    683 
    684 		new_dev_node->state = STATE_INIT;
    685 		new_dev_node->r_w = EVT_READ;
    686 
    687 		if (dev_list_head == NULL) {
    688 			dev_list_head = new_dev_node;
    689 			dev_list_tail = new_dev_node;
    690 
    691 		} else if (find_dev_node(dev_name, inst_num, pic_num) == NULL) {
    692 			dev_list_tail->next = new_dev_node;
    693 			dev_list_tail = new_dev_node;
    694 		}
    695 	}
    696 }
    697 
    698 
    699 /*
    700  * Add all possible instances of a device.
    701  */
    702 void
    703 add_all_dev_node(char *dev_name)
    704 {
    705 	kstat_t	*ksp;
    706 	int	match = 0;
    707 
    708 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
    709 		if ((strcmp(ksp->ks_class, "bus") == 0) &&
    710 			(strcmp(ksp->ks_name, "counters") == 0) &&
    711 			(strcmp(ksp->ks_module, dev_name) == 0)) {
    712 				match = 1;
    713 				add_dev_node(dev_name, ksp->ks_instance);
    714 		}
    715 	}
    716 
    717 	if (match == 0) {
    718 		(void) fprintf(stderr,
    719 			gettext("%s: invalid device name (%s)\n"),
    720 			pgmname, dev_name);
    721 		exit(1);
    722 	}
    723 }
    724 
    725 
    726 /*
    727  * Add an event node to a specified device node.
    728  */
    729 void
    730 add_evt_node(dev_node_t *dev_node)
    731 {
    732 	evt_node_t	*new_evt_node;
    733 	evt_node_t	*curr_evt_node;
    734 
    735 	new_evt_node = safe_malloc(sizeof (evt_node_t));
    736 	bzero(new_evt_node, sizeof (evt_node_t));
    737 
    738 	(void) strcpy(new_evt_node->evt_name, "");
    739 
    740 	if (dev_node->evt_node == NULL) {
    741 		dev_node->evt_node = new_evt_node;
    742 		new_evt_node->next = new_evt_node;
    743 		return;
    744 	} else {
    745 		curr_evt_node = dev_node->evt_node;
    746 		while (curr_evt_node->next != dev_node->evt_node)
    747 			curr_evt_node = curr_evt_node->next;
    748 
    749 		curr_evt_node->next = new_evt_node;
    750 		new_evt_node->next = dev_node->evt_node;
    751 	}
    752 }
    753 
    754 
    755 /*
    756  * Fill in or change the fields of an evt node.
    757  */
    758 void
    759 modify_evt_node(dev_node_t *dev_node, char *evt_name)
    760 {
    761 	evt_node_t	*evt_node;
    762 	kstat_t		*pic_ksp;
    763 	kstat_named_t	*pic_data;
    764 	int64_t		evt_num = 0;
    765 	int		evt_match = 0;
    766 	int		i;
    767 
    768 	evt_node = dev_node->evt_node;
    769 
    770 	/*
    771 	 * Find the last event node.
    772 	 */
    773 	if (evt_node->next != evt_node) {
    774 		while (evt_node->next != dev_node->evt_node) {
    775 			evt_node = evt_node->next;
    776 		}
    777 	}
    778 
    779 	evt_node->prev_count = 0;
    780 	evt_node->total = 0;
    781 
    782 	pic_ksp = dev_node->pic_ksp;
    783 
    784 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
    785 		(void) fprintf(stderr, gettext("%s: could not read "
    786 			"pic kstat.\n"), pgmname);
    787 		exit(1);
    788 	}
    789 
    790 	pic_data = (kstat_named_t *)dev_node->pic_ksp->ks_data;
    791 
    792 	/*
    793 	 * The event can either be given as a event name (string) or
    794 	 * as a pcr mask. If given as pcr mask, we try to match it
    795 	 * to an event name, and use that name. Otherwise we just use
    796 	 * the pcr mask value.
    797 	 */
    798 	if ((evt_num = is_num(evt_name)) == EVT_STR) {
    799 		(void) strcpy(evt_node->evt_name, evt_name);
    800 
    801 		for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
    802 			if (strcmp(evt_name, pic_data[i].name) == 0) {
    803 				evt_node->evt_pcr_mask = pic_data[i].value.ui64;
    804 				return;
    805 			}
    806 		}
    807 
    808 		(void) fprintf(stderr,
    809 			gettext("%s: %s is not a valid event name.\n"),
    810 			pgmname, evt_name);
    811 		exit(1);
    812 
    813 	} else {
    814 		/*
    815 		 * See if the pcr mask given by the user matches that for any
    816 		 * existing event.
    817 		 */
    818 		for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
    819 			if (evt_num == pic_data[i].value.ui64) {
    820 				(void) strcpy(evt_node->evt_name,
    821 					pic_data[i].name);
    822 				evt_match = 1;
    823 				break;
    824 			}
    825 		}
    826 
    827 		if (evt_match == 0)
    828 			(void) sprintf(evt_node->evt_name, "%llx", evt_num);
    829 
    830 		evt_node->evt_pcr_mask = evt_num;
    831 	}
    832 }
    833 
    834 
    835 /*
    836  * Removes all bar one of the evt_nodes that are hanging off the
    837  * specified dev_node.
    838  */
    839 void
    840 prune_evt_nodes(dev_node_t *dev_node)
    841 {
    842 	evt_node_t	*next_evt_node;
    843 	evt_node_t	*curr_evt_node;
    844 
    845 	/*
    846 	 * Only one evt node, nothing for us to do.
    847 	 */
    848 	if (dev_node->evt_node->next == dev_node->evt_node) {
    849 		return;
    850 	}
    851 
    852 	curr_evt_node = dev_node->evt_node->next;
    853 	dev_node->evt_node->next = dev_node->evt_node;
    854 
    855 	while (curr_evt_node != dev_node->evt_node) {
    856 		next_evt_node = curr_evt_node->next;
    857 		free(curr_evt_node);
    858 		curr_evt_node = next_evt_node;
    859 	}
    860 }
    861 
    862 
    863 /*
    864  * Set the events for each pic on each device instance.
    865  */
    866 void
    867 setup_evts()
    868 {
    869 	dev_node_t	*dev_node;
    870 
    871 	dev_node = dev_list_head;
    872 
    873 	while (dev_node != NULL) {
    874 		if (dev_node->r_w == EVT_WRITE)
    875 			set_evt(dev_node);
    876 
    877 		dev_node = dev_node->next;
    878 	}
    879 }
    880 
    881 
    882 /*
    883  * Set the appropiate events. Only called for event nodes
    884  * that are marked EVT_WRITE.
    885  */
    886 void
    887 set_evt(dev_node_t *dev_node)
    888 {
    889 	kstat_named_t	*cnt_data;
    890 	kstat_named_t	*pic_data;
    891 	kstat_t		*cnt_ksp;
    892 	kstat_t		*pic_ksp;
    893 	evt_node_t	*evt_node;
    894 	uint64_t	clear_pcr_mask;
    895 	uint64_t	pcr;
    896 	int		pic_num;
    897 
    898 	cnt_ksp = dev_node->cnt_ksp;
    899 	pic_ksp = dev_node->pic_ksp;
    900 	pic_num = dev_node->pic_num;
    901 	evt_node = dev_node->evt_node;
    902 
    903 	/* Read the "counters" kstat */
    904 	if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
    905 		(void) fprintf(stderr, gettext("%s: could "
    906 			"not set event's.\n"), pgmname);
    907 		exit(1);
    908 	}
    909 
    910 	cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
    911 
    912 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
    913 		(void) fprintf(stderr, gettext("%s: could "
    914 			"not set event's.\n"), pgmname);
    915 		exit(1);
    916 	}
    917 
    918 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
    919 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
    920 
    921 	if ((pic_num < 0) || (pic_num > cnt_ksp->ks_ndata-1)) {
    922 		(void) fprintf(stderr,
    923 			gettext("%s: invalid pic #%d.\n"),
    924 			pgmname, pic_num);
    925 		exit(1);
    926 	}
    927 
    928 	/*
    929 	 * Store the previous value that is on the pic
    930 	 * so that we can calculate the delta value
    931 	 * later.
    932 	 */
    933 	evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
    934 
    935 
    936 	/*
    937 	 * Read the current pcr value from device.
    938 	 */
    939 	pcr = cnt_data[0].value.ui64;
    940 
    941 	/*
    942 	 * Clear the section of the pcr which corresponds to the
    943 	 * pic we are setting events on. Also clear the pcr value
    944 	 * which is stored in the instance node.
    945 	 *
    946 	 */
    947 	pcr = pcr & clear_pcr_mask;
    948 
    949 	/*
    950 	 * Set the event.
    951 	 */
    952 	pcr = pcr | evt_node->evt_pcr_mask;
    953 	cnt_data[0].value.ui64 = pcr;
    954 
    955 	/*
    956 	 * Write the value back to the kstat, to make it
    957 	 * visible to the underlying driver.
    958 	 */
    959 	if (kstat_write(kc, cnt_ksp, NULL) == FAIL) {
    960 		(void) fprintf(stderr, gettext("%s: could not set events "
    961 					"(setting events requires root "
    962 					    "permission).\n"), pgmname);
    963 		exit(1);
    964 	}
    965 }
    966 
    967 
    968 /*
    969  * Works through the list of device nodes, reading events
    970  * and where appropiate setting new events (multiplexing).
    971  */
    972 void
    973 read_evts()
    974 {
    975 	dev_node_t	*dev_node;
    976 	kstat_t		*cnt_ksp;
    977 	kstat_named_t	*cnt_data;
    978 	char		tmp_str[30];
    979 	int		iter = 0;
    980 
    981 	dev_node = dev_list_head;
    982 
    983 	while (dev_node != NULL) {
    984 		if (iter == 0)
    985 			print_timestamp();
    986 		/*
    987 		 * First read of all the counters is done
    988 		 * to establish a baseline for the counts.
    989 		 * This data is not printed.
    990 		 */
    991 		if ((!initial_read) && (iter == 0)) {
    992 			(void) snprintf(tmp_str, sizeof (tmp_str), "%s%d",
    993 				dev_node->name, dev_node->dev_inst);
    994 			(void) printf("%-7s", tmp_str);
    995 		}
    996 
    997 		cnt_ksp = (kstat_t *)dev_node->cnt_ksp;
    998 
    999 		if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
   1000 			(void) fprintf(stderr, gettext("%s: device %s%d "
   1001 				"(pic %d) no longer valid.\n"),
   1002 				    pgmname, dev_node->name,
   1003 				    dev_node->dev_inst,
   1004 				    dev_node->pic_num);
   1005 			remove_dev_node(dev_node);
   1006 			dev_node = dev_list_head;
   1007 			continue;
   1008 		}
   1009 
   1010 		cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
   1011 
   1012 		if (dev_node->r_w == EVT_READ) {
   1013 			read_r_evt_node(dev_node, dev_node->pic_num, cnt_data);
   1014 			iter++;
   1015 		} else {
   1016 			read_w_evt_node(dev_node, dev_node->pic_num, cnt_data);
   1017 			iter++;
   1018 		}
   1019 
   1020 		if ((!initial_read) && (iter == max_pic_num)) {
   1021 			iter = 0;
   1022 			(void) printf("\n");
   1023 		}
   1024 
   1025 		/*
   1026 		 * If there is more than one event node
   1027 		 * per-pic then we are multiplexing.
   1028 		 */
   1029 		if ((dev_node->evt_node->next != dev_node->evt_node) &&
   1030 			(!initial_read)) {
   1031 				dev_node->evt_node = dev_node->evt_node->next;
   1032 				set_evt(dev_node);
   1033 		}
   1034 		dev_node = dev_node->next;
   1035 	}
   1036 	initial_read = FALSE;
   1037 }
   1038 
   1039 
   1040 /*
   1041  * Read a node that is marked as EVT_READ
   1042  */
   1043 void
   1044 read_r_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
   1045 {
   1046 	evt_node_t	*evt_node;
   1047 	kstat_t		*pic_ksp;
   1048 	kstat_named_t	*pic_data;
   1049 	uint64_t	pcr_read;
   1050 	uint64_t	clear_pcr_mask;
   1051 	uint64_t	delta_count;
   1052 	int		i;
   1053 	int		match = 0;
   1054 	int		evt_blank = 1;
   1055 
   1056 	evt_node = dev_node->evt_node;
   1057 
   1058 	pic_ksp = (kstat_t *)dev_node->pic_ksp;
   1059 
   1060 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
   1061 		(void) fprintf(stderr, gettext("%s: device %s%d "
   1062 			"(pic %d) no longer valid.\n"), pgmname,
   1063 			    dev_node->name, dev_node->dev_inst,
   1064 			    dev_node->pic_num);
   1065 		remove_dev_node(dev_node);
   1066 		return;
   1067 	}
   1068 
   1069 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
   1070 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
   1071 
   1072 	/*
   1073 	 * Get PCR value from device. We extract the portion
   1074 	 * of the PCR relating to the pic we are interested by
   1075 	 * AND'ing the inverse of the clear mask for this pic.
   1076 	 *
   1077 	 * The clear mask is usually used to clear the appropiate
   1078 	 * section of the PCR before we write events into it. So
   1079 	 * by using the inverse of the mask, we zero everything
   1080 	 * *but* the section we are interested in.
   1081 	 */
   1082 	pcr_read = cnt_data[0].value.ui64;
   1083 	pcr_read = pcr_read & ~(clear_pcr_mask);
   1084 
   1085 	/*
   1086 	 * If the event name is blank this is the first time that
   1087 	 * this node has been accessed, so we read the pcr and
   1088 	 * from that we get the event name if it exists.
   1089 	 *
   1090 	 * If the pcr read from the device does not match that
   1091 	 * stored in the node, then it means that the event has
   1092 	 * changed from its previous value, so we need to re-read
   1093 	 * all the values.
   1094 	 */
   1095 	if ((strcmp(evt_node->evt_name, "") == 0) ||
   1096 		(pcr_read != evt_node->evt_pcr_mask)) {
   1097 
   1098 		for (i = 0; i < pic_ksp->ks_ndata-1; i++) {
   1099 			if (pcr_read == pic_data[i].value.ui64) {
   1100 				match = TRUE;
   1101 				break;
   1102 			}
   1103 		}
   1104 
   1105 		/*
   1106 		 * Able to resolve pcr value to a event name.
   1107 		 */
   1108 		if (match) {
   1109 			(void) strcpy(evt_node->evt_name, pic_data[i].name);
   1110 			evt_node->evt_pcr_mask = pcr_read;
   1111 			evt_node->total = 0;
   1112 			evt_node->prev_count =
   1113 				cnt_data[pic_num+1].value.ui64;
   1114 
   1115 			if ((evt_blank) && (!initial_read)) {
   1116 				(void) printf("%s\t%-8d\t",
   1117 					evt_node->evt_name, 0);
   1118 				evt_blank = 0;
   1119 			}
   1120 
   1121 		} else {
   1122 			(void) sprintf(evt_node->evt_name, "0x%llx", pcr_read);
   1123 			evt_node->evt_pcr_mask = pcr_read;
   1124 			evt_node->total = 0;
   1125 			evt_node->prev_count =
   1126 				cnt_data[pic_num+1].value.ui64;
   1127 
   1128 			if ((evt_blank) && (!initial_read)) {
   1129 				(void) printf("%s\t%-8d\t",
   1130 					evt_node->evt_name, 0);
   1131 				evt_blank = 0;
   1132 			}
   1133 
   1134 		}
   1135 	} else {
   1136 		/* Deal with wraparound of the counters */
   1137 		if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
   1138 
   1139 			delta_count = (UINT32_MAX-evt_node->prev_count) +
   1140 				cnt_data[pic_num+1].value.ui64;
   1141 		} else {
   1142 			/* Calcalate delta value */
   1143 			delta_count = cnt_data[pic_num+1].value.ui64
   1144 						- evt_node->prev_count;
   1145 		}
   1146 
   1147 
   1148 		/*
   1149 		 * Store value so that we can calculate delta next
   1150 		 * time through.
   1151 		 */
   1152 		evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
   1153 
   1154 		/* Update count total */
   1155 		evt_node->total += delta_count;
   1156 
   1157 		if (delta) {
   1158 			(void) printf("%-20s %-9lld   ",
   1159 				evt_node->evt_name, delta_count);
   1160 		} else {
   1161 
   1162 			(void) printf("%-20s %-9lld   ",
   1163 				evt_node->evt_name, evt_node->total);
   1164 		}
   1165 	}
   1166 }
   1167 
   1168 
   1169 /*
   1170  * Read event nodes marked as EVT_WRITE
   1171  */
   1172 void
   1173 read_w_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
   1174 {
   1175 	kstat_t		*pic_ksp;
   1176 	kstat_named_t	*pic_data;
   1177 	evt_node_t	*evt_node;
   1178 	uint64_t	delta_count;
   1179 	uint64_t	pcr_read;
   1180 	uint64_t	clear_pcr_mask;
   1181 
   1182 	evt_node = dev_node->evt_node;
   1183 
   1184 	pic_ksp = (kstat_t *)dev_node->pic_ksp;
   1185 
   1186 	if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
   1187 		(void) fprintf(stderr, gettext("%s: could not read "
   1188 			"%s%d\n"), pgmname, dev_node->name,
   1189 			    dev_node->dev_inst);
   1190 		remove_dev_node(dev_node);
   1191 		return;
   1192 	}
   1193 
   1194 	pic_data = (kstat_named_t *)pic_ksp->ks_data;
   1195 	clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
   1196 
   1197 	/*
   1198 	 * Get PCR value from device. We extract the portion
   1199 	 * of the PCR relating to the pic we are interested by
   1200 	 * AND'ing the inverse of the clear mask for this pic.
   1201 	 *
   1202 	 * The clear mask is usually used to clear the appropiate
   1203 	 * section of the PCR before we write events into it. So
   1204 	 * by using the inverse of the mask, we zero everything
   1205 	 * *but* the section we are interested in.
   1206 	 */
   1207 	pcr_read = cnt_data[0].value.ui64;
   1208 	pcr_read = pcr_read & ~(clear_pcr_mask);
   1209 
   1210 	/*
   1211 	 * If the pcr value from the device does not match the
   1212 	 * stored value, then the events on at least one of the
   1213 	 * pics must have been change by another busstat instance.
   1214 	 *
   1215 	 * Regard this as a fatal error.
   1216 	 */
   1217 	if (pcr_read != evt_node->evt_pcr_mask) {
   1218 		(void) fprintf(stderr, gettext("%s: events changed (possibly "
   1219 			"by another busstat).\n"), pgmname);
   1220 		exit(2);
   1221 	}
   1222 
   1223 	/*
   1224 	 * Calculate delta, and then store value just read to allow us to
   1225 	 * calculate delta next time around.
   1226 	 */
   1227 	/* Deal with wraparound of the counters */
   1228 	if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
   1229 
   1230 		delta_count = (UINT32_MAX-evt_node->prev_count) +
   1231 			cnt_data[pic_num+1].value.ui64;
   1232 	} else {
   1233 		/* Calcalate delta value */
   1234 		delta_count = cnt_data[pic_num+1].value.ui64
   1235 			- evt_node->prev_count;
   1236 	}
   1237 
   1238 	evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
   1239 
   1240 	if (initial_read) {
   1241 		evt_node->total = 0;
   1242 
   1243 	} else {
   1244 		/* Update count total */
   1245 		evt_node->total += delta_count;
   1246 
   1247 		if (delta) {
   1248 			(void) printf("%-20s %-9lld   ",
   1249 				evt_node->evt_name, delta_count);
   1250 		} else {
   1251 			(void) printf("%-20s %-9lld   ",
   1252 				evt_node->evt_name, evt_node->total);
   1253 		}
   1254 	}
   1255 }
   1256 
   1257 
   1258 /*
   1259  * Check to see if any DR operations have occured, and deal with the
   1260  * consequences.
   1261  *
   1262  * Use the Kstat chain ID to check for DR operations. If the ID has
   1263  * changed then some kstats on system have been modified, we check
   1264  * all the data structures to see are they still valid. If they are
   1265  * not we remove them.
   1266  */
   1267 void
   1268 check_dr_ops()
   1269 {
   1270 	dev_node_t	*dev_node;
   1271 	kid_t		new_id;
   1272 	kstat_t		*ksp;
   1273 	int		match = 0;
   1274 
   1275 	if ((new_id = kstat_chain_update(kc)) < 0) {
   1276 		(void) fprintf(stderr, gettext("%s: could not get "
   1277 			"kstat chain id\n"), pgmname);
   1278 		exit(1);
   1279 	}
   1280 
   1281 	if (new_id == 0) {
   1282 		/* Kstat chain has not changed. */
   1283 		return;
   1284 	}
   1285 
   1286 	/*
   1287 	 * Scan the chain of device nodes, making sure that their associated
   1288 	 * kstats are still present. If not we remove the appropiate node.
   1289 	 */
   1290 	dev_node = dev_list_head;
   1291 
   1292 	while (dev_node != NULL) {
   1293 		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
   1294 			if ((strcmp("bus", ksp->ks_class) == 0) &&
   1295 				(strcmp("counters", ksp->ks_name) == 0) &&
   1296 				(strcmp(dev_node->name, ksp->ks_module) == 0) &&
   1297 				(ksp->ks_instance == dev_node->dev_inst)) {
   1298 					match = 1;
   1299 					break;
   1300 			}
   1301 		}
   1302 		if (match == 0) {
   1303 			(void) fprintf(stderr, gettext("%s: device %s%d"
   1304 				" (pic %d) no longer valid.\n"), pgmname,
   1305 				    dev_node->name, dev_node->dev_inst,
   1306 				    dev_node->pic_num);
   1307 
   1308 			remove_dev_node(dev_node);
   1309 		}
   1310 		dev_node = dev_node->next;
   1311 	}
   1312 }
   1313 
   1314 
   1315 
   1316 /*
   1317  * Remove a device node and its associated event nodes.
   1318  */
   1319 void
   1320 remove_dev_node(dev_node_t *dev_node)
   1321 {
   1322 	dev_node_t	*curr_node;
   1323 	dev_node_t	*prev_node;
   1324 	evt_node_t	*curr_evt_node;
   1325 	evt_node_t	*next_evt_node;
   1326 	evt_node_t	*start_pos;
   1327 
   1328 	curr_node = dev_list_head;
   1329 
   1330 	if (curr_node == dev_node) {
   1331 		dev_list_head = dev_node->next;
   1332 
   1333 		if (dev_list_head == NULL) {
   1334 			(void) fprintf(stderr, gettext("%s: no "
   1335 				"devices left to monitor.\n"),
   1336 				    pgmname);
   1337 			exit(1);
   1338 		}
   1339 
   1340 		/* Remove each event node first */
   1341 		start_pos = dev_node->evt_node;
   1342 		curr_evt_node = start_pos->next;
   1343 
   1344 		while (curr_evt_node != start_pos) {
   1345 			next_evt_node = curr_evt_node->next;
   1346 
   1347 			free(curr_evt_node);
   1348 			curr_evt_node = next_evt_node;
   1349 		}
   1350 
   1351 		free(start_pos);
   1352 		free(dev_node);
   1353 		return;
   1354 	}
   1355 
   1356 	/* Find the device node */
   1357 	prev_node = dev_list_head;
   1358 	curr_node = prev_node->next;
   1359 
   1360 	while (curr_node != NULL) {
   1361 		if (curr_node == dev_node) {
   1362 			prev_node->next = curr_node->next;
   1363 
   1364 			/* Remove each event node first */
   1365 			start_pos = dev_node->evt_node;
   1366 			curr_evt_node = start_pos->next;
   1367 
   1368 			while (curr_evt_node != start_pos) {
   1369 				next_evt_node = curr_evt_node->next;
   1370 
   1371 				free(curr_evt_node);
   1372 				curr_evt_node = next_evt_node;
   1373 			}
   1374 			free(start_pos);
   1375 
   1376 			free(dev_node);
   1377 			return;
   1378 		}
   1379 		prev_node = curr_node;
   1380 		curr_node = curr_node->next;
   1381 	}
   1382 }
   1383 
   1384 
   1385 /*
   1386  * Find a device node in the linked list of dev_nodes. Match
   1387  * is done on device name, and instance number.
   1388  */
   1389 dev_node_t *
   1390 find_dev_node(char *name, int inst_num, int pic_num)
   1391 {
   1392 	dev_node_t	*curr_node;
   1393 
   1394 	curr_node = dev_list_head;
   1395 
   1396 	while (curr_node != NULL) {
   1397 		if ((strcmp(curr_node->name, name) == 0) &&
   1398 			(curr_node->dev_inst == inst_num) &&
   1399 			(curr_node->pic_num == pic_num)) {
   1400 				return (curr_node);
   1401 		}
   1402 
   1403 		curr_node = curr_node->next;
   1404 	}
   1405 
   1406 	return (NULL);
   1407 }
   1408 
   1409 
   1410 /*
   1411  * Determines whether the string represents a event name
   1412  * or a numeric value. Numeric value can be dec, hex
   1413  * or octal. All are converted to long int.
   1414  */
   1415 int64_t
   1416 is_num(char *name)
   1417 {
   1418 	char	*remainder = NULL;
   1419 	int64_t	num;
   1420 
   1421 	num = (int64_t)strtol(name, &remainder, 0);
   1422 
   1423 	if (name == remainder) {
   1424 		return (EVT_STR);
   1425 	} else {
   1426 		return (num);
   1427 	}
   1428 }
   1429 
   1430 
   1431 /*
   1432  * Find a pointer to the specified picN kstat. First
   1433  * search for the specific kstat, and if that can't
   1434  * be found search for any picN kstat belonging to this device.
   1435  */
   1436 kstat_t *
   1437 find_pic_kstat(char *dev_name, int inst_num, char *pic)
   1438 {
   1439 	kstat_t	*ksp;
   1440 	kstat_t	*p_ksp;
   1441 
   1442 	/* Look for specific picN kstat */
   1443 	if ((p_ksp = kstat_lookup(kc, dev_name, inst_num, pic)) == NULL) {
   1444 
   1445 		for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
   1446 			if ((strcmp(ksp->ks_class, "bus") == 0) &&
   1447 				(strcmp(ksp->ks_name, pic) == 0) &&
   1448 				(strcmp(ksp->ks_module, dev_name) == 0)) {
   1449 
   1450 						return (ksp);
   1451 			}
   1452 		}
   1453 	}
   1454 	return (p_ksp);
   1455 }
   1456 
   1457 
   1458 /*
   1459  * Print column titles.
   1460  * Can be turned off by -n option.
   1461  */
   1462 void
   1463 print_banner()
   1464 {
   1465 	int		i;
   1466 
   1467 	(void) printf("time dev    ");
   1468 
   1469 	for (i = 0; i < max_pic_num; i++)
   1470 		(void) printf("event%d               "
   1471 			"pic%d        ", i, i);
   1472 
   1473 	(void) printf("\n");
   1474 
   1475 	banner = FALSE;
   1476 }
   1477 
   1478 
   1479 /*
   1480  * Print the elapsed time in seconds, since the last call.
   1481  */
   1482 void
   1483 print_timestamp()
   1484 {
   1485 	static hrtime_t	curr_time = 0;
   1486 	static hrtime_t total_elapsed = 0;
   1487 	hrtime_t	new_time = 0;
   1488 	hrtime_t	elapsed = 0;
   1489 	hrtime_t	rem = 0;
   1490 
   1491 	if (initial_read)	{
   1492 		curr_time = (uint64_t)gethrtime();
   1493 		return;
   1494 	}
   1495 
   1496 	new_time = gethrtime();
   1497 
   1498 	elapsed = (new_time - curr_time)/NANO;
   1499 
   1500 	/* Round up time value if necessary */
   1501 	rem = (new_time - curr_time)%NANO;
   1502 	if (rem >= NANO/2)
   1503 		elapsed += 1;
   1504 
   1505 	total_elapsed += elapsed;
   1506 
   1507 	(void) printf("%-4llu ", total_elapsed);
   1508 
   1509 	curr_time = new_time;
   1510 }
   1511 
   1512 
   1513 void
   1514 usage()
   1515 {
   1516 	(void) printf(gettext("Usage : busstat [-a] [-h] [-l] [-n]\n"
   1517 		"                [-e device-inst]\n"
   1518 		"                [-w device-inst "
   1519 					"[,pic0=<event>] [,picN=<event>] ]\n"
   1520 		"                [-r device-inst]\n"
   1521 		"                [ interval [count] ]\n"));
   1522 
   1523 	exit(2);
   1524 }
   1525 
   1526 
   1527 void *
   1528 safe_malloc(size_t size)
   1529 {
   1530 	void *a;
   1531 
   1532 	if ((a = malloc(size)) == NULL) {
   1533 		(void) fprintf(stderr,
   1534 			gettext("%s: out of memory.\n"), pgmname);
   1535 		exit(1);
   1536 	}
   1537 
   1538 	return (a);
   1539 }
   1540 
   1541 /*
   1542  * Create and arm the timer.
   1543  */
   1544 void
   1545 set_timer(int interval)
   1546 {
   1547 	timer_t		t_id;		/* Timer id */
   1548 	itimerspec_t	time_struct;
   1549 	struct sigevent	sig_struct;
   1550 	struct sigaction act;
   1551 
   1552 	bzero(&sig_struct, sizeof (struct sigevent));
   1553 	bzero(&act, sizeof (struct sigaction));
   1554 
   1555 	/* Create timer */
   1556 	sig_struct.sigev_notify = SIGEV_SIGNAL;
   1557 	sig_struct.sigev_signo = SIGUSR1;
   1558 	sig_struct.sigev_value.sival_int = 0;
   1559 
   1560 	if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
   1561 		(void) fprintf(stderr, gettext("%s: Timer creation failed.\n"),
   1562 			pgmname);
   1563 		exit(1);
   1564 	}
   1565 
   1566 	act.sa_handler = handle_sig;
   1567 
   1568 	if (sigaction(SIGUSR1, &act, NULL) != 0) {
   1569 		(void) fprintf(stderr, gettext("%s: could not setup signal "
   1570 			"handler"), pgmname);
   1571 		exit(1);
   1572 	}
   1573 
   1574 	time_struct.it_value.tv_sec = interval;
   1575 	time_struct.it_value.tv_nsec = 0;
   1576 	time_struct.it_interval.tv_sec = interval;
   1577 	time_struct.it_interval.tv_nsec = 0;
   1578 
   1579 	/* Arm timer */
   1580 	if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
   1581 		(void) fprintf(stderr, gettext("%s: Setting timer failed.\n"),
   1582 			pgmname);
   1583 		exit(1);
   1584 	}
   1585 }
   1586 
   1587 
   1588 /* ARGSUSED */
   1589 void
   1590 handle_sig(int x)
   1591 {
   1592 }
   1593 
   1594 /*
   1595  * return a boolean value indicating whether or not
   1596  * a string consists solely of characters which are
   1597  * digits 0..9
   1598  */
   1599 int
   1600 strisnum(const char *s)
   1601 {
   1602 	for (; *s != '\0'; s++) {
   1603 		if (*s < '0' || *s > '9')
   1604 			return (0);
   1605 	}
   1606 	return (1);
   1607 }
   1608