OpenSolaris_b135/cmd/avs/sdbc/sd_stats.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <curses.h>
#include <signal.h>
#include <fcntl.h>
#include <locale.h>

#include <sys/types.h>
#include <sys/time.h>
#include <sys/nsctl/sdbc_ioctl.h>
#include <sys/unistat/spcs_s_u.h>
#include <sys/nsctl/sd_bcache.h>
#include <sys/nsctl/sd_conf.h>

extern void total_display(void);
extern void display_cache(void);
extern void wrefresh_file(WINDOW *, int);
extern int is_dirty(void);
extern int dual_stats(void);
void checkbuf(int);
void setup_ranges(char *);
void prheading(int);
extern int zero_nic(void);

#ifdef m88k
#define	USEC_INIT()	usec_ptr = (unsigned int *)timer_init()
#define	USEC_READ()	(*usec_ptr)
#else /* !m88k */
#define	USEC_INIT()	USEC_START()
#include <sys/time.h>
static struct timeval Usec_time;
static int Usec_started = 0;

extern int higher(int);
extern int is_dirty();
extern int dual_stats();
extern void total_display();
extern void display_cache();
extern void wrefresh_file(WINDOW *, int);
void setup_ranges(char *);

void prheading(int);
void checkbuf(int);
void quit(int);
void leave(int);
#pragma does_not_return(quit, leave)

int sdbc_max_devices = 0;

static void
USEC_START()
{
	if (!Usec_started) {
		(void) gettimeofday(&Usec_time, NULL);
		Usec_started = 1;
	}
}

static unsigned int
USEC_READ()
{
	struct timeval tv;
	if (!Usec_started)
		USEC_START();

	(void) gettimeofday(&tv, NULL);
	return (unsigned)((tv.tv_sec - Usec_time.tv_sec) * 1000000
	    + (tv.tv_usec - Usec_time.tv_usec));
}
#endif /* m88k */

int		rev_flag = 0;		/* Reverse video flag */
int		bold_flg = 0;		/* Bold flag */
int		under_flg = 0;		/* Underline flag */
int		errflg = 0;		/* Error flag */
int		node_sw = 0;		/* Per node switch */
int 		toggle_total_sw = 0;
int		mirror_sw = 0;		/* Dual copy switch */

int		kmemfd;
int		delay = 1;			/* Display delay (seconds) */

time_t	*usec_ptr;
time_t	currtime = 0;
int		lasttime = 0;
int		Elapsed_Time = 0;

static char	*range;
static int	had_r_option = 0;
int		logfd = -1;		/* screen output logging */
extern 		int range_num;
extern		int screen;
extern 		int dual_screen;
int		*on_off;
int		*dual_on_off;
int		*updates_prev;
double		*rate_prev;
int		*samples;
_sd_stats_t	*cs_cur;
_sd_stats_t	*cs_prev;
_sd_stats_t	*cs_persec;

typedef struct {
	int lb, ub;
} range_t;

extern range_t ranges[];

#ifdef lint
int
sd_stats_lintmain(int argc, char *argv[])
#else
int
main(int argc, char *argv[])
#endif
{
	spcs_s_info_t ustats;
	struct timeval tout;
	fd_set readfds;
	char *errmessage, *ch;
	int c, period, prev;
	int count = 0, dflag = 0;
	int fd = fileno(stdin);

	errmessage = NULL;

	if (strcmp(argv[0], "sd_stats") != 0)
		errmessage = getenv("SD_STATS_USAGE");

	if (errmessage == NULL)
		errmessage = gettext("Usage: sd_stats [-Mz] "
				"[-d delay_time] [-l logfile] [-r range]");

	if (SDBC_IOCTL(SDBC_MAXFILES, &sdbc_max_devices,
	    0, 0, 0, 0, &ustats) == SPCS_S_ERROR) {
		if (ustats) {  	/* if SPCS_S_ERROR */
			spcs_s_report(ustats, stderr);
			spcs_s_ufree(&ustats);
		}
		(void) fprintf(stderr, gettext("cannot get maxfiles\n"));
		exit(1);
	}
	on_off = calloc(sdbc_max_devices, sizeof (int));
	dual_on_off = calloc(sdbc_max_devices, sizeof (int));
	updates_prev = calloc(sdbc_max_devices, sizeof (int));
	samples = calloc(sdbc_max_devices, sizeof (int));
	rate_prev = calloc(sdbc_max_devices, sizeof (double));
	cs_cur = malloc(sizeof (_sd_stats_t) +
	    (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
	cs_prev = malloc(sizeof (_sd_stats_t) +
	    (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
	cs_persec = malloc(sizeof (_sd_stats_t) +
	    (sdbc_max_devices - 1) * sizeof (_sd_shared_t));
	range = malloc(100);

	if (!on_off || !dual_on_off || !updates_prev || !samples ||
	    !rate_prev || !cs_cur || !cs_prev || !cs_persec || !range) {
		(void) fprintf(stderr, gettext("no free memory\n"));
		exit(1);
	}

	*range = '\0';

	while ((c = getopt(argc, argv, "DMzd:l:r:h")) != EOF) {

		prev = c;
		switch (c) {

		case 'd':
			delay = atoi(optarg);
			ch = optarg;
			while (*ch != '\0') {
				if (!isdigit(*ch))
					errflg++;
				ch++;
			}
			break;

		case 'l':
			logfd = open(optarg, O_CREAT|O_WRONLY|O_TRUNC, 0644);
			break;

		case 'r':
			ch = optarg;
			while (*ch != '\0') {
				if ((!isdigit(*ch)) && (*ch != ',') &&
				    (*ch != ':'))
					errflg++;
				ch++;
			}
			if (errflg)
				break;

			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;
			}
		}
	}
}