17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
27*bc54f855SJohn Levon /*
28*bc54f855SJohn Levon * Copyright (c) 2018, Joyent, Inc.
29*bc54f855SJohn Levon */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <strings.h>
347c478bd9Sstevel@tonic-gate #include <time.h>
357c478bd9Sstevel@tonic-gate #include <signal.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <sys/time.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
417c478bd9Sstevel@tonic-gate #include <limits.h>
427c478bd9Sstevel@tonic-gate #include <signal.h>
437c478bd9Sstevel@tonic-gate #include <fcntl.h>
447c478bd9Sstevel@tonic-gate #include <unistd.h>
457c478bd9Sstevel@tonic-gate #include <stropts.h>
467c478bd9Sstevel@tonic-gate #include <locale.h>
477c478bd9Sstevel@tonic-gate #include <libintl.h>
487c478bd9Sstevel@tonic-gate #include <libgen.h>
497c478bd9Sstevel@tonic-gate #include <nl_types.h>
507c478bd9Sstevel@tonic-gate #include <kstat.h>
517c478bd9Sstevel@tonic-gate #include <ctype.h>
527c478bd9Sstevel@tonic-gate #include <signal.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <time.h>
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate #include "busstat.h"
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /* Global defines */
607c478bd9Sstevel@tonic-gate static int delta = TRUE;
617c478bd9Sstevel@tonic-gate static int banner = TRUE;
627c478bd9Sstevel@tonic-gate static int max_pic_num = 1;
637c478bd9Sstevel@tonic-gate static int initial_read = TRUE;
647c478bd9Sstevel@tonic-gate static char *pgmname;
657c478bd9Sstevel@tonic-gate static kstat_ctl_t *kc; /* libkstat cookie */
667c478bd9Sstevel@tonic-gate static dev_node_t *dev_list_head = NULL;
677c478bd9Sstevel@tonic-gate static dev_node_t *dev_list_tail = NULL;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate * Global flags.
717c478bd9Sstevel@tonic-gate */
727c478bd9Sstevel@tonic-gate static char curr_dev_name[KSTAT_STRLEN];
737c478bd9Sstevel@tonic-gate static int curr_inst_num;
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate static void print_evt(void);
767c478bd9Sstevel@tonic-gate static void print_dev(int, char *);
777c478bd9Sstevel@tonic-gate static void parse_cmd(int);
787c478bd9Sstevel@tonic-gate static void parse_dev_inst(char *);
797c478bd9Sstevel@tonic-gate static void parse_pic_evt(char *);
807c478bd9Sstevel@tonic-gate static void add_dev_node(char *, int);
817c478bd9Sstevel@tonic-gate static void add_all_dev_node(char *);
827c478bd9Sstevel@tonic-gate static void add_evt_node(dev_node_t *);
837c478bd9Sstevel@tonic-gate static void modify_evt_node(dev_node_t *, char *);
847c478bd9Sstevel@tonic-gate static void prune_evt_nodes(dev_node_t *);
857c478bd9Sstevel@tonic-gate static void setup_evts(void);
867c478bd9Sstevel@tonic-gate static void set_evt(dev_node_t *);
877c478bd9Sstevel@tonic-gate static void read_evts(void);
887c478bd9Sstevel@tonic-gate static void read_r_evt_node(dev_node_t *, int, kstat_named_t *);
897c478bd9Sstevel@tonic-gate static void read_w_evt_node(dev_node_t *, int, kstat_named_t *);
907c478bd9Sstevel@tonic-gate static void check_dr_ops(void);
917c478bd9Sstevel@tonic-gate static void remove_dev_node(dev_node_t *);
927c478bd9Sstevel@tonic-gate static dev_node_t *find_dev_node(char *, int, int);
937c478bd9Sstevel@tonic-gate static kstat_t *find_pic_kstat(char *, int, char *);
947c478bd9Sstevel@tonic-gate static int64_t is_num(char *);
957c478bd9Sstevel@tonic-gate static void print_banner(void);
967c478bd9Sstevel@tonic-gate static void print_timestamp(void);
977c478bd9Sstevel@tonic-gate static void usage(void);
987c478bd9Sstevel@tonic-gate static void *safe_malloc(size_t);
997c478bd9Sstevel@tonic-gate static void set_timer(int);
1007c478bd9Sstevel@tonic-gate static void handle_sig(int);
1017c478bd9Sstevel@tonic-gate static int strisnum(const char *);
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1047c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate int c, i;
1077c478bd9Sstevel@tonic-gate int interval = 1; /* Interval between displays */
1087c478bd9Sstevel@tonic-gate int count = 0; /* Number of times to sample */
1097c478bd9Sstevel@tonic-gate int write_evts = FALSE;
1107c478bd9Sstevel@tonic-gate int pos = 0;
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1137c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
1147c478bd9Sstevel@tonic-gate #endif
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /* For I18N */
1177c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1187c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate pgmname = basename(argv[0]);
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) {
1237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not "
1247c478bd9Sstevel@tonic-gate "open /dev/kstat\n"), pgmname);
1257c478bd9Sstevel@tonic-gate exit(1);
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "e:w:r:ahln")) != EOF) {
1297c478bd9Sstevel@tonic-gate switch (c) {
1307c478bd9Sstevel@tonic-gate case 'a':
1317c478bd9Sstevel@tonic-gate delta = FALSE;
1327c478bd9Sstevel@tonic-gate break;
1337c478bd9Sstevel@tonic-gate case 'e':
1347c478bd9Sstevel@tonic-gate (void) print_evt();
1357c478bd9Sstevel@tonic-gate break;
1367c478bd9Sstevel@tonic-gate case 'h':
1377c478bd9Sstevel@tonic-gate usage();
1387c478bd9Sstevel@tonic-gate break;
1397c478bd9Sstevel@tonic-gate case 'l':
1407c478bd9Sstevel@tonic-gate (void) print_dev(argc, argv[argc-1]);
1417c478bd9Sstevel@tonic-gate break;
1427c478bd9Sstevel@tonic-gate case 'n':
1437c478bd9Sstevel@tonic-gate banner = FALSE;
1447c478bd9Sstevel@tonic-gate break;
1457c478bd9Sstevel@tonic-gate case 'r':
1467c478bd9Sstevel@tonic-gate (void) parse_cmd(READ_EVT);
1477c478bd9Sstevel@tonic-gate break;
1487c478bd9Sstevel@tonic-gate case 'w':
1497c478bd9Sstevel@tonic-gate (void) parse_cmd(WRITE_EVT);
1507c478bd9Sstevel@tonic-gate write_evts = TRUE;
1517c478bd9Sstevel@tonic-gate break;
1527c478bd9Sstevel@tonic-gate default:
1537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid "
1547c478bd9Sstevel@tonic-gate "option\n"), pgmname);
1557c478bd9Sstevel@tonic-gate usage();
1567c478bd9Sstevel@tonic-gate break;
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate if ((argc == 1) || (dev_list_head == NULL))
1617c478bd9Sstevel@tonic-gate usage();
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * validate remaining operands are numeric.
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate pos = optind;
1677c478bd9Sstevel@tonic-gate while (pos < argc) {
1687c478bd9Sstevel@tonic-gate if (strisnum(argv[pos]) == 0) {
1697c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
1707c478bd9Sstevel@tonic-gate gettext("%s: syntax error\n"),
1717c478bd9Sstevel@tonic-gate pgmname);
1727c478bd9Sstevel@tonic-gate usage();
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate pos++;
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate if (optind < argc) {
1787c478bd9Sstevel@tonic-gate if ((interval = atoi(argv[optind])) == 0) {
1797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid "
1807c478bd9Sstevel@tonic-gate "interval value\n"), pgmname);
1817c478bd9Sstevel@tonic-gate exit(1);
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate optind++;
1857c478bd9Sstevel@tonic-gate if (optind < argc)
1867c478bd9Sstevel@tonic-gate if ((count = atoi(argv[optind])) <= 0) {
1877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: "
1887c478bd9Sstevel@tonic-gate "invalid iteration value.\n"),
1897c478bd9Sstevel@tonic-gate pgmname);
1907c478bd9Sstevel@tonic-gate exit(1);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate set_timer(interval);
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate * Set events for the first time.
1987c478bd9Sstevel@tonic-gate */
1997c478bd9Sstevel@tonic-gate if (write_evts == TRUE)
2007c478bd9Sstevel@tonic-gate setup_evts();
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate if (count > 0) {
2047c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++) {
2057c478bd9Sstevel@tonic-gate if (banner)
2067c478bd9Sstevel@tonic-gate print_banner();
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate check_dr_ops();
2097c478bd9Sstevel@tonic-gate read_evts();
2107c478bd9Sstevel@tonic-gate (void) fflush(stdout);
2117c478bd9Sstevel@tonic-gate (void) pause();
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate } else {
2147c478bd9Sstevel@tonic-gate for (;;) {
2157c478bd9Sstevel@tonic-gate if (banner)
2167c478bd9Sstevel@tonic-gate print_banner();
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate check_dr_ops();
2197c478bd9Sstevel@tonic-gate read_evts();
2207c478bd9Sstevel@tonic-gate (void) fflush(stdout);
2217c478bd9Sstevel@tonic-gate (void) pause();
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate read_evts();
2267c478bd9Sstevel@tonic-gate return (0);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate * Display all the events that can be set on a device.
2327c478bd9Sstevel@tonic-gate */
2337c478bd9Sstevel@tonic-gate void
print_evt()2347c478bd9Sstevel@tonic-gate print_evt()
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate kstat_t *cnt_ksp;
2377c478bd9Sstevel@tonic-gate kstat_t *pic_ksp;
2387c478bd9Sstevel@tonic-gate kstat_named_t *cnt_data;
2397c478bd9Sstevel@tonic-gate kstat_named_t *pic_data;
2407c478bd9Sstevel@tonic-gate char *device = NULL;
2417c478bd9Sstevel@tonic-gate char *value;
2427c478bd9Sstevel@tonic-gate int inst_num = -1;
2437c478bd9Sstevel@tonic-gate int i = 0;
2447c478bd9Sstevel@tonic-gate int j;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate value = optarg;
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate * Search through the value string for a numeric char which will
2507c478bd9Sstevel@tonic-gate * be the device instance number, if the user specified one. If
2517c478bd9Sstevel@tonic-gate * the user did not specify an instance then the return value from
2527c478bd9Sstevel@tonic-gate * strscpn will be equal to the string length. In this case we
2537c478bd9Sstevel@tonic-gate * use a default value of -1 for the kstat_lookup which causes
2547c478bd9Sstevel@tonic-gate * the device number to be ignored during the search.
2557c478bd9Sstevel@tonic-gate */
2567c478bd9Sstevel@tonic-gate if (((i = strcspn(value, "0123456789")) > 0) && (i != strlen(value))) {
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate device = safe_malloc(sizeof (char) * i+1);
2597c478bd9Sstevel@tonic-gate device[i] = '\0';
2607c478bd9Sstevel@tonic-gate (void) strncpy(device, value, i);
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate value = value + i;
2637c478bd9Sstevel@tonic-gate inst_num = atoi(value);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * No instance specified.
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate if (device == NULL)
2707c478bd9Sstevel@tonic-gate device = value;
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate /*
2737c478bd9Sstevel@tonic-gate * Get the "counters" kstat, so that we can get
2747c478bd9Sstevel@tonic-gate * the names of the "picN" kstats, which hold the
2757c478bd9Sstevel@tonic-gate * event names.
2767c478bd9Sstevel@tonic-gate */
2777c478bd9Sstevel@tonic-gate if ((cnt_ksp = kstat_lookup(kc, device, inst_num, "counters"))
2787c478bd9Sstevel@tonic-gate == NULL) {
2797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid device "
2807c478bd9Sstevel@tonic-gate "name or instance (%s)\n"), pgmname, device);
2817c478bd9Sstevel@tonic-gate exit(1);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
2857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not read "
2867c478bd9Sstevel@tonic-gate "kstat.\n"), pgmname);
2877c478bd9Sstevel@tonic-gate exit(1);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate * Start at 1 as the first entry in the "counters"
2947c478bd9Sstevel@tonic-gate * kstat is the pcr value/name. We are looking for the
2957c478bd9Sstevel@tonic-gate * name of the "picN" kstats. For each one found store
2967c478bd9Sstevel@tonic-gate * a pointer to it in pic_data[].
2977c478bd9Sstevel@tonic-gate */
2987c478bd9Sstevel@tonic-gate if (cnt_ksp->ks_ndata <= 1) {
2997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid kstat "
3007c478bd9Sstevel@tonic-gate "structure.\n"), pgmname);
3017c478bd9Sstevel@tonic-gate exit(1);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate for (i = 1; i < cnt_ksp->ks_ndata; i++) {
3057c478bd9Sstevel@tonic-gate if ((pic_ksp = find_pic_kstat(device, inst_num,
3067c478bd9Sstevel@tonic-gate cnt_data[i].name)) == NULL) {
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not read "
3097c478bd9Sstevel@tonic-gate "pic kstat data structure for %s\n"),
3107c478bd9Sstevel@tonic-gate pgmname, cnt_ksp->ks_module);
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate exit(1);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
3167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not read "
3177c478bd9Sstevel@tonic-gate "pic kstat.\n"), pgmname);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate exit(1);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate pic_data = (kstat_named_t *)pic_ksp->ks_data;
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate (void) printf(gettext("pic%-8d\n"), i-1);
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate for (j = 0; j < pic_ksp->ks_ndata-1; j++) {
3277c478bd9Sstevel@tonic-gate (void) printf("%-30s\n", pic_data[j].name);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate (void) printf("\n");
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate exit(0);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate * Display the names and instances of the devices on the system
3397c478bd9Sstevel@tonic-gate * which can support performance monitoring.
3407c478bd9Sstevel@tonic-gate */
3417c478bd9Sstevel@tonic-gate void
print_dev(int argc,char * str)3427c478bd9Sstevel@tonic-gate print_dev(int argc, char *str)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate kstat_t *ksp;
3457c478bd9Sstevel@tonic-gate static int first_time = 1;
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate if ((argc > 2) || (strcmp(str, "-l") != 0)) {
3487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: no arguments "
3497c478bd9Sstevel@tonic-gate "permitted with -l option.\n"),
3507c478bd9Sstevel@tonic-gate pgmname);
3517c478bd9Sstevel@tonic-gate usage();
3527c478bd9Sstevel@tonic-gate exit(1);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate * For each device node, print the node name (device
3577c478bd9Sstevel@tonic-gate * name) and the instance numbers.
3587c478bd9Sstevel@tonic-gate */
3597c478bd9Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
3607c478bd9Sstevel@tonic-gate if ((strcmp(ksp->ks_class, "bus") == 0) &&
3617c478bd9Sstevel@tonic-gate (strcmp(ksp->ks_name, "counters") == 0)) {
3627c478bd9Sstevel@tonic-gate if (first_time) {
3637c478bd9Sstevel@tonic-gate (void) printf(gettext("Busstat "
3647c478bd9Sstevel@tonic-gate "Device(s):\n"));
3657c478bd9Sstevel@tonic-gate first_time = 0;
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate (void) printf("%s%d ", ksp->ks_module,
3687c478bd9Sstevel@tonic-gate ksp->ks_instance);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate if (first_time)
3737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: No devices available "
3747c478bd9Sstevel@tonic-gate "in system."), pgmname);
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate (void) printf("\n");
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate exit(0);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate * Parses the cmd line, checks all the values and
3837c478bd9Sstevel@tonic-gate * creates the appropiate data structures.
3847c478bd9Sstevel@tonic-gate */
3857c478bd9Sstevel@tonic-gate void
parse_cmd(int mode)3867c478bd9Sstevel@tonic-gate parse_cmd(int mode)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate char *options = optarg, *value;
3897c478bd9Sstevel@tonic-gate int arg_num = 0;
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate while ((value = (char *)strtok(options, ",=")) != NULL) {
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate * First arg must be device name.
3947c478bd9Sstevel@tonic-gate */
3957c478bd9Sstevel@tonic-gate if (!arg_num) {
3967c478bd9Sstevel@tonic-gate parse_dev_inst(value);
3977c478bd9Sstevel@tonic-gate } else {
3987c478bd9Sstevel@tonic-gate if (mode == READ_EVT) {
3997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: "
4007c478bd9Sstevel@tonic-gate "event names or pic values not "
4017c478bd9Sstevel@tonic-gate "permitted with -r option.\n"),
4027c478bd9Sstevel@tonic-gate pgmname);
403*bc54f855SJohn Levon usage();
4047c478bd9Sstevel@tonic-gate exit(1);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate * Now dealing with pic values.
4087c478bd9Sstevel@tonic-gate */
4097c478bd9Sstevel@tonic-gate parse_pic_evt(value);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate * After first strtok call, must set first arg
4137c478bd9Sstevel@tonic-gate * to null if wish to parse rest of string.
4147c478bd9Sstevel@tonic-gate * See strtok man page.
4157c478bd9Sstevel@tonic-gate */
4167c478bd9Sstevel@tonic-gate if (options != NULL)
4177c478bd9Sstevel@tonic-gate options = NULL;
4187c478bd9Sstevel@tonic-gate arg_num++;
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate * Parse the device name/instance section of the
4257c478bd9Sstevel@tonic-gate * command line.
4267c478bd9Sstevel@tonic-gate */
4277c478bd9Sstevel@tonic-gate void
parse_dev_inst(char * value)4287c478bd9Sstevel@tonic-gate parse_dev_inst(char *value)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate int i;
4317c478bd9Sstevel@tonic-gate char *device = NULL;
4327c478bd9Sstevel@tonic-gate int malloc_flag = FALSE;
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate if (strlen(value) == 0) {
4357c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: No device name given.\n"),
4367c478bd9Sstevel@tonic-gate pgmname);
4377c478bd9Sstevel@tonic-gate exit(1);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate * Break string into device name and
4427c478bd9Sstevel@tonic-gate * instance number (if given).
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate if ((i = strcspn(value, "0123456789")) > 0) {
4457c478bd9Sstevel@tonic-gate if (i != strlen(value)) {
4467c478bd9Sstevel@tonic-gate device = safe_malloc(sizeof (char) * i+1);
4477c478bd9Sstevel@tonic-gate device[i] = '\0';
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate (void) strncpy(device, value, i);
4507c478bd9Sstevel@tonic-gate malloc_flag = TRUE;
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate value = value + i;
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate * No instance was specified so we assume
4587c478bd9Sstevel@tonic-gate * the user wants to use ALL instances.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate if (device == NULL) {
4617c478bd9Sstevel@tonic-gate if ((device = value) == NULL) {
4627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: no device "
4637c478bd9Sstevel@tonic-gate "specified\n"), pgmname);
4647c478bd9Sstevel@tonic-gate exit(1);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate * Set global flags.
4697c478bd9Sstevel@tonic-gate */
4707c478bd9Sstevel@tonic-gate (void) strcpy(curr_dev_name, device);
4717c478bd9Sstevel@tonic-gate curr_inst_num = -1;
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate add_all_dev_node(device);
4747c478bd9Sstevel@tonic-gate goto clean_up;
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate * Set global flags.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate (void) strcpy(curr_dev_name, device);
4817c478bd9Sstevel@tonic-gate curr_inst_num = atoi(value);
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate add_dev_node(device, curr_inst_num);
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate clean_up:
4867c478bd9Sstevel@tonic-gate if (malloc_flag) {
4877c478bd9Sstevel@tonic-gate free(device);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate * Adds new event nodes to existing ones, modifies existing ones, or
4947c478bd9Sstevel@tonic-gate * prunes existing ones.
4957c478bd9Sstevel@tonic-gate *
4967c478bd9Sstevel@tonic-gate * A specific instance call will overwrite an earlier all
4977c478bd9Sstevel@tonic-gate * instances call, but *not* vice-versa.
4987c478bd9Sstevel@tonic-gate *
4997c478bd9Sstevel@tonic-gate * All the state transitions are given below.
5007c478bd9Sstevel@tonic-gate *
5017c478bd9Sstevel@tonic-gate *
5027c478bd9Sstevel@tonic-gate * Call Type
5037c478bd9Sstevel@tonic-gate * STATE | Specific Instance All Instances.
5047c478bd9Sstevel@tonic-gate * ======================================================
5057c478bd9Sstevel@tonic-gate * INIT | Change state to | Change state to ALL,
5067c478bd9Sstevel@tonic-gate * | INST, add events | add events.
5077c478bd9Sstevel@tonic-gate * | |
5087c478bd9Sstevel@tonic-gate * INST | State unchanged, | No change.
5097c478bd9Sstevel@tonic-gate * | Add events. |
5107c478bd9Sstevel@tonic-gate * | |
5117c478bd9Sstevel@tonic-gate * ALL | Change state to | State unchanged,
5127c478bd9Sstevel@tonic-gate * | INST, replace events. | add events.
5137c478bd9Sstevel@tonic-gate */
5147c478bd9Sstevel@tonic-gate void
parse_pic_evt(char * value)5157c478bd9Sstevel@tonic-gate parse_pic_evt(char *value)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate dev_node_t *dev_node;
5187c478bd9Sstevel@tonic-gate char *evt_name;
5197c478bd9Sstevel@tonic-gate int pic_num;
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate if (strlen(value) <= PIC_STR_LEN) {
5227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: no pic number "
5237c478bd9Sstevel@tonic-gate "specified.\n"), pgmname);
5247c478bd9Sstevel@tonic-gate exit(1);
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate if (strncmp(value, "pic", PIC_STR_LEN) != 0) {
5287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: missing pic "
5297c478bd9Sstevel@tonic-gate "specifier\n"), pgmname);
5307c478bd9Sstevel@tonic-gate usage();
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate * Step over the 'pic' part of the string to
5357c478bd9Sstevel@tonic-gate * get the pic number.
5367c478bd9Sstevel@tonic-gate */
5377c478bd9Sstevel@tonic-gate value = value + PIC_STR_LEN;
5387c478bd9Sstevel@tonic-gate pic_num = atoi(value);
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate if ((pic_num == -1) || (pic_num > max_pic_num -1)) {
5417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid pic "
5427c478bd9Sstevel@tonic-gate "number.\n"), pgmname);
5437c478bd9Sstevel@tonic-gate exit(1);
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate if ((evt_name = (char *)strtok(NULL, "=,")) == NULL) {
5477c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: no event "
5487c478bd9Sstevel@tonic-gate "specified.\n"), pgmname);
5497c478bd9Sstevel@tonic-gate exit(1);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate * Dealing with a specific instance.
5547c478bd9Sstevel@tonic-gate */
5557c478bd9Sstevel@tonic-gate if (curr_inst_num >= 0) {
5567c478bd9Sstevel@tonic-gate if ((dev_node = find_dev_node(curr_dev_name,
5577c478bd9Sstevel@tonic-gate curr_inst_num, pic_num)) == NULL) {
5587c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not find "
5597c478bd9Sstevel@tonic-gate "data structures for %s\n"),
5607c478bd9Sstevel@tonic-gate pgmname, curr_dev_name);
5617c478bd9Sstevel@tonic-gate exit(1);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate if (dev_node->r_w == EVT_READ) {
5657c478bd9Sstevel@tonic-gate modify_evt_node(dev_node, evt_name);
5667c478bd9Sstevel@tonic-gate dev_node->r_w = EVT_WRITE;
5677c478bd9Sstevel@tonic-gate dev_node->state = STATE_INST;
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate } else if ((dev_node->r_w == EVT_WRITE) &&
5707c478bd9Sstevel@tonic-gate (dev_node->state == STATE_ALL)) {
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate prune_evt_nodes(dev_node);
5737c478bd9Sstevel@tonic-gate modify_evt_node(dev_node, evt_name);
5747c478bd9Sstevel@tonic-gate dev_node->state = STATE_INST;
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate } else if ((dev_node->r_w == EVT_WRITE) &&
5777c478bd9Sstevel@tonic-gate (dev_node->state == STATE_INST)) {
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate add_evt_node(dev_node);
5807c478bd9Sstevel@tonic-gate modify_evt_node(dev_node, evt_name);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate return;
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate * Dealing with all instances of a specific device.
5887c478bd9Sstevel@tonic-gate */
5897c478bd9Sstevel@tonic-gate dev_node = dev_list_head;
5907c478bd9Sstevel@tonic-gate while (dev_node != NULL) {
5917c478bd9Sstevel@tonic-gate if ((strcmp(dev_node->name, curr_dev_name) == 0) &&
5927c478bd9Sstevel@tonic-gate (dev_node->pic_num == pic_num)) {
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if (dev_node->r_w == EVT_READ) {
5957c478bd9Sstevel@tonic-gate modify_evt_node(dev_node,
5967c478bd9Sstevel@tonic-gate evt_name);
5977c478bd9Sstevel@tonic-gate
5987c478bd9Sstevel@tonic-gate dev_node->r_w = EVT_WRITE;
5997c478bd9Sstevel@tonic-gate dev_node->state = STATE_ALL;
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate } else if ((dev_node->r_w == EVT_WRITE) &&
6027c478bd9Sstevel@tonic-gate (dev_node->state == STATE_ALL)) {
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate add_evt_node(dev_node);
6057c478bd9Sstevel@tonic-gate modify_evt_node(dev_node, evt_name);
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate dev_node = dev_node->next;
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate * Create a dev_node structure for this device if one does not
6167c478bd9Sstevel@tonic-gate * already exist.
6177c478bd9Sstevel@tonic-gate */
6187c478bd9Sstevel@tonic-gate void
add_dev_node(char * dev_name,int inst_num)6197c478bd9Sstevel@tonic-gate add_dev_node(char *dev_name, int inst_num)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate dev_node_t *new_dev_node;
6227c478bd9Sstevel@tonic-gate kstat_named_t *cnt_data;
6237c478bd9Sstevel@tonic-gate kstat_t *cnt_ksp;
6247c478bd9Sstevel@tonic-gate kstat_t *pic_ksp;
6257c478bd9Sstevel@tonic-gate int pic_num;
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate if ((cnt_ksp = kstat_lookup(kc, dev_name,
6297c478bd9Sstevel@tonic-gate inst_num, "counters")) == NULL) {
6307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid device "
6317c478bd9Sstevel@tonic-gate "name or instance (%s%d)\n"), pgmname,
6327c478bd9Sstevel@tonic-gate dev_name, inst_num);
6337c478bd9Sstevel@tonic-gate exit(1);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
6377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s : could not read counters "
6387c478bd9Sstevel@tonic-gate "kstat for device %s.\n"), pgmname, dev_name);
6397c478bd9Sstevel@tonic-gate exit(1);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate if (cnt_ksp->ks_ndata <= 1) {
6457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s : invalid "
6467c478bd9Sstevel@tonic-gate "kstat structure.\n"), pgmname);
6477c478bd9Sstevel@tonic-gate exit(1);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate /*
6517c478bd9Sstevel@tonic-gate * max_pic_num used to format headers correctly
6527c478bd9Sstevel@tonic-gate * for printing.
6537c478bd9Sstevel@tonic-gate */
6547c478bd9Sstevel@tonic-gate if (cnt_ksp->ks_ndata-1 > max_pic_num)
6557c478bd9Sstevel@tonic-gate max_pic_num = cnt_ksp->ks_ndata-1;
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate /* for each pic... */
6587c478bd9Sstevel@tonic-gate for (pic_num = 0; pic_num < cnt_ksp->ks_ndata-1; pic_num++) {
6597c478bd9Sstevel@tonic-gate if (find_dev_node(dev_name, inst_num, pic_num) != NULL) {
6607c478bd9Sstevel@tonic-gate /* Node already exists */
6617c478bd9Sstevel@tonic-gate continue;
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate new_dev_node = safe_malloc(sizeof (dev_node_t));
6657c478bd9Sstevel@tonic-gate bzero(new_dev_node, sizeof (dev_node_t));
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate (void) strcpy(new_dev_node->name, dev_name);
6687c478bd9Sstevel@tonic-gate new_dev_node->dev_inst = inst_num;
6697c478bd9Sstevel@tonic-gate new_dev_node->pic_num = pic_num;
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate new_dev_node->cnt_ksp = cnt_ksp;
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate if ((pic_ksp = find_pic_kstat(dev_name, inst_num,
6747c478bd9Sstevel@tonic-gate cnt_data[pic_num+1].name)) == NULL) {
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not find "
6777c478bd9Sstevel@tonic-gate "pic kstat structure for %s.\n"),
6787c478bd9Sstevel@tonic-gate pgmname, cnt_ksp->ks_module);
6797c478bd9Sstevel@tonic-gate exit(1);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate
6827c478bd9Sstevel@tonic-gate new_dev_node->pic_ksp = pic_ksp;
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate add_evt_node(new_dev_node);
6857c478bd9Sstevel@tonic-gate
6867c478bd9Sstevel@tonic-gate new_dev_node->state = STATE_INIT;
6877c478bd9Sstevel@tonic-gate new_dev_node->r_w = EVT_READ;
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate if (dev_list_head == NULL) {
6907c478bd9Sstevel@tonic-gate dev_list_head = new_dev_node;
6917c478bd9Sstevel@tonic-gate dev_list_tail = new_dev_node;
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate } else if (find_dev_node(dev_name, inst_num, pic_num) == NULL) {
6947c478bd9Sstevel@tonic-gate dev_list_tail->next = new_dev_node;
6957c478bd9Sstevel@tonic-gate dev_list_tail = new_dev_node;
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate * Add all possible instances of a device.
7037c478bd9Sstevel@tonic-gate */
7047c478bd9Sstevel@tonic-gate void
add_all_dev_node(char * dev_name)7057c478bd9Sstevel@tonic-gate add_all_dev_node(char *dev_name)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate kstat_t *ksp;
7087c478bd9Sstevel@tonic-gate int match = 0;
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
7117c478bd9Sstevel@tonic-gate if ((strcmp(ksp->ks_class, "bus") == 0) &&
7127c478bd9Sstevel@tonic-gate (strcmp(ksp->ks_name, "counters") == 0) &&
7137c478bd9Sstevel@tonic-gate (strcmp(ksp->ks_module, dev_name) == 0)) {
7147c478bd9Sstevel@tonic-gate match = 1;
7157c478bd9Sstevel@tonic-gate add_dev_node(dev_name, ksp->ks_instance);
7167c478bd9Sstevel@tonic-gate }
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate if (match == 0) {
7207c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7217c478bd9Sstevel@tonic-gate gettext("%s: invalid device name (%s)\n"),
7227c478bd9Sstevel@tonic-gate pgmname, dev_name);
7237c478bd9Sstevel@tonic-gate exit(1);
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate * Add an event node to a specified device node.
7307c478bd9Sstevel@tonic-gate */
7317c478bd9Sstevel@tonic-gate void
add_evt_node(dev_node_t * dev_node)7327c478bd9Sstevel@tonic-gate add_evt_node(dev_node_t *dev_node)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate evt_node_t *new_evt_node;
7357c478bd9Sstevel@tonic-gate evt_node_t *curr_evt_node;
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate new_evt_node = safe_malloc(sizeof (evt_node_t));
7387c478bd9Sstevel@tonic-gate bzero(new_evt_node, sizeof (evt_node_t));
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate (void) strcpy(new_evt_node->evt_name, "");
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gate if (dev_node->evt_node == NULL) {
7437c478bd9Sstevel@tonic-gate dev_node->evt_node = new_evt_node;
7447c478bd9Sstevel@tonic-gate new_evt_node->next = new_evt_node;
7457c478bd9Sstevel@tonic-gate return;
7467c478bd9Sstevel@tonic-gate } else {
7477c478bd9Sstevel@tonic-gate curr_evt_node = dev_node->evt_node;
7487c478bd9Sstevel@tonic-gate while (curr_evt_node->next != dev_node->evt_node)
7497c478bd9Sstevel@tonic-gate curr_evt_node = curr_evt_node->next;
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate curr_evt_node->next = new_evt_node;
7527c478bd9Sstevel@tonic-gate new_evt_node->next = dev_node->evt_node;
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate * Fill in or change the fields of an evt node.
7597c478bd9Sstevel@tonic-gate */
7607c478bd9Sstevel@tonic-gate void
modify_evt_node(dev_node_t * dev_node,char * evt_name)7617c478bd9Sstevel@tonic-gate modify_evt_node(dev_node_t *dev_node, char *evt_name)
7627c478bd9Sstevel@tonic-gate {
7637c478bd9Sstevel@tonic-gate evt_node_t *evt_node;
7647c478bd9Sstevel@tonic-gate kstat_t *pic_ksp;
7657c478bd9Sstevel@tonic-gate kstat_named_t *pic_data;
7667c478bd9Sstevel@tonic-gate int64_t evt_num = 0;
7677c478bd9Sstevel@tonic-gate int evt_match = 0;
7687c478bd9Sstevel@tonic-gate int i;
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate evt_node = dev_node->evt_node;
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate * Find the last event node.
7747c478bd9Sstevel@tonic-gate */
7757c478bd9Sstevel@tonic-gate if (evt_node->next != evt_node) {
7767c478bd9Sstevel@tonic-gate while (evt_node->next != dev_node->evt_node) {
7777c478bd9Sstevel@tonic-gate evt_node = evt_node->next;
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate evt_node->prev_count = 0;
7827c478bd9Sstevel@tonic-gate evt_node->total = 0;
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate pic_ksp = dev_node->pic_ksp;
7857c478bd9Sstevel@tonic-gate
7867c478bd9Sstevel@tonic-gate if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
7877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not read "
7887c478bd9Sstevel@tonic-gate "pic kstat.\n"), pgmname);
7897c478bd9Sstevel@tonic-gate exit(1);
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate pic_data = (kstat_named_t *)dev_node->pic_ksp->ks_data;
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate /*
7957c478bd9Sstevel@tonic-gate * The event can either be given as a event name (string) or
7967c478bd9Sstevel@tonic-gate * as a pcr mask. If given as pcr mask, we try to match it
7977c478bd9Sstevel@tonic-gate * to an event name, and use that name. Otherwise we just use
7987c478bd9Sstevel@tonic-gate * the pcr mask value.
7997c478bd9Sstevel@tonic-gate */
8007c478bd9Sstevel@tonic-gate if ((evt_num = is_num(evt_name)) == EVT_STR) {
8017c478bd9Sstevel@tonic-gate (void) strcpy(evt_node->evt_name, evt_name);
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
8047c478bd9Sstevel@tonic-gate if (strcmp(evt_name, pic_data[i].name) == 0) {
8057c478bd9Sstevel@tonic-gate evt_node->evt_pcr_mask = pic_data[i].value.ui64;
8067c478bd9Sstevel@tonic-gate return;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
8117c478bd9Sstevel@tonic-gate gettext("%s: %s is not a valid event name.\n"),
8127c478bd9Sstevel@tonic-gate pgmname, evt_name);
8137c478bd9Sstevel@tonic-gate exit(1);
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate } else {
8167c478bd9Sstevel@tonic-gate /*
8177c478bd9Sstevel@tonic-gate * See if the pcr mask given by the user matches that for any
8187c478bd9Sstevel@tonic-gate * existing event.
8197c478bd9Sstevel@tonic-gate */
8207c478bd9Sstevel@tonic-gate for (i = 0; i < dev_node->pic_ksp->ks_ndata; i++) {
8217c478bd9Sstevel@tonic-gate if (evt_num == pic_data[i].value.ui64) {
8227c478bd9Sstevel@tonic-gate (void) strcpy(evt_node->evt_name,
8237c478bd9Sstevel@tonic-gate pic_data[i].name);
8247c478bd9Sstevel@tonic-gate evt_match = 1;
8257c478bd9Sstevel@tonic-gate break;
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate if (evt_match == 0)
8307c478bd9Sstevel@tonic-gate (void) sprintf(evt_node->evt_name, "%llx", evt_num);
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate evt_node->evt_pcr_mask = evt_num;
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate * Removes all bar one of the evt_nodes that are hanging off the
8397c478bd9Sstevel@tonic-gate * specified dev_node.
8407c478bd9Sstevel@tonic-gate */
8417c478bd9Sstevel@tonic-gate void
prune_evt_nodes(dev_node_t * dev_node)8427c478bd9Sstevel@tonic-gate prune_evt_nodes(dev_node_t *dev_node)
8437c478bd9Sstevel@tonic-gate {
8447c478bd9Sstevel@tonic-gate evt_node_t *next_evt_node;
8457c478bd9Sstevel@tonic-gate evt_node_t *curr_evt_node;
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate /*
8487c478bd9Sstevel@tonic-gate * Only one evt node, nothing for us to do.
8497c478bd9Sstevel@tonic-gate */
8507c478bd9Sstevel@tonic-gate if (dev_node->evt_node->next == dev_node->evt_node) {
8517c478bd9Sstevel@tonic-gate return;
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate curr_evt_node = dev_node->evt_node->next;
8557c478bd9Sstevel@tonic-gate dev_node->evt_node->next = dev_node->evt_node;
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate while (curr_evt_node != dev_node->evt_node) {
8587c478bd9Sstevel@tonic-gate next_evt_node = curr_evt_node->next;
8597c478bd9Sstevel@tonic-gate free(curr_evt_node);
8607c478bd9Sstevel@tonic-gate curr_evt_node = next_evt_node;
8617c478bd9Sstevel@tonic-gate }
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate * Set the events for each pic on each device instance.
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate void
setup_evts()8697c478bd9Sstevel@tonic-gate setup_evts()
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate dev_node_t *dev_node;
8727c478bd9Sstevel@tonic-gate
8737c478bd9Sstevel@tonic-gate dev_node = dev_list_head;
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate while (dev_node != NULL) {
8767c478bd9Sstevel@tonic-gate if (dev_node->r_w == EVT_WRITE)
8777c478bd9Sstevel@tonic-gate set_evt(dev_node);
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate dev_node = dev_node->next;
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate /*
8857c478bd9Sstevel@tonic-gate * Set the appropiate events. Only called for event nodes
8867c478bd9Sstevel@tonic-gate * that are marked EVT_WRITE.
8877c478bd9Sstevel@tonic-gate */
8887c478bd9Sstevel@tonic-gate void
set_evt(dev_node_t * dev_node)8897c478bd9Sstevel@tonic-gate set_evt(dev_node_t *dev_node)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate kstat_named_t *cnt_data;
8927c478bd9Sstevel@tonic-gate kstat_named_t *pic_data;
8937c478bd9Sstevel@tonic-gate kstat_t *cnt_ksp;
8947c478bd9Sstevel@tonic-gate kstat_t *pic_ksp;
8957c478bd9Sstevel@tonic-gate evt_node_t *evt_node;
8967c478bd9Sstevel@tonic-gate uint64_t clear_pcr_mask;
8977c478bd9Sstevel@tonic-gate uint64_t pcr;
8987c478bd9Sstevel@tonic-gate int pic_num;
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate cnt_ksp = dev_node->cnt_ksp;
9017c478bd9Sstevel@tonic-gate pic_ksp = dev_node->pic_ksp;
9027c478bd9Sstevel@tonic-gate pic_num = dev_node->pic_num;
9037c478bd9Sstevel@tonic-gate evt_node = dev_node->evt_node;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate /* Read the "counters" kstat */
9067c478bd9Sstevel@tonic-gate if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
9077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could "
9087c478bd9Sstevel@tonic-gate "not set event's.\n"), pgmname);
9097c478bd9Sstevel@tonic-gate exit(1);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
9137c478bd9Sstevel@tonic-gate
9147c478bd9Sstevel@tonic-gate if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
9157c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could "
9167c478bd9Sstevel@tonic-gate "not set event's.\n"), pgmname);
9177c478bd9Sstevel@tonic-gate exit(1);
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate pic_data = (kstat_named_t *)pic_ksp->ks_data;
9217c478bd9Sstevel@tonic-gate clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate if ((pic_num < 0) || (pic_num > cnt_ksp->ks_ndata-1)) {
9247c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
9257c478bd9Sstevel@tonic-gate gettext("%s: invalid pic #%d.\n"),
9267c478bd9Sstevel@tonic-gate pgmname, pic_num);
9277c478bd9Sstevel@tonic-gate exit(1);
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate * Store the previous value that is on the pic
9327c478bd9Sstevel@tonic-gate * so that we can calculate the delta value
9337c478bd9Sstevel@tonic-gate * later.
9347c478bd9Sstevel@tonic-gate */
9357c478bd9Sstevel@tonic-gate evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
9367c478bd9Sstevel@tonic-gate
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate /*
9397c478bd9Sstevel@tonic-gate * Read the current pcr value from device.
9407c478bd9Sstevel@tonic-gate */
9417c478bd9Sstevel@tonic-gate pcr = cnt_data[0].value.ui64;
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate * Clear the section of the pcr which corresponds to the
9457c478bd9Sstevel@tonic-gate * pic we are setting events on. Also clear the pcr value
9467c478bd9Sstevel@tonic-gate * which is stored in the instance node.
9477c478bd9Sstevel@tonic-gate *
9487c478bd9Sstevel@tonic-gate */
9497c478bd9Sstevel@tonic-gate pcr = pcr & clear_pcr_mask;
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate /*
9527c478bd9Sstevel@tonic-gate * Set the event.
9537c478bd9Sstevel@tonic-gate */
9547c478bd9Sstevel@tonic-gate pcr = pcr | evt_node->evt_pcr_mask;
9557c478bd9Sstevel@tonic-gate cnt_data[0].value.ui64 = pcr;
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate /*
9587c478bd9Sstevel@tonic-gate * Write the value back to the kstat, to make it
9597c478bd9Sstevel@tonic-gate * visible to the underlying driver.
9607c478bd9Sstevel@tonic-gate */
9617c478bd9Sstevel@tonic-gate if (kstat_write(kc, cnt_ksp, NULL) == FAIL) {
9627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not set events "
9637c478bd9Sstevel@tonic-gate "(setting events requires root "
9647c478bd9Sstevel@tonic-gate "permission).\n"), pgmname);
9657c478bd9Sstevel@tonic-gate exit(1);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate * Works through the list of device nodes, reading events
9727c478bd9Sstevel@tonic-gate * and where appropiate setting new events (multiplexing).
9737c478bd9Sstevel@tonic-gate */
9747c478bd9Sstevel@tonic-gate void
read_evts()9757c478bd9Sstevel@tonic-gate read_evts()
9767c478bd9Sstevel@tonic-gate {
9777c478bd9Sstevel@tonic-gate dev_node_t *dev_node;
9787c478bd9Sstevel@tonic-gate kstat_t *cnt_ksp;
9797c478bd9Sstevel@tonic-gate kstat_named_t *cnt_data;
9807c478bd9Sstevel@tonic-gate char tmp_str[30];
9817c478bd9Sstevel@tonic-gate int iter = 0;
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate dev_node = dev_list_head;
9847c478bd9Sstevel@tonic-gate
9857c478bd9Sstevel@tonic-gate while (dev_node != NULL) {
9867c478bd9Sstevel@tonic-gate if (iter == 0)
9877c478bd9Sstevel@tonic-gate print_timestamp();
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate * First read of all the counters is done
9907c478bd9Sstevel@tonic-gate * to establish a baseline for the counts.
9917c478bd9Sstevel@tonic-gate * This data is not printed.
9927c478bd9Sstevel@tonic-gate */
9937c478bd9Sstevel@tonic-gate if ((!initial_read) && (iter == 0)) {
9947c478bd9Sstevel@tonic-gate (void) snprintf(tmp_str, sizeof (tmp_str), "%s%d",
9957c478bd9Sstevel@tonic-gate dev_node->name, dev_node->dev_inst);
9967c478bd9Sstevel@tonic-gate (void) printf("%-7s", tmp_str);
9977c478bd9Sstevel@tonic-gate }
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate cnt_ksp = (kstat_t *)dev_node->cnt_ksp;
10007c478bd9Sstevel@tonic-gate
10017c478bd9Sstevel@tonic-gate if (kstat_read(kc, cnt_ksp, NULL) == FAIL) {
10027c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: device %s%d "
10037c478bd9Sstevel@tonic-gate "(pic %d) no longer valid.\n"),
10047c478bd9Sstevel@tonic-gate pgmname, dev_node->name,
10057c478bd9Sstevel@tonic-gate dev_node->dev_inst,
10067c478bd9Sstevel@tonic-gate dev_node->pic_num);
10077c478bd9Sstevel@tonic-gate remove_dev_node(dev_node);
10087c478bd9Sstevel@tonic-gate dev_node = dev_list_head;
10097c478bd9Sstevel@tonic-gate continue;
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate cnt_data = (kstat_named_t *)cnt_ksp->ks_data;
10137c478bd9Sstevel@tonic-gate
10147c478bd9Sstevel@tonic-gate if (dev_node->r_w == EVT_READ) {
10157c478bd9Sstevel@tonic-gate read_r_evt_node(dev_node, dev_node->pic_num, cnt_data);
10167c478bd9Sstevel@tonic-gate iter++;
10177c478bd9Sstevel@tonic-gate } else {
10187c478bd9Sstevel@tonic-gate read_w_evt_node(dev_node, dev_node->pic_num, cnt_data);
10197c478bd9Sstevel@tonic-gate iter++;
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate if ((!initial_read) && (iter == max_pic_num)) {
10237c478bd9Sstevel@tonic-gate iter = 0;
10247c478bd9Sstevel@tonic-gate (void) printf("\n");
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate /*
10287c478bd9Sstevel@tonic-gate * If there is more than one event node
10297c478bd9Sstevel@tonic-gate * per-pic then we are multiplexing.
10307c478bd9Sstevel@tonic-gate */
10317c478bd9Sstevel@tonic-gate if ((dev_node->evt_node->next != dev_node->evt_node) &&
10327c478bd9Sstevel@tonic-gate (!initial_read)) {
10337c478bd9Sstevel@tonic-gate dev_node->evt_node = dev_node->evt_node->next;
10347c478bd9Sstevel@tonic-gate set_evt(dev_node);
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate dev_node = dev_node->next;
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate initial_read = FALSE;
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate /*
10437c478bd9Sstevel@tonic-gate * Read a node that is marked as EVT_READ
10447c478bd9Sstevel@tonic-gate */
10457c478bd9Sstevel@tonic-gate void
read_r_evt_node(dev_node_t * dev_node,int pic_num,kstat_named_t * cnt_data)10467c478bd9Sstevel@tonic-gate read_r_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
10477c478bd9Sstevel@tonic-gate {
10487c478bd9Sstevel@tonic-gate evt_node_t *evt_node;
10497c478bd9Sstevel@tonic-gate kstat_t *pic_ksp;
10507c478bd9Sstevel@tonic-gate kstat_named_t *pic_data;
10517c478bd9Sstevel@tonic-gate uint64_t pcr_read;
10527c478bd9Sstevel@tonic-gate uint64_t clear_pcr_mask;
10537c478bd9Sstevel@tonic-gate uint64_t delta_count;
10547c478bd9Sstevel@tonic-gate int i;
10557c478bd9Sstevel@tonic-gate int match = 0;
10567c478bd9Sstevel@tonic-gate int evt_blank = 1;
10577c478bd9Sstevel@tonic-gate
10587c478bd9Sstevel@tonic-gate evt_node = dev_node->evt_node;
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate pic_ksp = (kstat_t *)dev_node->pic_ksp;
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
10637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: device %s%d "
10647c478bd9Sstevel@tonic-gate "(pic %d) no longer valid.\n"), pgmname,
10657c478bd9Sstevel@tonic-gate dev_node->name, dev_node->dev_inst,
10667c478bd9Sstevel@tonic-gate dev_node->pic_num);
10677c478bd9Sstevel@tonic-gate remove_dev_node(dev_node);
10687c478bd9Sstevel@tonic-gate return;
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate pic_data = (kstat_named_t *)pic_ksp->ks_data;
10727c478bd9Sstevel@tonic-gate clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate /*
10757c478bd9Sstevel@tonic-gate * Get PCR value from device. We extract the portion
10767c478bd9Sstevel@tonic-gate * of the PCR relating to the pic we are interested by
10777c478bd9Sstevel@tonic-gate * AND'ing the inverse of the clear mask for this pic.
10787c478bd9Sstevel@tonic-gate *
10797c478bd9Sstevel@tonic-gate * The clear mask is usually used to clear the appropiate
10807c478bd9Sstevel@tonic-gate * section of the PCR before we write events into it. So
10817c478bd9Sstevel@tonic-gate * by using the inverse of the mask, we zero everything
10827c478bd9Sstevel@tonic-gate * *but* the section we are interested in.
10837c478bd9Sstevel@tonic-gate */
10847c478bd9Sstevel@tonic-gate pcr_read = cnt_data[0].value.ui64;
10857c478bd9Sstevel@tonic-gate pcr_read = pcr_read & ~(clear_pcr_mask);
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate * If the event name is blank this is the first time that
10897c478bd9Sstevel@tonic-gate * this node has been accessed, so we read the pcr and
10907c478bd9Sstevel@tonic-gate * from that we get the event name if it exists.
10917c478bd9Sstevel@tonic-gate *
10927c478bd9Sstevel@tonic-gate * If the pcr read from the device does not match that
10937c478bd9Sstevel@tonic-gate * stored in the node, then it means that the event has
10947c478bd9Sstevel@tonic-gate * changed from its previous value, so we need to re-read
10957c478bd9Sstevel@tonic-gate * all the values.
10967c478bd9Sstevel@tonic-gate */
10977c478bd9Sstevel@tonic-gate if ((strcmp(evt_node->evt_name, "") == 0) ||
10987c478bd9Sstevel@tonic-gate (pcr_read != evt_node->evt_pcr_mask)) {
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate for (i = 0; i < pic_ksp->ks_ndata-1; i++) {
11017c478bd9Sstevel@tonic-gate if (pcr_read == pic_data[i].value.ui64) {
11027c478bd9Sstevel@tonic-gate match = TRUE;
11037c478bd9Sstevel@tonic-gate break;
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate
11077c478bd9Sstevel@tonic-gate /*
11087c478bd9Sstevel@tonic-gate * Able to resolve pcr value to a event name.
11097c478bd9Sstevel@tonic-gate */
11107c478bd9Sstevel@tonic-gate if (match) {
11117c478bd9Sstevel@tonic-gate (void) strcpy(evt_node->evt_name, pic_data[i].name);
11127c478bd9Sstevel@tonic-gate evt_node->evt_pcr_mask = pcr_read;
11137c478bd9Sstevel@tonic-gate evt_node->total = 0;
11147c478bd9Sstevel@tonic-gate evt_node->prev_count =
11157c478bd9Sstevel@tonic-gate cnt_data[pic_num+1].value.ui64;
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate if ((evt_blank) && (!initial_read)) {
11187c478bd9Sstevel@tonic-gate (void) printf("%s\t%-8d\t",
11197c478bd9Sstevel@tonic-gate evt_node->evt_name, 0);
11207c478bd9Sstevel@tonic-gate evt_blank = 0;
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate } else {
11247c478bd9Sstevel@tonic-gate (void) sprintf(evt_node->evt_name, "0x%llx", pcr_read);
11257c478bd9Sstevel@tonic-gate evt_node->evt_pcr_mask = pcr_read;
11267c478bd9Sstevel@tonic-gate evt_node->total = 0;
11277c478bd9Sstevel@tonic-gate evt_node->prev_count =
11287c478bd9Sstevel@tonic-gate cnt_data[pic_num+1].value.ui64;
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate if ((evt_blank) && (!initial_read)) {
11317c478bd9Sstevel@tonic-gate (void) printf("%s\t%-8d\t",
11327c478bd9Sstevel@tonic-gate evt_node->evt_name, 0);
11337c478bd9Sstevel@tonic-gate evt_blank = 0;
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate } else {
11387c478bd9Sstevel@tonic-gate /* Deal with wraparound of the counters */
11397c478bd9Sstevel@tonic-gate if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
11407c478bd9Sstevel@tonic-gate
11417c478bd9Sstevel@tonic-gate delta_count = (UINT32_MAX-evt_node->prev_count) +
11427c478bd9Sstevel@tonic-gate cnt_data[pic_num+1].value.ui64;
11437c478bd9Sstevel@tonic-gate } else {
11447c478bd9Sstevel@tonic-gate /* Calcalate delta value */
11457c478bd9Sstevel@tonic-gate delta_count = cnt_data[pic_num+1].value.ui64
11467c478bd9Sstevel@tonic-gate - evt_node->prev_count;
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate /*
11517c478bd9Sstevel@tonic-gate * Store value so that we can calculate delta next
11527c478bd9Sstevel@tonic-gate * time through.
11537c478bd9Sstevel@tonic-gate */
11547c478bd9Sstevel@tonic-gate evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
11557c478bd9Sstevel@tonic-gate
11567c478bd9Sstevel@tonic-gate /* Update count total */
11577c478bd9Sstevel@tonic-gate evt_node->total += delta_count;
11587c478bd9Sstevel@tonic-gate
11597c478bd9Sstevel@tonic-gate if (delta) {
11607c478bd9Sstevel@tonic-gate (void) printf("%-20s %-9lld ",
11617c478bd9Sstevel@tonic-gate evt_node->evt_name, delta_count);
11627c478bd9Sstevel@tonic-gate } else {
11637c478bd9Sstevel@tonic-gate
11647c478bd9Sstevel@tonic-gate (void) printf("%-20s %-9lld ",
11657c478bd9Sstevel@tonic-gate evt_node->evt_name, evt_node->total);
11667c478bd9Sstevel@tonic-gate }
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate /*
11727c478bd9Sstevel@tonic-gate * Read event nodes marked as EVT_WRITE
11737c478bd9Sstevel@tonic-gate */
11747c478bd9Sstevel@tonic-gate void
read_w_evt_node(dev_node_t * dev_node,int pic_num,kstat_named_t * cnt_data)11757c478bd9Sstevel@tonic-gate read_w_evt_node(dev_node_t *dev_node, int pic_num, kstat_named_t *cnt_data)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate kstat_t *pic_ksp;
11787c478bd9Sstevel@tonic-gate kstat_named_t *pic_data;
11797c478bd9Sstevel@tonic-gate evt_node_t *evt_node;
11807c478bd9Sstevel@tonic-gate uint64_t delta_count;
11817c478bd9Sstevel@tonic-gate uint64_t pcr_read;
11827c478bd9Sstevel@tonic-gate uint64_t clear_pcr_mask;
11837c478bd9Sstevel@tonic-gate
11847c478bd9Sstevel@tonic-gate evt_node = dev_node->evt_node;
11857c478bd9Sstevel@tonic-gate
11867c478bd9Sstevel@tonic-gate pic_ksp = (kstat_t *)dev_node->pic_ksp;
11877c478bd9Sstevel@tonic-gate
11887c478bd9Sstevel@tonic-gate if (kstat_read(kc, pic_ksp, NULL) == FAIL) {
11897c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not read "
11907c478bd9Sstevel@tonic-gate "%s%d\n"), pgmname, dev_node->name,
11917c478bd9Sstevel@tonic-gate dev_node->dev_inst);
11927c478bd9Sstevel@tonic-gate remove_dev_node(dev_node);
11937c478bd9Sstevel@tonic-gate return;
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate
11967c478bd9Sstevel@tonic-gate pic_data = (kstat_named_t *)pic_ksp->ks_data;
11977c478bd9Sstevel@tonic-gate clear_pcr_mask = pic_data[pic_ksp->ks_ndata-1].value.ui64;
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate /*
12007c478bd9Sstevel@tonic-gate * Get PCR value from device. We extract the portion
12017c478bd9Sstevel@tonic-gate * of the PCR relating to the pic we are interested by
12027c478bd9Sstevel@tonic-gate * AND'ing the inverse of the clear mask for this pic.
12037c478bd9Sstevel@tonic-gate *
12047c478bd9Sstevel@tonic-gate * The clear mask is usually used to clear the appropiate
12057c478bd9Sstevel@tonic-gate * section of the PCR before we write events into it. So
12067c478bd9Sstevel@tonic-gate * by using the inverse of the mask, we zero everything
12077c478bd9Sstevel@tonic-gate * *but* the section we are interested in.
12087c478bd9Sstevel@tonic-gate */
12097c478bd9Sstevel@tonic-gate pcr_read = cnt_data[0].value.ui64;
12107c478bd9Sstevel@tonic-gate pcr_read = pcr_read & ~(clear_pcr_mask);
12117c478bd9Sstevel@tonic-gate
12127c478bd9Sstevel@tonic-gate /*
12137c478bd9Sstevel@tonic-gate * If the pcr value from the device does not match the
12147c478bd9Sstevel@tonic-gate * stored value, then the events on at least one of the
12157c478bd9Sstevel@tonic-gate * pics must have been change by another busstat instance.
12167c478bd9Sstevel@tonic-gate *
12177c478bd9Sstevel@tonic-gate * Regard this as a fatal error.
12187c478bd9Sstevel@tonic-gate */
12197c478bd9Sstevel@tonic-gate if (pcr_read != evt_node->evt_pcr_mask) {
12207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: events changed (possibly "
12217c478bd9Sstevel@tonic-gate "by another busstat).\n"), pgmname);
12227c478bd9Sstevel@tonic-gate exit(2);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate /*
12267c478bd9Sstevel@tonic-gate * Calculate delta, and then store value just read to allow us to
12277c478bd9Sstevel@tonic-gate * calculate delta next time around.
12287c478bd9Sstevel@tonic-gate */
12297c478bd9Sstevel@tonic-gate /* Deal with wraparound of the counters */
12307c478bd9Sstevel@tonic-gate if (cnt_data[pic_num+1].value.ui64 < evt_node->prev_count) {
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate delta_count = (UINT32_MAX-evt_node->prev_count) +
12337c478bd9Sstevel@tonic-gate cnt_data[pic_num+1].value.ui64;
12347c478bd9Sstevel@tonic-gate } else {
12357c478bd9Sstevel@tonic-gate /* Calcalate delta value */
12367c478bd9Sstevel@tonic-gate delta_count = cnt_data[pic_num+1].value.ui64
12377c478bd9Sstevel@tonic-gate - evt_node->prev_count;
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate evt_node->prev_count = cnt_data[pic_num+1].value.ui64;
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate if (initial_read) {
12437c478bd9Sstevel@tonic-gate evt_node->total = 0;
12447c478bd9Sstevel@tonic-gate
12457c478bd9Sstevel@tonic-gate } else {
12467c478bd9Sstevel@tonic-gate /* Update count total */
12477c478bd9Sstevel@tonic-gate evt_node->total += delta_count;
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate if (delta) {
12507c478bd9Sstevel@tonic-gate (void) printf("%-20s %-9lld ",
12517c478bd9Sstevel@tonic-gate evt_node->evt_name, delta_count);
12527c478bd9Sstevel@tonic-gate } else {
12537c478bd9Sstevel@tonic-gate (void) printf("%-20s %-9lld ",
12547c478bd9Sstevel@tonic-gate evt_node->evt_name, evt_node->total);
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate /*
12617c478bd9Sstevel@tonic-gate * Check to see if any DR operations have occured, and deal with the
12627c478bd9Sstevel@tonic-gate * consequences.
12637c478bd9Sstevel@tonic-gate *
12647c478bd9Sstevel@tonic-gate * Use the Kstat chain ID to check for DR operations. If the ID has
12657c478bd9Sstevel@tonic-gate * changed then some kstats on system have been modified, we check
12667c478bd9Sstevel@tonic-gate * all the data structures to see are they still valid. If they are
12677c478bd9Sstevel@tonic-gate * not we remove them.
12687c478bd9Sstevel@tonic-gate */
12697c478bd9Sstevel@tonic-gate void
check_dr_ops()12707c478bd9Sstevel@tonic-gate check_dr_ops()
12717c478bd9Sstevel@tonic-gate {
12727c478bd9Sstevel@tonic-gate dev_node_t *dev_node;
12737c478bd9Sstevel@tonic-gate kid_t new_id;
12747c478bd9Sstevel@tonic-gate kstat_t *ksp;
12757c478bd9Sstevel@tonic-gate int match = 0;
12767c478bd9Sstevel@tonic-gate
12777c478bd9Sstevel@tonic-gate if ((new_id = kstat_chain_update(kc)) < 0) {
12787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not get "
12797c478bd9Sstevel@tonic-gate "kstat chain id\n"), pgmname);
12807c478bd9Sstevel@tonic-gate exit(1);
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate if (new_id == 0) {
12847c478bd9Sstevel@tonic-gate /* Kstat chain has not changed. */
12857c478bd9Sstevel@tonic-gate return;
12867c478bd9Sstevel@tonic-gate }
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate /*
12897c478bd9Sstevel@tonic-gate * Scan the chain of device nodes, making sure that their associated
12907c478bd9Sstevel@tonic-gate * kstats are still present. If not we remove the appropiate node.
12917c478bd9Sstevel@tonic-gate */
12927c478bd9Sstevel@tonic-gate dev_node = dev_list_head;
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate while (dev_node != NULL) {
12957c478bd9Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
12967c478bd9Sstevel@tonic-gate if ((strcmp("bus", ksp->ks_class) == 0) &&
12977c478bd9Sstevel@tonic-gate (strcmp("counters", ksp->ks_name) == 0) &&
12987c478bd9Sstevel@tonic-gate (strcmp(dev_node->name, ksp->ks_module) == 0) &&
12997c478bd9Sstevel@tonic-gate (ksp->ks_instance == dev_node->dev_inst)) {
13007c478bd9Sstevel@tonic-gate match = 1;
13017c478bd9Sstevel@tonic-gate break;
13027c478bd9Sstevel@tonic-gate }
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate if (match == 0) {
13057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: device %s%d"
13067c478bd9Sstevel@tonic-gate " (pic %d) no longer valid.\n"), pgmname,
13077c478bd9Sstevel@tonic-gate dev_node->name, dev_node->dev_inst,
13087c478bd9Sstevel@tonic-gate dev_node->pic_num);
13097c478bd9Sstevel@tonic-gate
13107c478bd9Sstevel@tonic-gate remove_dev_node(dev_node);
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate dev_node = dev_node->next;
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate /*
13197c478bd9Sstevel@tonic-gate * Remove a device node and its associated event nodes.
13207c478bd9Sstevel@tonic-gate */
13217c478bd9Sstevel@tonic-gate void
remove_dev_node(dev_node_t * dev_node)13227c478bd9Sstevel@tonic-gate remove_dev_node(dev_node_t *dev_node)
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate dev_node_t *curr_node;
13257c478bd9Sstevel@tonic-gate dev_node_t *prev_node;
13267c478bd9Sstevel@tonic-gate evt_node_t *curr_evt_node;
13277c478bd9Sstevel@tonic-gate evt_node_t *next_evt_node;
13287c478bd9Sstevel@tonic-gate evt_node_t *start_pos;
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate curr_node = dev_list_head;
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate if (curr_node == dev_node) {
13337c478bd9Sstevel@tonic-gate dev_list_head = dev_node->next;
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate if (dev_list_head == NULL) {
13367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: no "
13377c478bd9Sstevel@tonic-gate "devices left to monitor.\n"),
13387c478bd9Sstevel@tonic-gate pgmname);
13397c478bd9Sstevel@tonic-gate exit(1);
13407c478bd9Sstevel@tonic-gate }
13417c478bd9Sstevel@tonic-gate
13427c478bd9Sstevel@tonic-gate /* Remove each event node first */
13437c478bd9Sstevel@tonic-gate start_pos = dev_node->evt_node;
13447c478bd9Sstevel@tonic-gate curr_evt_node = start_pos->next;
13457c478bd9Sstevel@tonic-gate
13467c478bd9Sstevel@tonic-gate while (curr_evt_node != start_pos) {
13477c478bd9Sstevel@tonic-gate next_evt_node = curr_evt_node->next;
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate free(curr_evt_node);
13507c478bd9Sstevel@tonic-gate curr_evt_node = next_evt_node;
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate free(start_pos);
13547c478bd9Sstevel@tonic-gate free(dev_node);
13557c478bd9Sstevel@tonic-gate return;
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate
13587c478bd9Sstevel@tonic-gate /* Find the device node */
13597c478bd9Sstevel@tonic-gate prev_node = dev_list_head;
13607c478bd9Sstevel@tonic-gate curr_node = prev_node->next;
13617c478bd9Sstevel@tonic-gate
13627c478bd9Sstevel@tonic-gate while (curr_node != NULL) {
13637c478bd9Sstevel@tonic-gate if (curr_node == dev_node) {
13647c478bd9Sstevel@tonic-gate prev_node->next = curr_node->next;
13657c478bd9Sstevel@tonic-gate
13667c478bd9Sstevel@tonic-gate /* Remove each event node first */
13677c478bd9Sstevel@tonic-gate start_pos = dev_node->evt_node;
13687c478bd9Sstevel@tonic-gate curr_evt_node = start_pos->next;
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate while (curr_evt_node != start_pos) {
13717c478bd9Sstevel@tonic-gate next_evt_node = curr_evt_node->next;
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate free(curr_evt_node);
13747c478bd9Sstevel@tonic-gate curr_evt_node = next_evt_node;
13757c478bd9Sstevel@tonic-gate }
13767c478bd9Sstevel@tonic-gate free(start_pos);
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate free(dev_node);
13797c478bd9Sstevel@tonic-gate return;
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate prev_node = curr_node;
13827c478bd9Sstevel@tonic-gate curr_node = curr_node->next;
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate * Find a device node in the linked list of dev_nodes. Match
13897c478bd9Sstevel@tonic-gate * is done on device name, and instance number.
13907c478bd9Sstevel@tonic-gate */
13917c478bd9Sstevel@tonic-gate dev_node_t *
find_dev_node(char * name,int inst_num,int pic_num)13927c478bd9Sstevel@tonic-gate find_dev_node(char *name, int inst_num, int pic_num)
13937c478bd9Sstevel@tonic-gate {
13947c478bd9Sstevel@tonic-gate dev_node_t *curr_node;
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate curr_node = dev_list_head;
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate while (curr_node != NULL) {
13997c478bd9Sstevel@tonic-gate if ((strcmp(curr_node->name, name) == 0) &&
14007c478bd9Sstevel@tonic-gate (curr_node->dev_inst == inst_num) &&
14017c478bd9Sstevel@tonic-gate (curr_node->pic_num == pic_num)) {
14027c478bd9Sstevel@tonic-gate return (curr_node);
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate curr_node = curr_node->next;
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate return (NULL);
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate * Determines whether the string represents a event name
14147c478bd9Sstevel@tonic-gate * or a numeric value. Numeric value can be dec, hex
14157c478bd9Sstevel@tonic-gate * or octal. All are converted to long int.
14167c478bd9Sstevel@tonic-gate */
14177c478bd9Sstevel@tonic-gate int64_t
is_num(char * name)14187c478bd9Sstevel@tonic-gate is_num(char *name)
14197c478bd9Sstevel@tonic-gate {
14207c478bd9Sstevel@tonic-gate char *remainder = NULL;
14217c478bd9Sstevel@tonic-gate int64_t num;
14227c478bd9Sstevel@tonic-gate
14237c478bd9Sstevel@tonic-gate num = (int64_t)strtol(name, &remainder, 0);
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate if (name == remainder) {
14267c478bd9Sstevel@tonic-gate return (EVT_STR);
14277c478bd9Sstevel@tonic-gate } else {
14287c478bd9Sstevel@tonic-gate return (num);
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate
14337c478bd9Sstevel@tonic-gate /*
14347c478bd9Sstevel@tonic-gate * Find a pointer to the specified picN kstat. First
14357c478bd9Sstevel@tonic-gate * search for the specific kstat, and if that can't
14367c478bd9Sstevel@tonic-gate * be found search for any picN kstat belonging to this device.
14377c478bd9Sstevel@tonic-gate */
14387c478bd9Sstevel@tonic-gate kstat_t *
find_pic_kstat(char * dev_name,int inst_num,char * pic)14397c478bd9Sstevel@tonic-gate find_pic_kstat(char *dev_name, int inst_num, char *pic)
14407c478bd9Sstevel@tonic-gate {
14417c478bd9Sstevel@tonic-gate kstat_t *ksp;
14427c478bd9Sstevel@tonic-gate kstat_t *p_ksp;
14437c478bd9Sstevel@tonic-gate
14447c478bd9Sstevel@tonic-gate /* Look for specific picN kstat */
14457c478bd9Sstevel@tonic-gate if ((p_ksp = kstat_lookup(kc, dev_name, inst_num, pic)) == NULL) {
14467c478bd9Sstevel@tonic-gate
14477c478bd9Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
14487c478bd9Sstevel@tonic-gate if ((strcmp(ksp->ks_class, "bus") == 0) &&
14497c478bd9Sstevel@tonic-gate (strcmp(ksp->ks_name, pic) == 0) &&
14507c478bd9Sstevel@tonic-gate (strcmp(ksp->ks_module, dev_name) == 0)) {
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate return (ksp);
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate }
14567c478bd9Sstevel@tonic-gate return (p_ksp);
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate /*
14617c478bd9Sstevel@tonic-gate * Print column titles.
14627c478bd9Sstevel@tonic-gate * Can be turned off by -n option.
14637c478bd9Sstevel@tonic-gate */
14647c478bd9Sstevel@tonic-gate void
print_banner()14657c478bd9Sstevel@tonic-gate print_banner()
14667c478bd9Sstevel@tonic-gate {
14677c478bd9Sstevel@tonic-gate int i;
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate (void) printf("time dev ");
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate for (i = 0; i < max_pic_num; i++)
14727c478bd9Sstevel@tonic-gate (void) printf("event%d "
14737c478bd9Sstevel@tonic-gate "pic%d ", i, i);
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate (void) printf("\n");
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate banner = FALSE;
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate /*
14827c478bd9Sstevel@tonic-gate * Print the elapsed time in seconds, since the last call.
14837c478bd9Sstevel@tonic-gate */
14847c478bd9Sstevel@tonic-gate void
print_timestamp()14857c478bd9Sstevel@tonic-gate print_timestamp()
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate static hrtime_t curr_time = 0;
14887c478bd9Sstevel@tonic-gate static hrtime_t total_elapsed = 0;
14897c478bd9Sstevel@tonic-gate hrtime_t new_time = 0;
14907c478bd9Sstevel@tonic-gate hrtime_t elapsed = 0;
14917c478bd9Sstevel@tonic-gate hrtime_t rem = 0;
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate if (initial_read) {
14947c478bd9Sstevel@tonic-gate curr_time = (uint64_t)gethrtime();
14957c478bd9Sstevel@tonic-gate return;
14967c478bd9Sstevel@tonic-gate }
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate new_time = gethrtime();
14997c478bd9Sstevel@tonic-gate
15007c478bd9Sstevel@tonic-gate elapsed = (new_time - curr_time)/NANO;
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate /* Round up time value if necessary */
15037c478bd9Sstevel@tonic-gate rem = (new_time - curr_time)%NANO;
15047c478bd9Sstevel@tonic-gate if (rem >= NANO/2)
15057c478bd9Sstevel@tonic-gate elapsed += 1;
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate total_elapsed += elapsed;
15087c478bd9Sstevel@tonic-gate
15097c478bd9Sstevel@tonic-gate (void) printf("%-4llu ", total_elapsed);
15107c478bd9Sstevel@tonic-gate
15117c478bd9Sstevel@tonic-gate curr_time = new_time;
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate void
usage()15167c478bd9Sstevel@tonic-gate usage()
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate (void) printf(gettext("Usage : busstat [-a] [-h] [-l] [-n]\n"
15197c478bd9Sstevel@tonic-gate " [-e device-inst]\n"
15207c478bd9Sstevel@tonic-gate " [-w device-inst "
15217c478bd9Sstevel@tonic-gate "[,pic0=<event>] [,picN=<event>] ]\n"
15227c478bd9Sstevel@tonic-gate " [-r device-inst]\n"
15237c478bd9Sstevel@tonic-gate " [ interval [count] ]\n"));
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate exit(2);
15267c478bd9Sstevel@tonic-gate }
15277c478bd9Sstevel@tonic-gate
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate void *
safe_malloc(size_t size)15307c478bd9Sstevel@tonic-gate safe_malloc(size_t size)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate void *a;
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate if ((a = malloc(size)) == NULL) {
15357c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
15367c478bd9Sstevel@tonic-gate gettext("%s: out of memory.\n"), pgmname);
15377c478bd9Sstevel@tonic-gate exit(1);
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate
15407c478bd9Sstevel@tonic-gate return (a);
15417c478bd9Sstevel@tonic-gate }
15427c478bd9Sstevel@tonic-gate
15437c478bd9Sstevel@tonic-gate /*
15447c478bd9Sstevel@tonic-gate * Create and arm the timer.
15457c478bd9Sstevel@tonic-gate */
15467c478bd9Sstevel@tonic-gate void
set_timer(int interval)15477c478bd9Sstevel@tonic-gate set_timer(int interval)
15487c478bd9Sstevel@tonic-gate {
15497c478bd9Sstevel@tonic-gate timer_t t_id; /* Timer id */
15507c478bd9Sstevel@tonic-gate itimerspec_t time_struct;
15517c478bd9Sstevel@tonic-gate struct sigevent sig_struct;
15527c478bd9Sstevel@tonic-gate struct sigaction act;
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate bzero(&sig_struct, sizeof (struct sigevent));
15557c478bd9Sstevel@tonic-gate bzero(&act, sizeof (struct sigaction));
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate /* Create timer */
15587c478bd9Sstevel@tonic-gate sig_struct.sigev_notify = SIGEV_SIGNAL;
15597c478bd9Sstevel@tonic-gate sig_struct.sigev_signo = SIGUSR1;
15607c478bd9Sstevel@tonic-gate sig_struct.sigev_value.sival_int = 0;
15617c478bd9Sstevel@tonic-gate
15627c478bd9Sstevel@tonic-gate if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) {
15637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Timer creation failed.\n"),
15647c478bd9Sstevel@tonic-gate pgmname);
15657c478bd9Sstevel@tonic-gate exit(1);
15667c478bd9Sstevel@tonic-gate }
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate act.sa_handler = handle_sig;
15697c478bd9Sstevel@tonic-gate
15707c478bd9Sstevel@tonic-gate if (sigaction(SIGUSR1, &act, NULL) != 0) {
15717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: could not setup signal "
15727c478bd9Sstevel@tonic-gate "handler"), pgmname);
15737c478bd9Sstevel@tonic-gate exit(1);
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate time_struct.it_value.tv_sec = interval;
15777c478bd9Sstevel@tonic-gate time_struct.it_value.tv_nsec = 0;
15787c478bd9Sstevel@tonic-gate time_struct.it_interval.tv_sec = interval;
15797c478bd9Sstevel@tonic-gate time_struct.it_interval.tv_nsec = 0;
15807c478bd9Sstevel@tonic-gate
15817c478bd9Sstevel@tonic-gate /* Arm timer */
15827c478bd9Sstevel@tonic-gate if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) {
15837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: Setting timer failed.\n"),
15847c478bd9Sstevel@tonic-gate pgmname);
15857c478bd9Sstevel@tonic-gate exit(1);
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate /* ARGSUSED */
15917c478bd9Sstevel@tonic-gate void
handle_sig(int x)15927c478bd9Sstevel@tonic-gate handle_sig(int x)
15937c478bd9Sstevel@tonic-gate {
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate /*
15977c478bd9Sstevel@tonic-gate * return a boolean value indicating whether or not
15987c478bd9Sstevel@tonic-gate * a string consists solely of characters which are
15997c478bd9Sstevel@tonic-gate * digits 0..9
16007c478bd9Sstevel@tonic-gate */
16017c478bd9Sstevel@tonic-gate int
strisnum(const char * s)16027c478bd9Sstevel@tonic-gate strisnum(const char *s)
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate for (; *s != '\0'; s++) {
16057c478bd9Sstevel@tonic-gate if (*s < '0' || *s > '9')
16067c478bd9Sstevel@tonic-gate return (0);
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate return (1);
16097c478bd9Sstevel@tonic-gate }
1610