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