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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <sys/types.h>
37 #include <sys/modctl.h>
38 #include <sys/systeminfo.h>
58 static int delta
= TRUE
;
59 static int banner
= TRUE
;
60 static int max_pic_num
= 1;
61 static int initial_read
= TRUE
;
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
;
70 static char curr_dev_name
[KSTAT_STRLEN
];
71 static int curr_inst_num
;
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 *);
102 main(int argc
, char **argv
)
105 int interval
= 1; /* Interval between displays */
106 int count
= 0; /* Number of times to sample */
107 int write_evts
= FALSE
;
110 #if !defined(TEXT_DOMAIN)
111 #define TEXT_DOMAIN "SYS_TEST"
115 (void) setlocale(LC_ALL
, "");
116 (void) textdomain(TEXT_DOMAIN
);
118 pgmname
= basename(argv
[0]);
120 if ((kc
= kstat_open()) == NULL
) {
121 (void) fprintf(stderr
, gettext("%s: could not "
122 "open /dev/kstat\n"), pgmname
);
126 while ((c
= getopt(argc
, argv
, "e:w:r:ahln")) != EOF
) {
138 (void) print_dev(argc
, argv
[argc
-1]);
144 (void) parse_cmd(READ_EVT
);
147 (void) parse_cmd(WRITE_EVT
);
151 (void) fprintf(stderr
, gettext("%s: invalid "
152 "option\n"), pgmname
);
158 if ((argc
== 1) || (dev_list_head
== NULL
))
162 * validate remaining operands are numeric.
166 if (strisnum(argv
[pos
]) == 0) {
167 (void) fprintf(stderr
,
168 gettext("%s: syntax error\n"),
176 if ((interval
= atoi(argv
[optind
])) == 0) {
177 (void) fprintf(stderr
, gettext("%s: invalid "
178 "interval value\n"), pgmname
);
184 if ((count
= atoi(argv
[optind
])) <= 0) {
185 (void) fprintf(stderr
, gettext("%s: "
186 "invalid iteration value.\n"),
195 * Set events for the first time.
197 if (write_evts
== TRUE
)
202 for (i
= 0; i
< count
; i
++) {
208 (void) fflush(stdout
);
218 (void) fflush(stdout
);
229 * Display all the events that can be set on a device.
236 kstat_named_t
*cnt_data
;
237 kstat_named_t
*pic_data
;
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.
254 if (((i
= strcspn(value
, "0123456789")) > 0) && (i
!= strlen(value
))) {
256 device
= safe_malloc(sizeof (char) * i
+1);
258 (void) strncpy(device
, value
, i
);
261 inst_num
= atoi(value
);
265 * No instance specified.
271 * Get the "counters" kstat, so that we can get
272 * the names of the "picN" kstats, which hold the
275 if ((cnt_ksp
= kstat_lookup(kc
, device
, inst_num
, "counters"))
277 (void) fprintf(stderr
, gettext("%s: invalid device "
278 "name or instance (%s)\n"), pgmname
, device
);
282 if (kstat_read(kc
, cnt_ksp
, NULL
) == FAIL
) {
283 (void) fprintf(stderr
, gettext("%s: could not read "
284 "kstat.\n"), pgmname
);
288 cnt_data
= (kstat_named_t
*)cnt_ksp
->ks_data
;
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[].
296 if (cnt_ksp
->ks_ndata
<= 1) {
297 (void) fprintf(stderr
, gettext("%s: invalid kstat "
298 "structure.\n"), pgmname
);
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
) {
306 (void) fprintf(stderr
, gettext("%s: could not read "
307 "pic kstat data structure for %s\n"),
308 pgmname
, cnt_ksp
->ks_module
);
313 if (kstat_read(kc
, pic_ksp
, NULL
) == FAIL
) {
314 (void) fprintf(stderr
, gettext("%s: could not read "
315 "pic kstat.\n"), pgmname
);
320 pic_data
= (kstat_named_t
*)pic_ksp
->ks_data
;
322 (void) printf(gettext("pic%-8d\n"), i
-1);
324 for (j
= 0; j
< pic_ksp
->ks_ndata
-1; j
++) {
325 (void) printf("%-30s\n", pic_data
[j
].name
);
336 * Display the names and instances of the devices on the system
337 * which can support performance monitoring.
340 print_dev(int argc
, char *str
)
343 static int first_time
= 1;
345 if ((argc
> 2) || (strcmp(str
, "-l") != 0)) {
346 (void) fprintf(stderr
, gettext("%s: no arguments "
347 "permitted with -l option.\n"),
354 * For each device node, print the node name (device
355 * name) and the instance numbers.
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)) {
361 (void) printf(gettext("Busstat "
365 (void) printf("%s%d ", ksp
->ks_module
,
371 (void) fprintf(stderr
, gettext("%s: No devices available "
372 "in system."), pgmname
);
380 * Parses the cmd line, checks all the values and
381 * creates the appropiate data structures.
386 char *options
= optarg
, *value
;
389 while ((value
= (char *)strtok(options
, ",=")) != NULL
) {
391 * First arg must be device name.
394 parse_dev_inst(value
);
396 if (mode
== READ_EVT
) {
397 (void) fprintf(stderr
, gettext("%s: "
398 "event names or pic values not "
399 "permitted with -r option.\n"),
405 * Now dealing with pic values.
407 parse_pic_evt(value
);
410 * After first strtok call, must set first arg
411 * to null if wish to parse rest of string.
412 * See strtok man page.
422 * Parse the device name/instance section of the
426 parse_dev_inst(char *value
)
430 int malloc_flag
= FALSE
;
432 if (strlen(value
) == 0) {
433 (void) fprintf(stderr
, gettext("%s: No device name given.\n"),
439 * Break string into device name and
440 * instance number (if given).
442 if ((i
= strcspn(value
, "0123456789")) > 0) {
443 if (i
!= strlen(value
)) {
444 device
= safe_malloc(sizeof (char) * i
+1);
447 (void) strncpy(device
, value
, i
);
455 * No instance was specified so we assume
456 * the user wants to use ALL instances.
458 if (device
== NULL
) {
459 if ((device
= value
) == NULL
) {
460 (void) fprintf(stderr
, gettext("%s: no device "
461 "specified\n"), pgmname
);
468 (void) strcpy(curr_dev_name
, device
);
471 add_all_dev_node(device
);
478 (void) strcpy(curr_dev_name
, device
);
479 curr_inst_num
= atoi(value
);
481 add_dev_node(device
, curr_inst_num
);
491 * Adds new event nodes to existing ones, modifies existing ones, or
492 * prunes existing ones.
494 * A specific instance call will overwrite an earlier all
495 * instances call, but *not* vice-versa.
497 * All the state transitions are given below.
501 * STATE | Specific Instance All Instances.
502 * ======================================================
503 * INIT | Change state to | Change state to ALL,
504 * | INST, add events | add events.
506 * INST | State unchanged, | No change.
509 * ALL | Change state to | State unchanged,
510 * | INST, replace events. | add events.
513 parse_pic_evt(char *value
)
515 dev_node_t
*dev_node
;
519 if (strlen(value
) <= PIC_STR_LEN
) {
520 (void) fprintf(stderr
, gettext("%s: no pic number "
521 "specified.\n"), pgmname
);
525 if (strncmp(value
, "pic", PIC_STR_LEN
) != 0) {
526 (void) fprintf(stderr
, gettext("%s: missing pic "
527 "specifier\n"), pgmname
);
532 * Step over the 'pic' part of the string to
533 * get the pic number.
535 value
= value
+ PIC_STR_LEN
;
536 pic_num
= atoi(value
);
538 if ((pic_num
== -1) || (pic_num
> max_pic_num
-1)) {
539 (void) fprintf(stderr
, gettext("%s: invalid pic "
540 "number.\n"), pgmname
);
544 if ((evt_name
= (char *)strtok(NULL
, "=,")) == NULL
) {
545 (void) fprintf(stderr
, gettext("%s: no event "
546 "specified.\n"), pgmname
);
551 * Dealing with a specific instance.
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
);
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
;
567 } else if ((dev_node
->r_w
== EVT_WRITE
) &&
568 (dev_node
->state
== STATE_ALL
)) {
570 prune_evt_nodes(dev_node
);
571 modify_evt_node(dev_node
, evt_name
);
572 dev_node
->state
= STATE_INST
;
574 } else if ((dev_node
->r_w
== EVT_WRITE
) &&
575 (dev_node
->state
== STATE_INST
)) {
577 add_evt_node(dev_node
);
578 modify_evt_node(dev_node
, evt_name
);
585 * Dealing with all instances of a specific device.
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
)) {
592 if (dev_node
->r_w
== EVT_READ
) {
593 modify_evt_node(dev_node
,
596 dev_node
->r_w
= EVT_WRITE
;
597 dev_node
->state
= STATE_ALL
;
599 } else if ((dev_node
->r_w
== EVT_WRITE
) &&
600 (dev_node
->state
== STATE_ALL
)) {
602 add_evt_node(dev_node
);
603 modify_evt_node(dev_node
, evt_name
);
607 dev_node
= dev_node
->next
;
613 * Create a dev_node structure for this device if one does not
617 add_dev_node(char *dev_name
, int inst_num
)
619 dev_node_t
*new_dev_node
;
620 kstat_named_t
*cnt_data
;
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
,
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
);
640 cnt_data
= (kstat_named_t
*)cnt_ksp
->ks_data
;
642 if (cnt_ksp
->ks_ndata
<= 1) {
643 (void) fprintf(stderr
, gettext("%s : invalid "
644 "kstat structure.\n"), pgmname
);
649 * max_pic_num used to format headers correctly
652 if (cnt_ksp
->ks_ndata
-1 > max_pic_num
)
653 max_pic_num
= cnt_ksp
->ks_ndata
-1;
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 */
662 new_dev_node
= safe_malloc(sizeof (dev_node_t
));
663 bzero(new_dev_node
, sizeof (dev_node_t
));
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
;
669 new_dev_node
->cnt_ksp
= cnt_ksp
;
671 if ((pic_ksp
= find_pic_kstat(dev_name
, inst_num
,
672 cnt_data
[pic_num
+1].name
)) == NULL
) {
674 (void) fprintf(stderr
, gettext("%s: could not find "
675 "pic kstat structure for %s.\n"),
676 pgmname
, cnt_ksp
->ks_module
);
680 new_dev_node
->pic_ksp
= pic_ksp
;
682 add_evt_node(new_dev_node
);
684 new_dev_node
->state
= STATE_INIT
;
685 new_dev_node
->r_w
= EVT_READ
;
687 if (dev_list_head
== NULL
) {
688 dev_list_head
= new_dev_node
;
689 dev_list_tail
= new_dev_node
;
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
;
700 * Add all possible instances of a device.
703 add_all_dev_node(char *dev_name
)
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)) {
713 add_dev_node(dev_name
, ksp
->ks_instance
);
718 (void) fprintf(stderr
,
719 gettext("%s: invalid device name (%s)\n"),
727 * Add an event node to a specified device node.
730 add_evt_node(dev_node_t
*dev_node
)
732 evt_node_t
*new_evt_node
;
733 evt_node_t
*curr_evt_node
;
735 new_evt_node
= safe_malloc(sizeof (evt_node_t
));
736 bzero(new_evt_node
, sizeof (evt_node_t
));
738 (void) strcpy(new_evt_node
->evt_name
, "");
740 if (dev_node
->evt_node
== NULL
) {
741 dev_node
->evt_node
= new_evt_node
;
742 new_evt_node
->next
= new_evt_node
;
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
;
749 curr_evt_node
->next
= new_evt_node
;
750 new_evt_node
->next
= dev_node
->evt_node
;
756 * Fill in or change the fields of an evt node.
759 modify_evt_node(dev_node_t
*dev_node
, char *evt_name
)
761 evt_node_t
*evt_node
;
763 kstat_named_t
*pic_data
;
768 evt_node
= dev_node
->evt_node
;
771 * Find the last event node.
773 if (evt_node
->next
!= evt_node
) {
774 while (evt_node
->next
!= dev_node
->evt_node
) {
775 evt_node
= evt_node
->next
;
779 evt_node
->prev_count
= 0;
782 pic_ksp
= dev_node
->pic_ksp
;
784 if (kstat_read(kc
, pic_ksp
, NULL
) == FAIL
) {
785 (void) fprintf(stderr
, gettext("%s: could not read "
786 "pic kstat.\n"), pgmname
);
790 pic_data
= (kstat_named_t
*)dev_node
->pic_ksp
->ks_data
;
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.
798 if ((evt_num
= is_num(evt_name
)) == EVT_STR
) {
799 (void) strcpy(evt_node
->evt_name
, evt_name
);
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
;
808 (void) fprintf(stderr
,
809 gettext("%s: %s is not a valid event name.\n"),
815 * See if the pcr mask given by the user matches that for any
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
,
828 (void) sprintf(evt_node
->evt_name
, "%llx", evt_num
);
830 evt_node
->evt_pcr_mask
= evt_num
;
836 * Removes all bar one of the evt_nodes that are hanging off the
837 * specified dev_node.
840 prune_evt_nodes(dev_node_t
*dev_node
)
842 evt_node_t
*next_evt_node
;
843 evt_node_t
*curr_evt_node
;
846 * Only one evt node, nothing for us to do.
848 if (dev_node
->evt_node
->next
== dev_node
->evt_node
) {
852 curr_evt_node
= dev_node
->evt_node
->next
;
853 dev_node
->evt_node
->next
= dev_node
->evt_node
;
855 while (curr_evt_node
!= dev_node
->evt_node
) {
856 next_evt_node
= curr_evt_node
->next
;
858 curr_evt_node
= next_evt_node
;
864 * Set the events for each pic on each device instance.
869 dev_node_t
*dev_node
;
871 dev_node
= dev_list_head
;
873 while (dev_node
!= NULL
) {
874 if (dev_node
->r_w
== EVT_WRITE
)
877 dev_node
= dev_node
->next
;
883 * Set the appropiate events. Only called for event nodes
884 * that are marked EVT_WRITE.
887 set_evt(dev_node_t
*dev_node
)
889 kstat_named_t
*cnt_data
;
890 kstat_named_t
*pic_data
;
893 evt_node_t
*evt_node
;
894 uint64_t clear_pcr_mask
;
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
;
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
);
910 cnt_data
= (kstat_named_t
*)cnt_ksp
->ks_data
;
912 if (kstat_read(kc
, pic_ksp
, NULL
) == FAIL
) {
913 (void) fprintf(stderr
, gettext("%s: could "
914 "not set event's.\n"), pgmname
);
918 pic_data
= (kstat_named_t
*)pic_ksp
->ks_data
;
919 clear_pcr_mask
= pic_data
[pic_ksp
->ks_ndata
-1].value
.ui64
;
921 if ((pic_num
< 0) || (pic_num
> cnt_ksp
->ks_ndata
-1)) {
922 (void) fprintf(stderr
,
923 gettext("%s: invalid pic #%d.\n"),
929 * Store the previous value that is on the pic
930 * so that we can calculate the delta value
933 evt_node
->prev_count
= cnt_data
[pic_num
+1].value
.ui64
;
937 * Read the current pcr value from device.
939 pcr
= cnt_data
[0].value
.ui64
;
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.
947 pcr
= pcr
& clear_pcr_mask
;
952 pcr
= pcr
| evt_node
->evt_pcr_mask
;
953 cnt_data
[0].value
.ui64
= pcr
;
956 * Write the value back to the kstat, to make it
957 * visible to the underlying driver.
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
);
969 * Works through the list of device nodes, reading events
970 * and where appropiate setting new events (multiplexing).
975 dev_node_t
*dev_node
;
977 kstat_named_t
*cnt_data
;
981 dev_node
= dev_list_head
;
983 while (dev_node
!= NULL
) {
987 * First read of all the counters is done
988 * to establish a baseline for the counts.
989 * This data is not printed.
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
);
997 cnt_ksp
= (kstat_t
*)dev_node
->cnt_ksp
;
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
,
1005 remove_dev_node(dev_node
);
1006 dev_node
= dev_list_head
;
1010 cnt_data
= (kstat_named_t
*)cnt_ksp
->ks_data
;
1012 if (dev_node
->r_w
== EVT_READ
) {
1013 read_r_evt_node(dev_node
, dev_node
->pic_num
, cnt_data
);
1016 read_w_evt_node(dev_node
, dev_node
->pic_num
, cnt_data
);
1020 if ((!initial_read
) && (iter
== max_pic_num
)) {
1022 (void) printf("\n");
1026 * If there is more than one event node
1027 * per-pic then we are multiplexing.
1029 if ((dev_node
->evt_node
->next
!= dev_node
->evt_node
) &&
1031 dev_node
->evt_node
= dev_node
->evt_node
->next
;
1034 dev_node
= dev_node
->next
;
1036 initial_read
= FALSE
;
1041 * Read a node that is marked as EVT_READ
1044 read_r_evt_node(dev_node_t
*dev_node
, int pic_num
, kstat_named_t
*cnt_data
)
1046 evt_node_t
*evt_node
;
1048 kstat_named_t
*pic_data
;
1050 uint64_t clear_pcr_mask
;
1051 uint64_t delta_count
;
1056 evt_node
= dev_node
->evt_node
;
1058 pic_ksp
= (kstat_t
*)dev_node
->pic_ksp
;
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
,
1065 remove_dev_node(dev_node
);
1069 pic_data
= (kstat_named_t
*)pic_ksp
->ks_data
;
1070 clear_pcr_mask
= pic_data
[pic_ksp
->ks_ndata
-1].value
.ui64
;
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.
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.
1082 pcr_read
= cnt_data
[0].value
.ui64
;
1083 pcr_read
= pcr_read
& ~(clear_pcr_mask
);
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.
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
1095 if ((strcmp(evt_node
->evt_name
, "") == 0) ||
1096 (pcr_read
!= evt_node
->evt_pcr_mask
)) {
1098 for (i
= 0; i
< pic_ksp
->ks_ndata
-1; i
++) {
1099 if (pcr_read
== pic_data
[i
].value
.ui64
) {
1106 * Able to resolve pcr value to a event name.
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
;
1115 if ((evt_blank
) && (!initial_read
)) {
1116 (void) printf("%s\t%-8d\t",
1117 evt_node
->evt_name
, 0);
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
;
1128 if ((evt_blank
) && (!initial_read
)) {
1129 (void) printf("%s\t%-8d\t",
1130 evt_node
->evt_name
, 0);
1136 /* Deal with wraparound of the counters */
1137 if (cnt_data
[pic_num
+1].value
.ui64
< evt_node
->prev_count
) {
1139 delta_count
= (UINT32_MAX
-evt_node
->prev_count
) +
1140 cnt_data
[pic_num
+1].value
.ui64
;
1142 /* Calcalate delta value */
1143 delta_count
= cnt_data
[pic_num
+1].value
.ui64
1144 - evt_node
->prev_count
;
1149 * Store value so that we can calculate delta next
1152 evt_node
->prev_count
= cnt_data
[pic_num
+1].value
.ui64
;
1154 /* Update count total */
1155 evt_node
->total
+= delta_count
;
1158 (void) printf("%-20s %-9lld ",
1159 evt_node
->evt_name
, delta_count
);
1162 (void) printf("%-20s %-9lld ",
1163 evt_node
->evt_name
, evt_node
->total
);
1170 * Read event nodes marked as EVT_WRITE
1173 read_w_evt_node(dev_node_t
*dev_node
, int pic_num
, kstat_named_t
*cnt_data
)
1176 kstat_named_t
*pic_data
;
1177 evt_node_t
*evt_node
;
1178 uint64_t delta_count
;
1180 uint64_t clear_pcr_mask
;
1182 evt_node
= dev_node
->evt_node
;
1184 pic_ksp
= (kstat_t
*)dev_node
->pic_ksp
;
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
);
1194 pic_data
= (kstat_named_t
*)pic_ksp
->ks_data
;
1195 clear_pcr_mask
= pic_data
[pic_ksp
->ks_ndata
-1].value
.ui64
;
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.
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.
1207 pcr_read
= cnt_data
[0].value
.ui64
;
1208 pcr_read
= pcr_read
& ~(clear_pcr_mask
);
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.
1215 * Regard this as a fatal error.
1217 if (pcr_read
!= evt_node
->evt_pcr_mask
) {
1218 (void) fprintf(stderr
, gettext("%s: events changed (possibly "
1219 "by another busstat).\n"), pgmname
);
1224 * Calculate delta, and then store value just read to allow us to
1225 * calculate delta next time around.
1227 /* Deal with wraparound of the counters */
1228 if (cnt_data
[pic_num
+1].value
.ui64
< evt_node
->prev_count
) {
1230 delta_count
= (UINT32_MAX
-evt_node
->prev_count
) +
1231 cnt_data
[pic_num
+1].value
.ui64
;
1233 /* Calcalate delta value */
1234 delta_count
= cnt_data
[pic_num
+1].value
.ui64
1235 - evt_node
->prev_count
;
1238 evt_node
->prev_count
= cnt_data
[pic_num
+1].value
.ui64
;
1241 evt_node
->total
= 0;
1244 /* Update count total */
1245 evt_node
->total
+= delta_count
;
1248 (void) printf("%-20s %-9lld ",
1249 evt_node
->evt_name
, delta_count
);
1251 (void) printf("%-20s %-9lld ",
1252 evt_node
->evt_name
, evt_node
->total
);
1259 * Check to see if any DR operations have occured, and deal with the
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.
1270 dev_node_t
*dev_node
;
1275 if ((new_id
= kstat_chain_update(kc
)) < 0) {
1276 (void) fprintf(stderr
, gettext("%s: could not get "
1277 "kstat chain id\n"), pgmname
);
1282 /* Kstat chain has not changed. */
1287 * Scan the chain of device nodes, making sure that their associated
1288 * kstats are still present. If not we remove the appropiate node.
1290 dev_node
= dev_list_head
;
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
)) {
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
,
1308 remove_dev_node(dev_node
);
1310 dev_node
= dev_node
->next
;
1317 * Remove a device node and its associated event nodes.
1320 remove_dev_node(dev_node_t
*dev_node
)
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
;
1328 curr_node
= dev_list_head
;
1330 if (curr_node
== dev_node
) {
1331 dev_list_head
= dev_node
->next
;
1333 if (dev_list_head
== NULL
) {
1334 (void) fprintf(stderr
, gettext("%s: no "
1335 "devices left to monitor.\n"),
1340 /* Remove each event node first */
1341 start_pos
= dev_node
->evt_node
;
1342 curr_evt_node
= start_pos
->next
;
1344 while (curr_evt_node
!= start_pos
) {
1345 next_evt_node
= curr_evt_node
->next
;
1347 free(curr_evt_node
);
1348 curr_evt_node
= next_evt_node
;
1356 /* Find the device node */
1357 prev_node
= dev_list_head
;
1358 curr_node
= prev_node
->next
;
1360 while (curr_node
!= NULL
) {
1361 if (curr_node
== dev_node
) {
1362 prev_node
->next
= curr_node
->next
;
1364 /* Remove each event node first */
1365 start_pos
= dev_node
->evt_node
;
1366 curr_evt_node
= start_pos
->next
;
1368 while (curr_evt_node
!= start_pos
) {
1369 next_evt_node
= curr_evt_node
->next
;
1371 free(curr_evt_node
);
1372 curr_evt_node
= next_evt_node
;
1379 prev_node
= curr_node
;
1380 curr_node
= curr_node
->next
;
1386 * Find a device node in the linked list of dev_nodes. Match
1387 * is done on device name, and instance number.
1390 find_dev_node(char *name
, int inst_num
, int pic_num
)
1392 dev_node_t
*curr_node
;
1394 curr_node
= dev_list_head
;
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
)) {
1403 curr_node
= curr_node
->next
;
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.
1418 char *remainder
= NULL
;
1421 num
= (int64_t)strtol(name
, &remainder
, 0);
1423 if (name
== remainder
) {
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.
1437 find_pic_kstat(char *dev_name
, int inst_num
, char *pic
)
1442 /* Look for specific picN kstat */
1443 if ((p_ksp
= kstat_lookup(kc
, dev_name
, inst_num
, pic
)) == NULL
) {
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)) {
1459 * Print column titles.
1460 * Can be turned off by -n option.
1467 (void) printf("time dev ");
1469 for (i
= 0; i
< max_pic_num
; i
++)
1470 (void) printf("event%d "
1473 (void) printf("\n");
1480 * Print the elapsed time in seconds, since the last call.
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;
1492 curr_time
= (uint64_t)gethrtime();
1496 new_time
= gethrtime();
1498 elapsed
= (new_time
- curr_time
)/NANO
;
1500 /* Round up time value if necessary */
1501 rem
= (new_time
- curr_time
)%NANO
;
1505 total_elapsed
+= elapsed
;
1507 (void) printf("%-4llu ", total_elapsed
);
1509 curr_time
= new_time
;
1516 (void) printf(gettext("Usage : busstat [-a] [-h] [-l] [-n]\n"
1517 " [-e device-inst]\n"
1519 "[,pic0=<event>] [,picN=<event>] ]\n"
1520 " [-r device-inst]\n"
1521 " [ interval [count] ]\n"));
1528 safe_malloc(size_t size
)
1532 if ((a
= malloc(size
)) == NULL
) {
1533 (void) fprintf(stderr
,
1534 gettext("%s: out of memory.\n"), pgmname
);
1542 * Create and arm the timer.
1545 set_timer(int interval
)
1547 timer_t t_id
; /* Timer id */
1548 itimerspec_t time_struct
;
1549 struct sigevent sig_struct
;
1550 struct sigaction act
;
1552 bzero(&sig_struct
, sizeof (struct sigevent
));
1553 bzero(&act
, sizeof (struct sigaction
));
1556 sig_struct
.sigev_notify
= SIGEV_SIGNAL
;
1557 sig_struct
.sigev_signo
= SIGUSR1
;
1558 sig_struct
.sigev_value
.sival_int
= 0;
1560 if (timer_create(CLOCK_REALTIME
, &sig_struct
, &t_id
) != 0) {
1561 (void) fprintf(stderr
, gettext("%s: Timer creation failed.\n"),
1566 act
.sa_handler
= handle_sig
;
1568 if (sigaction(SIGUSR1
, &act
, NULL
) != 0) {
1569 (void) fprintf(stderr
, gettext("%s: could not setup signal "
1570 "handler"), pgmname
);
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;
1580 if ((timer_settime(t_id
, 0, &time_struct
, NULL
)) != 0) {
1581 (void) fprintf(stderr
, gettext("%s: Setting timer failed.\n"),
1595 * return a boolean value indicating whether or not
1596 * a string consists solely of characters which are
1600 strisnum(const char *s
)
1602 for (; *s
!= '\0'; s
++) {
1603 if (*s
< '0' || *s
> '9')