sd_stats.c revision 570de38f63910201fdd77246630b7aa8f9dc5661
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <strings.h>
2N/A#include <curses.h>
2N/A#include <signal.h>
2N/A#include <fcntl.h>
2N/A#include <locale.h>
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/time.h>
2N/A#include <sys/nsctl/sdbc_ioctl.h>
2N/A#include <sys/unistat/spcs_s_u.h>
2N/A#include <sys/nsctl/sd_bcache.h>
2N/A#include <sys/nsctl/sd_conf.h>
2N/A
2N/Aextern void total_display(void);
2N/Aextern void display_cache(void);
2N/Aextern void wrefresh_file(WINDOW *, int);
2N/Aextern int is_dirty(void);
2N/Aextern int dual_stats(void);
2N/Avoid checkbuf(int);
2N/Avoid setup_ranges(char *);
2N/Avoid prheading(int);
2N/Aextern int zero_nic(void);
2N/A
2N/A#ifdef m88k
2N/A#define USEC_INIT() usec_ptr = (unsigned int *)timer_init()
2N/A#define USEC_READ() (*usec_ptr)
2N/A#else /* !m88k */
2N/A#define USEC_INIT() USEC_START()
2N/A#include <sys/time.h>
2N/Astatic struct timeval Usec_time;
2N/Astatic int Usec_started = 0;
2N/A
2N/Aextern int higher(int);
2N/Aextern int is_dirty();
2N/Aextern int dual_stats();
2N/Aextern void total_display();
2N/Aextern void display_cache();
2N/Aextern void wrefresh_file(WINDOW *, int);
2N/Avoid setup_ranges(char *);
2N/A
2N/Avoid prheading(int);
2N/Avoid checkbuf(int);
2N/Avoid quit(int);
2N/Avoid leave(int);
2N/A#pragma does_not_return(quit, leave)
2N/A
2N/Aint sdbc_max_devices = 0;
2N/A
2N/Astatic void
2N/AUSEC_START()
2N/A{
2N/A if (!Usec_started) {
2N/A (void) gettimeofday(&Usec_time, NULL);
2N/A Usec_started = 1;
2N/A }
2N/A}
2N/A
2N/Astatic unsigned int
2N/AUSEC_READ()
2N/A{
2N/A struct timeval tv;
2N/A if (!Usec_started)
2N/A USEC_START();
2N/A
2N/A (void) gettimeofday(&tv, NULL);
2N/A return (unsigned)((tv.tv_sec - Usec_time.tv_sec) * 1000000
2N/A + (tv.tv_usec - Usec_time.tv_usec));
2N/A}
2N/A#endif /* m88k */
2N/A
2N/Aint rev_flag = 0; /* Reverse video flag */
2N/Aint bold_flg = 0; /* Bold flag */
2N/Aint under_flg = 0; /* Underline flag */
2N/Aint errflg = 0; /* Error flag */
2N/Aint node_sw = 0; /* Per node switch */
2N/Aint toggle_total_sw = 0;
2N/Aint mirror_sw = 0; /* Dual copy switch */
2N/A
2N/Aint kmemfd;
2N/Aint delay = 1; /* Display delay (seconds) */
2N/A
2N/Atime_t *usec_ptr;
2N/Atime_t currtime = 0;
2N/Aint lasttime = 0;
2N/Aint Elapsed_Time = 0;
2N/A
2N/Astatic char *range;
2N/Astatic int had_r_option = 0;
2N/Aint logfd = -1; /* screen output logging */
2N/Aextern int range_num;
2N/Aextern int screen;
2N/Aextern int dual_screen;
2N/Aint *on_off;
2N/Aint *dual_on_off;
2N/Aint *updates_prev;
2N/Adouble *rate_prev;
2N/Aint *samples;
2N/A_sd_stats_t *cs_cur;
2N/A_sd_stats_t *cs_prev;
2N/A_sd_stats_t *cs_persec;
2N/A
2N/Atypedef struct {
2N/A int lb, ub;
2N/A} range_t;
2N/A
2N/Aextern range_t ranges[];
2N/A
2N/A#ifdef lint
2N/Aint
2N/Asd_stats_lintmain(int argc, char *argv[])
2N/A#else
2N/Aint
2N/Amain(int argc, char *argv[])
2N/A#endif
2N/A{
2N/A spcs_s_info_t ustats;
2N/A struct timeval tout;
2N/A fd_set readfds;
2N/A char *errmessage, *ch;
2N/A int c, period, prev;
2N/A int count = 0, dflag = 0;
2N/A int fd = fileno(stdin);
2N/A
2N/A errmessage = NULL;
2N/A
2N/A if (strcmp(argv[0], "sd_stats") != 0)
2N/A errmessage = getenv("SD_STATS_USAGE");
2N/A
2N/A if (errmessage == NULL)
2N/A errmessage = gettext("Usage: sd_stats [-Mz] "
2N/A "[-d delay_time] [-l logfile] [-r range]");
2N/A
2N/A if (SDBC_IOCTL(SDBC_MAXFILES, &sdbc_max_devices,
2N/A 0, 0, 0, 0, &ustats) == SPCS_S_ERROR) {
2N/A if (ustats) { /* if SPCS_S_ERROR */
2N/A spcs_s_report(ustats, stderr);
2N/A spcs_s_ufree(&ustats);
2N/A }
2N/A (void) fprintf(stderr, gettext("cannot get maxfiles\n"));
2N/A exit(1);
2N/A }
2N/A on_off = calloc(sdbc_max_devices, sizeof (int));
2N/A dual_on_off = calloc(sdbc_max_devices, sizeof (int));
2N/A updates_prev = calloc(sdbc_max_devices, sizeof (int));
2N/A samples = calloc(sdbc_max_devices, sizeof (int));
2N/A rate_prev = calloc(sdbc_max_devices, sizeof (double));
2N/A cs_cur = malloc(sizeof (_sd_stats_t) +
2N/A (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
2N/A cs_prev = malloc(sizeof (_sd_stats_t) +
2N/A (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
2N/A cs_persec = malloc(sizeof (_sd_stats_t) +
2N/A (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
2N/A range = malloc(100);
2N/A
2N/A if (!on_off || !dual_on_off || !updates_prev || !samples ||
2N/A !rate_prev || !cs_cur || !cs_prev || !cs_persec || !range) {
2N/A (void) fprintf(stderr, gettext("no free memory\n"));
2N/A exit(1);
2N/A }
2N/A
2N/A *range = '\0';
2N/A
2N/A while ((c = getopt(argc, argv, "DMzd:l:r:h")) != EOF) {
2N/A
2N/A prev = c;
2N/A switch (c) {
2N/A
2N/A case 'd':
2N/A delay = atoi(optarg);
2N/A ch = optarg;
2N/A while (*ch != '\0') {
2N/A if (!isdigit(*ch))
2N/A errflg++;
2N/A ch++;
2N/A }
2N/A break;
2N/A
2N/A case 'l':
2N/A logfd = open(optarg, O_CREAT|O_WRONLY|O_TRUNC, 0644);
2N/A break;
2N/A
2N/A case 'r':
2N/A ch = optarg;
2N/A while (*ch != '\0') {
2N/A if ((!isdigit(*ch)) && (*ch != ',') &&
2N/A (*ch != ':'))
2N/A errflg++;
2N/A ch++;
2N/A }
2N/A if (errflg)
2N/A break;
2N/A
range = realloc((char *)range,
(strlen(range) + strlen(optarg) + 1)
* sizeof (char));
if (had_r_option)
(void) strcat(range, ",");
(void) strcat(range, optarg);
had_r_option = 1;
break;
case 'z':
if (SDBC_IOCTL(SDBC_ZAP_STATS, 0, 0, 0, 0, 0,
&ustats) == SPCS_S_ERROR) {
if (ustats) {
spcs_s_report(ustats, stderr);
spcs_s_ufree(&ustats);
}
}
break;
case 'D':
dflag = 1;
break;
case 'M':
mirror_sw = 1;
break;
case 'h':
case '?':
default :
errflg++;
break;
}
}
if (errflg) {
(void) fprintf(stderr, "%s\n", errmessage);
exit(1);
} else if (!prev) {
if (argc > 1) {
(void) fprintf(stderr, "%s\n", errmessage);
exit(1);
}
}
if (dflag) {
exit(is_dirty());
}
/*
* A few curses routines to setup screen and tty interface
*/
(void) initscr();
(void) cbreak();
(void) noecho();
(void) nonl();
(void) erase();
(void) clear();
(void) refresh();
setup_ranges(range);
/*
* Set signal handle
*/
(void) sigset(SIGPIPE, leave);
(void) sigset(SIGINT, leave);
(void) sigset(SIGQUIT, leave);
(void) signal(SIGFPE, leave);
(void) signal(SIGSEGV, leave);
USEC_INIT();
currtime = USEC_READ();
/*
* Wait one second before reading the new values
*/
(void) sleep(1);
/*CONSTCOND*/
while (1) {
lasttime = currtime;
currtime = USEC_READ();
/*
* If less that 1 second, force it to one second
*/
if ((period = (currtime - lasttime) / 1000000) <= 0)
period = 1;
/*
* Calculate new per/period values for statistics
*/
Elapsed_Time += period;
/*
* Display new statistics
*/
prheading(++count);
if (mirror_sw) {
if (dual_stats() < 0)
mirror_sw = 0;
} else if (toggle_total_sw)
total_display();
else
display_cache();
(void) move(0, 0);
(void) refresh();
if (logfd > -1) wrefresh_file(stdscr, logfd);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
tout.tv_sec = delay;
for (;;) {
tout.tv_usec = 0;
if (select(fd + 1, &readfds, (fd_set *)0, (fd_set *)0,
&tout) <= 0)
break;
if ((c = getch()) == EOF) {
(void) sleep(delay);
break;
}
checkbuf(c);
tout.tv_sec = 0;
}
(void) erase();
}
#pragma error_messages(off, E_STATEMENT_NOT_REACHED)
return (0);
#pragma error_messages(default, E_STATEMENT_NOT_REACHED)
}
void
checkbuf(int c)
{
spcs_s_info_t ustats;
switch (c) {
case 'b' : /* ctrl b or b -- scroll backward */
case 2 :
{
if (mirror_sw == 1) {
if (dual_screen > 0)
dual_screen--;
break;
}
if (screen > 0)
screen--;
break;
}
case 'f' : /* ctrl f or f -- scroll forward */
case 6 :
{
if (mirror_sw == 1) {
dual_screen++;
break;
}
screen++;
break;
}
case 't':
case 'T':
if (mirror_sw == 1)
mirror_sw = 0;
toggle_total_sw ^= 1;
break;
case '-':
case KEY_DOWN:
if (delay > 1) {
--delay;
} else {
(void) beep();
}
break;
case '+':
case KEY_UP:
delay++;
break;
case 'C':
case 0xc:
(void) clearok(stdscr, TRUE);
break;
case 'B':
if (bold_flg) {
bold_flg = 0;
(void) attroff(A_BOLD);
} else {
bold_flg = 1;
(void) attron(A_BOLD);
}
break;
case 'R':
if (rev_flag) {
rev_flag = 0;
(void) attroff(A_REVERSE);
} else {
rev_flag = 1;
(void) attron(A_REVERSE);
}
break;
case 'z':
if (SDBC_IOCTL(SDBC_ZAP_STATS, 0, 0, 0, 0, 0,
&ustats) == SPCS_S_ERROR) {
if (ustats) {
spcs_s_report(ustats, stderr);
spcs_s_ufree(&ustats);
}
}
break;
case 'm':
case 'M':
mirror_sw = mirror_sw ? 0 : 1;
(void) clear();
break;
}
}
void
prheading(int count)
{
time_t tim;
/*
* Print sample count in upper left corner
*/
(void) mvprintw(0, 0, "SAMPLE %-8d", count);
/*
* Get time and print it in upper right corner
*/
tim = time((time_t *)0);
(void) mvprintw(0, 79 - 10, "%-8.8s\n", &(ctime(&tim)[11]));
}
/*ARGSUSED*/
void
leave(int status)
{
(void) sigignore(SIGPIPE);
(void) sigignore(SIGALRM);
/* clear(); */
(void) move(LINES, 0);
(void) refresh();
if (logfd > -1) wrefresh_file(stdscr, logfd);
quit(0);
}
void
quit(int status)
{
(void) resetterm();
(void) endwin();
exit(status);
}
void
setup_ranges(char *range)
{
int ndx;
char chr1;
char prev_chr = '\0';
int got_colon = 0;
int after_got_colon = 0;
int got_comma = 0;
int after_got_comma = 0;
int number = 0;
int prev_num = 0;
if (range == NULL || (strlen(range) == 0)) {
ranges[range_num].lb = 0;
ranges[range_num].ub = sdbc_max_devices - 1;
return;
} else {
ndx = 0;
got_comma = 0;
got_colon = 0;
while ((chr1 = (range[ndx++])) != '\0') {
switch (chr1) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number = number*10 + (chr1 - '0');
break;
case ':':
got_colon = 1;
break;
case ',':
got_comma = 1;
break;
default: /* ignore any unknown characters */
break;
} /* switch */
if (got_comma && after_got_colon) {
after_got_colon = 0;
got_comma = 0;
if (number >= sdbc_max_devices)
number = sdbc_max_devices - 1;
ranges[range_num].lb = prev_num;
ranges[range_num].ub = number;
if (range_num == 99) break;
range_num++;
number = 0;
} else if (got_colon && after_got_comma) {
got_colon = 0;
after_got_colon = 1;
after_got_comma = 0;
if (number >= sdbc_max_devices)
number = sdbc_max_devices - 1;
prev_num = number;
number = 0;
} else if (got_colon) {
got_colon = 0;
after_got_colon = 1;
if ((prev_chr != '\0') && (prev_chr != ':')) {
if (number >= sdbc_max_devices)
number = sdbc_max_devices - 1;
prev_num = number;
number = 0;
}
} else if (got_comma) {
got_comma = 0;
after_got_comma = 1;
after_got_colon = 0;
if (number >= sdbc_max_devices)
number = sdbc_max_devices -1;
if ((prev_chr != '\0') && (prev_chr != ',')) {
ranges[range_num].lb = number;
ranges[range_num].ub = number;
if (range_num == 99) break;
range_num++;
}
number = 0;
} /* if */
prev_chr = chr1;
} /* while */
if (number >= sdbc_max_devices)
number = sdbc_max_devices - 1;
if (after_got_colon) {
ranges[range_num].lb = prev_num;
ranges[range_num].ub = number;
} else {
if ((after_got_comma) && (prev_chr == ','))
range_num--;
else {
ranges[range_num].lb = number;
ranges[range_num].ub = number;
}
}
}
}