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