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 }