xref: /onnv-gate/usr/src/cmd/powertop/common/display.c (revision 11122:393b5ac48d9b)
19338Srafael.vanoni@sun.com /*
29338Srafael.vanoni@sun.com  * Copyright 2009, Intel Corporation
39338Srafael.vanoni@sun.com  * Copyright 2009, Sun Microsystems, Inc
49338Srafael.vanoni@sun.com  *
59338Srafael.vanoni@sun.com  * This file is part of PowerTOP
69338Srafael.vanoni@sun.com  *
79338Srafael.vanoni@sun.com  * This program file is free software; you can redistribute it and/or modify it
89338Srafael.vanoni@sun.com  * under the terms of the GNU General Public License as published by the
99338Srafael.vanoni@sun.com  * Free Software Foundation; version 2 of the License.
109338Srafael.vanoni@sun.com  *
119338Srafael.vanoni@sun.com  * This program is distributed in the hope that it will be useful, but WITHOUT
129338Srafael.vanoni@sun.com  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139338Srafael.vanoni@sun.com  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
149338Srafael.vanoni@sun.com  * for more details.
159338Srafael.vanoni@sun.com  *
169338Srafael.vanoni@sun.com  * You should have received a copy of the GNU General Public License
179338Srafael.vanoni@sun.com  * along with this program in a file named COPYING; if not, write to the
189338Srafael.vanoni@sun.com  * Free Software Foundation, Inc.,
199338Srafael.vanoni@sun.com  * 51 Franklin Street, Fifth Floor,
209338Srafael.vanoni@sun.com  * Boston, MA 02110-1301 USA
219338Srafael.vanoni@sun.com  *
229338Srafael.vanoni@sun.com  * Authors:
239338Srafael.vanoni@sun.com  *	Arjan van de Ven <arjan@linux.intel.com>
249338Srafael.vanoni@sun.com  *	Eric C Saxe <eric.saxe@sun.com>
259338Srafael.vanoni@sun.com  *	Aubrey Li <aubrey.li@intel.com>
269338Srafael.vanoni@sun.com  */
279338Srafael.vanoni@sun.com 
289338Srafael.vanoni@sun.com /*
299338Srafael.vanoni@sun.com  * GPL Disclaimer
309338Srafael.vanoni@sun.com  *
319338Srafael.vanoni@sun.com  * For the avoidance of doubt, except that if any license choice other
329338Srafael.vanoni@sun.com  * than GPL or LGPL is available it will apply instead, Sun elects to
339338Srafael.vanoni@sun.com  * use only the General Public License version 2 (GPLv2) at this time
349338Srafael.vanoni@sun.com  * for any software where a choice of GPL license versions is made
359338Srafael.vanoni@sun.com  * available with the language indicating that GPLv2 or any later
369338Srafael.vanoni@sun.com  * version may be used, or where a choice of which version of the GPL
379338Srafael.vanoni@sun.com  * is applied is otherwise unspecified.
389338Srafael.vanoni@sun.com  */
399338Srafael.vanoni@sun.com 
409338Srafael.vanoni@sun.com #include <stdlib.h>
419338Srafael.vanoni@sun.com #include <string.h>
429908Srafael.vanoni@sun.com #include <unistd.h>
439338Srafael.vanoni@sun.com #include <curses.h>
449908Srafael.vanoni@sun.com #include <signal.h>
459908Srafael.vanoni@sun.com #include <fcntl.h>
469338Srafael.vanoni@sun.com #include "powertop.h"
479338Srafael.vanoni@sun.com 
489908Srafael.vanoni@sun.com /*
499908Srafael.vanoni@sun.com  * Minimum terminal height and width to run PowerTOP on curses mode.
509908Srafael.vanoni@sun.com  */
519908Srafael.vanoni@sun.com #define	PT_MIN_COLS		70
529908Srafael.vanoni@sun.com #define	PT_MIN_ROWS		15
539908Srafael.vanoni@sun.com 
549908Srafael.vanoni@sun.com /*
559908Srafael.vanoni@sun.com  * Display colors
569908Srafael.vanoni@sun.com  */
579908Srafael.vanoni@sun.com #define	PT_COLOR_DEFAULT	1
589908Srafael.vanoni@sun.com #define	PT_COLOR_HEADER_BAR	2
599908Srafael.vanoni@sun.com #define	PT_COLOR_ERROR		3
609908Srafael.vanoni@sun.com #define	PT_COLOR_RED		4
619908Srafael.vanoni@sun.com #define	PT_COLOR_YELLOW		5
629908Srafael.vanoni@sun.com #define	PT_COLOR_GREEN		6
639908Srafael.vanoni@sun.com #define	PT_COLOR_BRIGHT		7
649908Srafael.vanoni@sun.com #define	PT_COLOR_BLUE		8
659908Srafael.vanoni@sun.com 
669908Srafael.vanoni@sun.com /*
679908Srafael.vanoni@sun.com  * Constants for pt_display_setup()
689908Srafael.vanoni@sun.com  */
699908Srafael.vanoni@sun.com #define	SINGLE_LINE_SW 		1
709908Srafael.vanoni@sun.com #define	LENGTH_SUGG_SW		2
719908Srafael.vanoni@sun.com #define	TITLE_LINE		1
729908Srafael.vanoni@sun.com #define	BLANK_LINE		1
739908Srafael.vanoni@sun.com #define	NEXT_LINE		1
749338Srafael.vanoni@sun.com 
759338Srafael.vanoni@sun.com #define	print(win, y, x, fmt, args...)				\
769711Srafael.vanoni@sun.com 	if (PT_ON_DUMP)						\
779338Srafael.vanoni@sun.com 		(void) printf(fmt, ## args);			\
789338Srafael.vanoni@sun.com 	else							\
799338Srafael.vanoni@sun.com 		(void) mvwprintw(win, y, x, fmt, ## args);
809338Srafael.vanoni@sun.com 
819908Srafael.vanoni@sun.com enum pt_subwindows {
829908Srafael.vanoni@sun.com 	SW_TITLE,
839908Srafael.vanoni@sun.com 	SW_IDLE,
849908Srafael.vanoni@sun.com 	SW_FREQ,
859908Srafael.vanoni@sun.com 	SW_WAKEUPS,
869908Srafael.vanoni@sun.com 	SW_POWER,
879908Srafael.vanoni@sun.com 	SW_EVENTS,
889908Srafael.vanoni@sun.com 	SW_SUGG,
899908Srafael.vanoni@sun.com 	SW_STATUS,
909908Srafael.vanoni@sun.com 	SW_COUNT
919908Srafael.vanoni@sun.com };
929338Srafael.vanoni@sun.com 
939908Srafael.vanoni@sun.com typedef struct sb_slot {
949908Srafael.vanoni@sun.com 	char *msg;
959908Srafael.vanoni@sun.com 	struct sb_slot *prev;
969908Srafael.vanoni@sun.com 	struct sb_slot *next;
979908Srafael.vanoni@sun.com } sb_slot_t;
989908Srafael.vanoni@sun.com 
999908Srafael.vanoni@sun.com static WINDOW *sw[SW_COUNT];
1009908Srafael.vanoni@sun.com static int win_cols, win_rows;
1019908Srafael.vanoni@sun.com static sb_slot_t *status_bar;
1029338Srafael.vanoni@sun.com 
103*11122Srafael.vanoni@sun.com /*
104*11122Srafael.vanoni@sun.com  * Delete all subwindows and reset the terminal to a non-visual mode. This
105*11122Srafael.vanoni@sun.com  * routine is used during resize events and before exiting.
106*11122Srafael.vanoni@sun.com  */
1079338Srafael.vanoni@sun.com static void
pt_display_cleanup(void)1089908Srafael.vanoni@sun.com pt_display_cleanup(void)
1099908Srafael.vanoni@sun.com {
110*11122Srafael.vanoni@sun.com 	int i;
111*11122Srafael.vanoni@sun.com 
112*11122Srafael.vanoni@sun.com 	for (i = 0; i < SW_COUNT; i++) {
113*11122Srafael.vanoni@sun.com 		if (sw[i] != NULL) {
114*11122Srafael.vanoni@sun.com 			(void) delwin(sw[i]);
115*11122Srafael.vanoni@sun.com 			sw[i] = NULL;
116*11122Srafael.vanoni@sun.com 		}
117*11122Srafael.vanoni@sun.com 	}
118*11122Srafael.vanoni@sun.com 
1199908Srafael.vanoni@sun.com 	(void) endwin();
120*11122Srafael.vanoni@sun.com 	(void) fflush(stdout);
121*11122Srafael.vanoni@sun.com 	(void) putchar('\r');
1229908Srafael.vanoni@sun.com }
1239908Srafael.vanoni@sun.com 
1249908Srafael.vanoni@sun.com static void
pt_display_get_size(void)1259908Srafael.vanoni@sun.com pt_display_get_size(void)
1269338Srafael.vanoni@sun.com {
1279908Srafael.vanoni@sun.com 	getmaxyx(stdscr, win_rows, win_cols);
1289908Srafael.vanoni@sun.com 
1299908Srafael.vanoni@sun.com 	if (win_rows < PT_MIN_ROWS || win_cols < PT_MIN_COLS) {
1309908Srafael.vanoni@sun.com 		pt_display_cleanup();
1319908Srafael.vanoni@sun.com 		(void) printf("\n\nPowerTOP cannot run in such a small "
1329908Srafael.vanoni@sun.com 		    "terminal window. Please resize it.\n\n");
1339908Srafael.vanoni@sun.com 		exit(EXIT_FAILURE);
1349338Srafael.vanoni@sun.com 	}
1359338Srafael.vanoni@sun.com }
1369338Srafael.vanoni@sun.com 
137*11122Srafael.vanoni@sun.com void
pt_display_resize(void)138*11122Srafael.vanoni@sun.com pt_display_resize(void)
1399338Srafael.vanoni@sun.com {
140*11122Srafael.vanoni@sun.com 	pt_display_cleanup();
141*11122Srafael.vanoni@sun.com 	(void) pt_display_init_curses();
142*11122Srafael.vanoni@sun.com 	pt_display_setup(B_TRUE);
143*11122Srafael.vanoni@sun.com 
144*11122Srafael.vanoni@sun.com 	pt_display_title_bar();
145*11122Srafael.vanoni@sun.com 
146*11122Srafael.vanoni@sun.com 	pt_display_states();
1479908Srafael.vanoni@sun.com 
148*11122Srafael.vanoni@sun.com 	if (g_features & FEATURE_EVENTS) {
149*11122Srafael.vanoni@sun.com 		pt_display_wakeups(g_interval_length);
150*11122Srafael.vanoni@sun.com 		pt_display_events(g_interval_length);
151*11122Srafael.vanoni@sun.com 	}
1529908Srafael.vanoni@sun.com 
153*11122Srafael.vanoni@sun.com 	pt_battery_print();
154*11122Srafael.vanoni@sun.com 	pt_sugg_pick();
155*11122Srafael.vanoni@sun.com 	pt_display_status_bar();
1569908Srafael.vanoni@sun.com 
157*11122Srafael.vanoni@sun.com 	pt_display_update();
1589908Srafael.vanoni@sun.com 
159*11122Srafael.vanoni@sun.com 	g_sig_resize = B_FALSE;
160*11122Srafael.vanoni@sun.com 	(void) signal(SIGWINCH, pt_sig_handler);
1619338Srafael.vanoni@sun.com }
1629338Srafael.vanoni@sun.com 
1639338Srafael.vanoni@sun.com /*
1649338Srafael.vanoni@sun.com  * This part was re-written to be human readable and easy to modify. Please
1659338Srafael.vanoni@sun.com  * try to keep it that way and help us save some time.
1669338Srafael.vanoni@sun.com  *
1679338Srafael.vanoni@sun.com  * Friendly reminder:
1689338Srafael.vanoni@sun.com  * 	subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x)
1699338Srafael.vanoni@sun.com  */
1709338Srafael.vanoni@sun.com void
pt_display_setup(boolean_t resized)1719908Srafael.vanoni@sun.com pt_display_setup(boolean_t resized)
1729338Srafael.vanoni@sun.com {
1739338Srafael.vanoni@sun.com 	/*
1749338Srafael.vanoni@sun.com 	 * These variables are used to properly set the initial y position and
1759338Srafael.vanoni@sun.com 	 * number of lines in each subwindow, as the number of supported CPU
1769338Srafael.vanoni@sun.com 	 * states affects their placement.
1779338Srafael.vanoni@sun.com 	 */
1789908Srafael.vanoni@sun.com 	int cstate_lines, event_lines, pos_y = 0;
1799338Srafael.vanoni@sun.com 
1809908Srafael.vanoni@sun.com 	/*
1819908Srafael.vanoni@sun.com 	 * In theory, all systems have at least two idle states. We add two here
1829908Srafael.vanoni@sun.com 	 * since we have to use DTrace to figure out how many this box has.
1839908Srafael.vanoni@sun.com 	 */
1849908Srafael.vanoni@sun.com 	cstate_lines = TITLE_LINE + max((g_max_cstate+2), g_npstates);
1859338Srafael.vanoni@sun.com 
1869908Srafael.vanoni@sun.com 	sw[SW_TITLE] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
1879338Srafael.vanoni@sun.com 
1889338Srafael.vanoni@sun.com 	pos_y += NEXT_LINE + BLANK_LINE;
1899908Srafael.vanoni@sun.com 	sw[SW_IDLE] = subwin(stdscr, cstate_lines, win_cols/2 + 1, pos_y, 0);
1909908Srafael.vanoni@sun.com 	sw[SW_FREQ] = subwin(stdscr, cstate_lines, win_cols/2 - 8, pos_y,
1919908Srafael.vanoni@sun.com 	    win_cols/2 + 8);
1929338Srafael.vanoni@sun.com 
1939338Srafael.vanoni@sun.com 	pos_y += cstate_lines + BLANK_LINE;
1949908Srafael.vanoni@sun.com 	sw[SW_WAKEUPS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
1959338Srafael.vanoni@sun.com 
1969338Srafael.vanoni@sun.com 	pos_y += NEXT_LINE;
1979908Srafael.vanoni@sun.com 	sw[SW_POWER] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
1989338Srafael.vanoni@sun.com 
1999338Srafael.vanoni@sun.com 	pos_y += NEXT_LINE + BLANK_LINE;
2009908Srafael.vanoni@sun.com 	event_lines = win_rows - SINGLE_LINE_SW - NEXT_LINE - LENGTH_SUGG_SW -
2019338Srafael.vanoni@sun.com 	    pos_y;
2029908Srafael.vanoni@sun.com 
2039908Srafael.vanoni@sun.com 	if (event_lines > 0) {
2049908Srafael.vanoni@sun.com 		sw[SW_EVENTS] = subwin(stdscr, event_lines, win_cols, pos_y, 0);
2059908Srafael.vanoni@sun.com 	} else {
2069908Srafael.vanoni@sun.com 		(void) printf("\n\nPowerTOP cannot run in such a small "
2079908Srafael.vanoni@sun.com 		    "terminal window, please resize it.\n\n");
2089908Srafael.vanoni@sun.com 		exit(EXIT_FAILURE);
2099908Srafael.vanoni@sun.com 	}
2109338Srafael.vanoni@sun.com 
2119338Srafael.vanoni@sun.com 	pos_y += event_lines + NEXT_LINE;
2129908Srafael.vanoni@sun.com 	sw[SW_SUGG] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
2139338Srafael.vanoni@sun.com 
2149338Srafael.vanoni@sun.com 	pos_y += BLANK_LINE + NEXT_LINE;
2159908Srafael.vanoni@sun.com 	sw[SW_STATUS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
2169908Srafael.vanoni@sun.com 
2179908Srafael.vanoni@sun.com 	if (!resized) {
2189908Srafael.vanoni@sun.com 		status_bar = NULL;
2199338Srafael.vanoni@sun.com 
220*11122Srafael.vanoni@sun.com 		pt_display_mod_status_bar("Q - Quit");
221*11122Srafael.vanoni@sun.com 		pt_display_mod_status_bar("R - Refresh");
2229908Srafael.vanoni@sun.com 	}
2239338Srafael.vanoni@sun.com }
2249338Srafael.vanoni@sun.com 
2259908Srafael.vanoni@sun.com /*
2269908Srafael.vanoni@sun.com  * This routine handles all the necessary curses initialization.
2279908Srafael.vanoni@sun.com  */
2289338Srafael.vanoni@sun.com void
pt_display_init_curses(void)2299908Srafael.vanoni@sun.com pt_display_init_curses(void)
2309338Srafael.vanoni@sun.com {
2319338Srafael.vanoni@sun.com 	(void) initscr();
2329908Srafael.vanoni@sun.com 
2339908Srafael.vanoni@sun.com 	(void) atexit(pt_display_cleanup);
2349908Srafael.vanoni@sun.com 
2359908Srafael.vanoni@sun.com 	pt_display_get_size();
2369908Srafael.vanoni@sun.com 
2379338Srafael.vanoni@sun.com 	(void) start_color();
2389338Srafael.vanoni@sun.com 
2399338Srafael.vanoni@sun.com 	/*
2409338Srafael.vanoni@sun.com 	 * Enable keyboard mapping
2419338Srafael.vanoni@sun.com 	 */
2429338Srafael.vanoni@sun.com 	(void) keypad(stdscr, TRUE);
2439338Srafael.vanoni@sun.com 
2449338Srafael.vanoni@sun.com 	/*
2459338Srafael.vanoni@sun.com 	 * Tell curses not to do NL->CR/NL on output
2469338Srafael.vanoni@sun.com 	 */
2479338Srafael.vanoni@sun.com 	(void) nonl();
2489338Srafael.vanoni@sun.com 
2499338Srafael.vanoni@sun.com 	/*
2509338Srafael.vanoni@sun.com 	 * Take input chars one at a time, no wait for \n
2519338Srafael.vanoni@sun.com 	 */
2529338Srafael.vanoni@sun.com 	(void) cbreak();
2539338Srafael.vanoni@sun.com 
2549338Srafael.vanoni@sun.com 	/*
2559338Srafael.vanoni@sun.com 	 * Dont echo input
2569338Srafael.vanoni@sun.com 	 */
2579338Srafael.vanoni@sun.com 	(void) noecho();
2589338Srafael.vanoni@sun.com 
2599338Srafael.vanoni@sun.com 	/*
2609338Srafael.vanoni@sun.com 	 * Turn off cursor
2619338Srafael.vanoni@sun.com 	 */
2629338Srafael.vanoni@sun.com 	(void) curs_set(0);
2639338Srafael.vanoni@sun.com 
2649338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
2659338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
2669338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
2679338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
2689338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
2699338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
2709338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
2719338Srafael.vanoni@sun.com 	(void) init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
2729908Srafael.vanoni@sun.com }
2739338Srafael.vanoni@sun.com 
2749908Srafael.vanoni@sun.com void
pt_display_update(void)2759908Srafael.vanoni@sun.com pt_display_update(void)
2769908Srafael.vanoni@sun.com {
2779908Srafael.vanoni@sun.com 	(void) doupdate();
2789908Srafael.vanoni@sun.com }
2799908Srafael.vanoni@sun.com 
2809908Srafael.vanoni@sun.com void
pt_display_title_bar(void)2819908Srafael.vanoni@sun.com pt_display_title_bar(void)
2829908Srafael.vanoni@sun.com {
283*11122Srafael.vanoni@sun.com 	char title_pad[10];
2849908Srafael.vanoni@sun.com 
2859908Srafael.vanoni@sun.com 	(void) wattrset(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
2869908Srafael.vanoni@sun.com 	(void) wbkgd(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
2879908Srafael.vanoni@sun.com 	(void) werase(sw[SW_TITLE]);
2889908Srafael.vanoni@sun.com 
2899908Srafael.vanoni@sun.com 	(void) snprintf(title_pad, 10, "%%%ds",
2909908Srafael.vanoni@sun.com 	    (win_cols - strlen(TITLE))/2 + strlen(TITLE));
2919908Srafael.vanoni@sun.com 
2929908Srafael.vanoni@sun.com 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
2939908Srafael.vanoni@sun.com 	print(sw[SW_TITLE], 0, 0, title_pad, TITLE);
2949908Srafael.vanoni@sun.com 
2959908Srafael.vanoni@sun.com 	(void) wnoutrefresh(sw[SW_TITLE]);
2969338Srafael.vanoni@sun.com }
2979338Srafael.vanoni@sun.com 
2989338Srafael.vanoni@sun.com void
pt_display_status_bar(void)2999908Srafael.vanoni@sun.com pt_display_status_bar(void)
3009338Srafael.vanoni@sun.com {
3019908Srafael.vanoni@sun.com 	sb_slot_t *n = status_bar;
3029908Srafael.vanoni@sun.com 	int x = 0;
3039908Srafael.vanoni@sun.com 
3049908Srafael.vanoni@sun.com 	(void) werase(sw[SW_STATUS]);
3059908Srafael.vanoni@sun.com 
3069908Srafael.vanoni@sun.com 	while (n && x < win_cols) {
3079908Srafael.vanoni@sun.com 		(void) wattron(sw[SW_STATUS], A_REVERSE);
3089908Srafael.vanoni@sun.com 		print(sw[SW_STATUS], 0, x, "%s", n->msg);
3099908Srafael.vanoni@sun.com 		(void) wattroff(sw[SW_STATUS], A_REVERSE);
3109908Srafael.vanoni@sun.com 		x += strlen(n->msg) + 1;
3119908Srafael.vanoni@sun.com 
3129908Srafael.vanoni@sun.com 		n = n->next;
3139908Srafael.vanoni@sun.com 	}
3149908Srafael.vanoni@sun.com 
3159908Srafael.vanoni@sun.com 	(void) wnoutrefresh(sw[SW_STATUS]);
3169908Srafael.vanoni@sun.com }
3179338Srafael.vanoni@sun.com 
3189908Srafael.vanoni@sun.com /*
3199908Srafael.vanoni@sun.com  * Adds or removes items to the status bar automatically.
3209908Srafael.vanoni@sun.com  * Only one instance of an item allowed.
3219908Srafael.vanoni@sun.com  */
3229908Srafael.vanoni@sun.com void
pt_display_mod_status_bar(char * msg)3239908Srafael.vanoni@sun.com pt_display_mod_status_bar(char *msg)
3249908Srafael.vanoni@sun.com {
3259908Srafael.vanoni@sun.com 	sb_slot_t *new, *n;
3269908Srafael.vanoni@sun.com 	boolean_t found = B_FALSE, first = B_FALSE;
3279908Srafael.vanoni@sun.com 
3289908Srafael.vanoni@sun.com 	if (msg == NULL) {
329*11122Srafael.vanoni@sun.com 		pt_error("can't add an empty status bar item\n");
3309908Srafael.vanoni@sun.com 		return;
3319908Srafael.vanoni@sun.com 	}
3329908Srafael.vanoni@sun.com 
3339908Srafael.vanoni@sun.com 	if (status_bar != NULL) {
3349908Srafael.vanoni@sun.com 		/*
3359908Srafael.vanoni@sun.com 		 * Non-empty status bar. Look for an entry matching this msg.
3369908Srafael.vanoni@sun.com 		 */
3379908Srafael.vanoni@sun.com 		for (n = status_bar; n != NULL; n = n->next) {
3389908Srafael.vanoni@sun.com 
3399908Srafael.vanoni@sun.com 			if (strcmp(msg, n->msg) == 0) {
3409908Srafael.vanoni@sun.com 				if (n != status_bar)
3419908Srafael.vanoni@sun.com 					n->prev->next = n->next;
3429908Srafael.vanoni@sun.com 				else
3439908Srafael.vanoni@sun.com 					first = B_TRUE;
3449338Srafael.vanoni@sun.com 
3459908Srafael.vanoni@sun.com 				if (n->next != NULL) {
3469908Srafael.vanoni@sun.com 					n->next->prev = n->prev;
3479908Srafael.vanoni@sun.com 					if (first)
3489908Srafael.vanoni@sun.com 						status_bar = n->next;
3499908Srafael.vanoni@sun.com 				} else {
3509908Srafael.vanoni@sun.com 					if (first)
3519908Srafael.vanoni@sun.com 						status_bar = NULL;
3529908Srafael.vanoni@sun.com 				}
3539338Srafael.vanoni@sun.com 
3549908Srafael.vanoni@sun.com 				free(n);
3559908Srafael.vanoni@sun.com 				found = B_TRUE;
3569908Srafael.vanoni@sun.com 			}
3579908Srafael.vanoni@sun.com 		}
3589338Srafael.vanoni@sun.com 
3599908Srafael.vanoni@sun.com 		/*
3609908Srafael.vanoni@sun.com 		 * Found and removed at least one occurrance of msg, refresh
3619908Srafael.vanoni@sun.com 		 * the bar and return.
3629908Srafael.vanoni@sun.com 		 */
3639908Srafael.vanoni@sun.com 		if (found) {
3649908Srafael.vanoni@sun.com 			return;
3659908Srafael.vanoni@sun.com 		} else {
3669908Srafael.vanoni@sun.com 			/*
3679908Srafael.vanoni@sun.com 			 * Inserting a new msg, walk to the end of the bar.
3689908Srafael.vanoni@sun.com 			 */
3699908Srafael.vanoni@sun.com 			for (n = status_bar; n->next != NULL; n = n->next)
3709908Srafael.vanoni@sun.com 				;
3719908Srafael.vanoni@sun.com 		}
3729338Srafael.vanoni@sun.com 	}
3739908Srafael.vanoni@sun.com 
3749908Srafael.vanoni@sun.com 	if ((new = calloc(1, sizeof (sb_slot_t))) == NULL) {
375*11122Srafael.vanoni@sun.com 		pt_error("failed to allocate a new status bar slot\n");
3769908Srafael.vanoni@sun.com 	} else {
3779908Srafael.vanoni@sun.com 		new->msg = strdup(msg);
3789908Srafael.vanoni@sun.com 
3799908Srafael.vanoni@sun.com 		/*
3809908Srafael.vanoni@sun.com 		 * Check if it's the first entry.
3819908Srafael.vanoni@sun.com 		 */
3829908Srafael.vanoni@sun.com 		if (status_bar == NULL) {
3839908Srafael.vanoni@sun.com 			status_bar = new;
3849908Srafael.vanoni@sun.com 			new->prev = NULL;
3859908Srafael.vanoni@sun.com 		} else {
3869908Srafael.vanoni@sun.com 			new->prev = n;
3879908Srafael.vanoni@sun.com 			n->next = new;
3889908Srafael.vanoni@sun.com 		}
3899908Srafael.vanoni@sun.com 		new->next = NULL;
3909908Srafael.vanoni@sun.com 	}
3919338Srafael.vanoni@sun.com }
3929338Srafael.vanoni@sun.com 
3939338Srafael.vanoni@sun.com void
pt_display_states(void)3949908Srafael.vanoni@sun.com pt_display_states(void)
3959338Srafael.vanoni@sun.com {
3969338Srafael.vanoni@sun.com 	char		c[100];
3979338Srafael.vanoni@sun.com 	int		i;
3989338Srafael.vanoni@sun.com 	double		total_pstates = 0.0, avg, res;
3999338Srafael.vanoni@sun.com 	uint64_t	p0_speed, p1_speed;
4009338Srafael.vanoni@sun.com 
4019908Srafael.vanoni@sun.com 	print(sw[SW_IDLE], 0, 0, "%s\tAvg\tResidency\n", g_msg_idle_state);
4029908Srafael.vanoni@sun.com 
4039908Srafael.vanoni@sun.com 	if (g_features & FEATURE_CSTATE) {
4049908Srafael.vanoni@sun.com 		res =  (((double)g_cstate_info[0].total_time / g_total_c_time))
4059908Srafael.vanoni@sun.com 		    * 100;
4069908Srafael.vanoni@sun.com 		(void) sprintf(c, "C0 (cpu running)\t\t(%.1f%%)\n", (float)res);
4079908Srafael.vanoni@sun.com 		print(sw[SW_IDLE], 1, 0, "%s", c);
4089908Srafael.vanoni@sun.com 
4099908Srafael.vanoni@sun.com 		for (i = 1; i <= g_max_cstate; i++) {
4109908Srafael.vanoni@sun.com 			/*
4119908Srafael.vanoni@sun.com 			 * In situations where the load is too intensive, the
4129908Srafael.vanoni@sun.com 			 * system might not transition at all.
4139908Srafael.vanoni@sun.com 			 */
4149908Srafael.vanoni@sun.com 			if (g_cstate_info[i].events > 0)
4159908Srafael.vanoni@sun.com 				avg = (((double)g_cstate_info[i].total_time/
4169908Srafael.vanoni@sun.com 				    MICROSEC)/g_cstate_info[i].events);
4179908Srafael.vanoni@sun.com 			else
4189908Srafael.vanoni@sun.com 				avg = 0;
4199908Srafael.vanoni@sun.com 
4209908Srafael.vanoni@sun.com 			res = ((double)g_cstate_info[i].total_time/
4219908Srafael.vanoni@sun.com 			    g_total_c_time) * 100;
4229908Srafael.vanoni@sun.com 
4239908Srafael.vanoni@sun.com 			(void) sprintf(c, "C%d\t\t\t%.1fms\t(%.1f%%)\n",
4249908Srafael.vanoni@sun.com 			    i, (float)avg, (float)res);
4259908Srafael.vanoni@sun.com 			print(sw[SW_IDLE], i + 1, 0, "%s", c);
4269908Srafael.vanoni@sun.com 		}
4279338Srafael.vanoni@sun.com 	}
4289338Srafael.vanoni@sun.com 
4299908Srafael.vanoni@sun.com 	if (!PT_ON_DUMP)
4309908Srafael.vanoni@sun.com 		(void) wnoutrefresh(sw[SW_IDLE]);
4319338Srafael.vanoni@sun.com 
4329908Srafael.vanoni@sun.com 	print(sw[SW_FREQ], 0, 0, "%s\n", g_msg_freq_state);
4339338Srafael.vanoni@sun.com 
4349908Srafael.vanoni@sun.com 	if (g_features & FEATURE_PSTATE) {
4359338Srafael.vanoni@sun.com 		for (i = 0; i < g_npstates; i++) {
4369908Srafael.vanoni@sun.com 			total_pstates +=
4379908Srafael.vanoni@sun.com 			    (double)(g_pstate_info[i].total_time/
4389711Srafael.vanoni@sun.com 			    g_ncpus_observed/MICROSEC);
4399338Srafael.vanoni@sun.com 		}
4409338Srafael.vanoni@sun.com 
4419338Srafael.vanoni@sun.com 		/*
4429338Srafael.vanoni@sun.com 		 * display ACPI_PSTATE from P(n) to P(1)
4439338Srafael.vanoni@sun.com 		 */
4449338Srafael.vanoni@sun.com 		for (i = 0;  i < g_npstates - 1; i++) {
4459338Srafael.vanoni@sun.com 			(void) sprintf(c, "%4lu Mhz\t%.1f%%",
4469338Srafael.vanoni@sun.com 			    (long)g_pstate_info[i].speed,
4479908Srafael.vanoni@sun.com 			    100 * (g_pstate_info[i].total_time/
4489908Srafael.vanoni@sun.com 			    g_ncpus_observed/MICROSEC/total_pstates));
4499908Srafael.vanoni@sun.com 			print(sw[SW_FREQ], i+1, 0, "%s\n", c);
4509338Srafael.vanoni@sun.com 		}
4519338Srafael.vanoni@sun.com 
4529338Srafael.vanoni@sun.com 		/*
4539338Srafael.vanoni@sun.com 		 * Display ACPI_PSTATE P0 according to if turbo
4549338Srafael.vanoni@sun.com 		 * mode is supported
4559338Srafael.vanoni@sun.com 		 */
4569338Srafael.vanoni@sun.com 		if (g_turbo_supported) {
4579338Srafael.vanoni@sun.com 			p1_speed = g_pstate_info[g_npstates - 2].speed;
4589338Srafael.vanoni@sun.com 
4599338Srafael.vanoni@sun.com 			/*
4609338Srafael.vanoni@sun.com 			 * If g_turbo_ratio <= 1.0, it will be ignored.
4619338Srafael.vanoni@sun.com 			 * we display P(0) as P(1) + 1.
4629338Srafael.vanoni@sun.com 			 */
4639338Srafael.vanoni@sun.com 			if (g_turbo_ratio <= 1.0) {
4649338Srafael.vanoni@sun.com 				p0_speed = p1_speed + 1;
4659338Srafael.vanoni@sun.com 			} else {
4669338Srafael.vanoni@sun.com 				/*
4679908Srafael.vanoni@sun.com 				 * If g_turbo_ratio > 1.0, that means
4689908Srafael.vanoni@sun.com 				 * turbo mode works. So, P(0) = ratio *
4699908Srafael.vanoni@sun.com 				 *  P(1);
4709338Srafael.vanoni@sun.com 				 */
4719908Srafael.vanoni@sun.com 				p0_speed = (uint64_t)(p1_speed *
4729908Srafael.vanoni@sun.com 				    g_turbo_ratio);
4739338Srafael.vanoni@sun.com 				if (p0_speed < (p1_speed + 1))
4749908Srafael.vanoni@sun.com 					p0_speed = p1_speed + 1;
4759338Srafael.vanoni@sun.com 			}
4769338Srafael.vanoni@sun.com 			/*
4779338Srafael.vanoni@sun.com 			 * Reset the ratio for the next round
4789338Srafael.vanoni@sun.com 			 */
4799338Srafael.vanoni@sun.com 			g_turbo_ratio = 0.0;
4809338Srafael.vanoni@sun.com 
4819338Srafael.vanoni@sun.com 			/*
4829338Srafael.vanoni@sun.com 			 * Setup the string for the display
4839338Srafael.vanoni@sun.com 			 */
4849338Srafael.vanoni@sun.com 			(void) sprintf(c, "%4lu Mhz(turbo)\t%.1f%%",
4859338Srafael.vanoni@sun.com 			    (long)p0_speed,
4869338Srafael.vanoni@sun.com 			    100 * (g_pstate_info[i].total_time/
4879711Srafael.vanoni@sun.com 			    g_ncpus_observed/MICROSEC/total_pstates));
4889338Srafael.vanoni@sun.com 		} else {
4899338Srafael.vanoni@sun.com 			(void) sprintf(c, "%4lu Mhz\t%.1f%%",
4909338Srafael.vanoni@sun.com 			    (long)g_pstate_info[i].speed,
4919338Srafael.vanoni@sun.com 			    100 * (g_pstate_info[i].total_time/
4929711Srafael.vanoni@sun.com 			    g_ncpus_observed/MICROSEC/total_pstates));
4939338Srafael.vanoni@sun.com 		}
4949908Srafael.vanoni@sun.com 		print(sw[SW_FREQ], i+1, 0, "%s\n", c);
4959908Srafael.vanoni@sun.com 	} else {
4969908Srafael.vanoni@sun.com 		if (g_npstates == 1) {
4979908Srafael.vanoni@sun.com 			(void) sprintf(c, "%4lu Mhz\t%.1f%%",
4989908Srafael.vanoni@sun.com 			    (long)g_pstate_info[0].speed, 100.0);
4999908Srafael.vanoni@sun.com 			print(sw[SW_FREQ], 1, 0, "%s\n", c);
5009908Srafael.vanoni@sun.com 		}
5019338Srafael.vanoni@sun.com 	}
5029338Srafael.vanoni@sun.com 
5039711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP)
5049908Srafael.vanoni@sun.com 		(void) wnoutrefresh(sw[SW_FREQ]);
5059338Srafael.vanoni@sun.com }
5069338Srafael.vanoni@sun.com 
5079338Srafael.vanoni@sun.com void
pt_display_acpi_power(uint32_t flag,double rate,double rem_cap,double cap,uint32_t state)5089908Srafael.vanoni@sun.com pt_display_acpi_power(uint32_t flag, double rate, double rem_cap, double cap,
5099338Srafael.vanoni@sun.com     uint32_t state)
5109338Srafael.vanoni@sun.com {
5119338Srafael.vanoni@sun.com 	char	buffer[1024];
5129338Srafael.vanoni@sun.com 
513*11122Srafael.vanoni@sun.com 	(void) sprintf(buffer, "no ACPI power usage estimate available");
5149338Srafael.vanoni@sun.com 
5159711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP)
5169908Srafael.vanoni@sun.com 		(void) werase(sw[SW_POWER]);
5179908Srafael.vanoni@sun.com 
5189338Srafael.vanoni@sun.com 	if (flag) {
5199338Srafael.vanoni@sun.com 		char *c;
5209338Srafael.vanoni@sun.com 		(void) sprintf(buffer, "Power usage (ACPI estimate): %.3fW",
5219338Srafael.vanoni@sun.com 		    rate);
5229338Srafael.vanoni@sun.com 		(void) strcat(buffer, " ");
5239338Srafael.vanoni@sun.com 		c = &buffer[strlen(buffer)];
5249338Srafael.vanoni@sun.com 		switch (state) {
5259338Srafael.vanoni@sun.com 		case 0:
5269338Srafael.vanoni@sun.com 			(void) sprintf(c, "(running on AC power, fully "
5279338Srafael.vanoni@sun.com 			    "charged)");
5289338Srafael.vanoni@sun.com 			break;
5299338Srafael.vanoni@sun.com 		case 1:
5309338Srafael.vanoni@sun.com 			(void) sprintf(c, "(discharging: %3.1f hours)",
5319338Srafael.vanoni@sun.com 			    (uint32_t)rem_cap/rate);
5329338Srafael.vanoni@sun.com 			break;
5339338Srafael.vanoni@sun.com 		case 2:
5349338Srafael.vanoni@sun.com 			(void) sprintf(c, "(charging: %3.1f hours)",
5359338Srafael.vanoni@sun.com 			    (uint32_t)(cap - rem_cap)/rate);
5369338Srafael.vanoni@sun.com 			break;
5379338Srafael.vanoni@sun.com 		case 4:
5389338Srafael.vanoni@sun.com 			(void) sprintf(c, "(##critically low battery power##)");
5399338Srafael.vanoni@sun.com 			break;
5409338Srafael.vanoni@sun.com 		}
5419338Srafael.vanoni@sun.com 
5429338Srafael.vanoni@sun.com 	}
5439908Srafael.vanoni@sun.com 
5449908Srafael.vanoni@sun.com 	print(sw[SW_POWER], 0, 0, "%s\n", buffer);
5459711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP)
5469908Srafael.vanoni@sun.com 		(void) wnoutrefresh(sw[SW_POWER]);
5479338Srafael.vanoni@sun.com }
5489338Srafael.vanoni@sun.com 
5499338Srafael.vanoni@sun.com void
pt_display_wakeups(double interval)5509908Srafael.vanoni@sun.com pt_display_wakeups(double interval)
5519338Srafael.vanoni@sun.com {
5529338Srafael.vanoni@sun.com 	char		c[100];
5539338Srafael.vanoni@sun.com 	int		i, event_sum = 0;
5549711Srafael.vanoni@sun.com 	event_info_t	*event = g_event_info;
5559338Srafael.vanoni@sun.com 
5569711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP) {
5579908Srafael.vanoni@sun.com 		(void) werase(sw[SW_WAKEUPS]);
5589908Srafael.vanoni@sun.com 		(void) wbkgd(sw[SW_WAKEUPS], COLOR_PAIR(PT_COLOR_RED));
5599908Srafael.vanoni@sun.com 		(void) wattron(sw[SW_WAKEUPS], A_BOLD);
5609338Srafael.vanoni@sun.com 	}
5619338Srafael.vanoni@sun.com 
5629338Srafael.vanoni@sun.com 	/*
5639338Srafael.vanoni@sun.com 	 * calculate the actual total event number
5649338Srafael.vanoni@sun.com 	 */
5659711Srafael.vanoni@sun.com 	for (i = 0; i < g_top_events; i++, event++)
5669711Srafael.vanoni@sun.com 		event_sum += event->total_count;
5679338Srafael.vanoni@sun.com 
5689338Srafael.vanoni@sun.com 	/*
5699338Srafael.vanoni@sun.com 	 * g_total_events is the sum of the number of Cx->C0 transition,
5709338Srafael.vanoni@sun.com 	 * So when the system is very busy, the idle thread will have no
5719338Srafael.vanoni@sun.com 	 * chance or very seldom to be scheduled, this could cause >100%
5729338Srafael.vanoni@sun.com 	 * event report. Re-assign g_total_events to the actual event
5739338Srafael.vanoni@sun.com 	 * number is a way to avoid this issue.
5749338Srafael.vanoni@sun.com 	 */
5759338Srafael.vanoni@sun.com 	if (event_sum > g_total_events)
5769338Srafael.vanoni@sun.com 		g_total_events = event_sum;
5779338Srafael.vanoni@sun.com 
5789338Srafael.vanoni@sun.com 	(void) sprintf(c, "Wakeups-from-idle per second: %4.1f\tinterval: "
5799338Srafael.vanoni@sun.com 	    "%.1fs", (double)(g_total_events/interval), interval);
5809908Srafael.vanoni@sun.com 	print(sw[SW_WAKEUPS], 0, 0, "%s\n", c);
5819338Srafael.vanoni@sun.com 
5829711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP)
5839908Srafael.vanoni@sun.com 		(void) wnoutrefresh(sw[SW_WAKEUPS]);
5849338Srafael.vanoni@sun.com }
5859338Srafael.vanoni@sun.com 
5869338Srafael.vanoni@sun.com void
pt_display_events(double interval)5879908Srafael.vanoni@sun.com pt_display_events(double interval)
5889338Srafael.vanoni@sun.com {
5899338Srafael.vanoni@sun.com 	char		c[100];
5909338Srafael.vanoni@sun.com 	int		i;
5919338Srafael.vanoni@sun.com 	double		events;
5929711Srafael.vanoni@sun.com 	event_info_t	*event = g_event_info;
5939338Srafael.vanoni@sun.com 
5949711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP) {
5959908Srafael.vanoni@sun.com 		(void) werase(sw[SW_EVENTS]);
5969908Srafael.vanoni@sun.com 		(void) wbkgd(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
5979908Srafael.vanoni@sun.com 		(void) wattron(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
5989338Srafael.vanoni@sun.com 	}
5999338Srafael.vanoni@sun.com 
6009338Srafael.vanoni@sun.com 	/*
6019338Srafael.vanoni@sun.com 	 * Sort the event report list
6029338Srafael.vanoni@sun.com 	 */
6039711Srafael.vanoni@sun.com 	if (g_top_events > EVENT_NUM_MAX)
6049711Srafael.vanoni@sun.com 		g_top_events = EVENT_NUM_MAX;
6059338Srafael.vanoni@sun.com 
6069711Srafael.vanoni@sun.com 	qsort((void *)g_event_info, g_top_events, sizeof (event_info_t),
607*11122Srafael.vanoni@sun.com 	    pt_event_compare);
6089338Srafael.vanoni@sun.com 
6099711Srafael.vanoni@sun.com 	if (PT_ON_CPU)
6109338Srafael.vanoni@sun.com 		(void) sprintf(c, "Top causes for wakeups on CPU %d:\n",
6119338Srafael.vanoni@sun.com 		    g_observed_cpu);
6129338Srafael.vanoni@sun.com 	else
6139338Srafael.vanoni@sun.com 		(void) sprintf(c, "Top causes for wakeups:\n");
6149338Srafael.vanoni@sun.com 
6159908Srafael.vanoni@sun.com 	print(sw[SW_EVENTS], 0, 0, "%s", c);
6169338Srafael.vanoni@sun.com 
6179711Srafael.vanoni@sun.com 	for (i = 0; i < g_top_events; i++, event++) {
6189338Srafael.vanoni@sun.com 
6199711Srafael.vanoni@sun.com 		if (g_total_events > 0 && event->total_count > 0)
6209711Srafael.vanoni@sun.com 			events = (double)event->total_count/
6219338Srafael.vanoni@sun.com 			    (double)g_total_events;
6229338Srafael.vanoni@sun.com 		else
6239338Srafael.vanoni@sun.com 			continue;
6249338Srafael.vanoni@sun.com 
6259338Srafael.vanoni@sun.com 		(void) sprintf(c, "%4.1f%% (%5.1f)", 100 * events,
6269711Srafael.vanoni@sun.com 		    (double)event->total_count/interval);
6279908Srafael.vanoni@sun.com 		print(sw[SW_EVENTS], i+1, 0, "%s", c);
6289908Srafael.vanoni@sun.com 		print(sw[SW_EVENTS], i+1, 16, "%20s :",
6299711Srafael.vanoni@sun.com 		    event->offender_name);
6309908Srafael.vanoni@sun.com 		print(sw[SW_EVENTS], i+1, 40, "%-64s\n",
6319711Srafael.vanoni@sun.com 		    event->offense_name);
6329338Srafael.vanoni@sun.com 	}
6339338Srafael.vanoni@sun.com 
6349711Srafael.vanoni@sun.com 	if (!PT_ON_DUMP)
6359908Srafael.vanoni@sun.com 		(void) wnoutrefresh(sw[SW_EVENTS]);
6369338Srafael.vanoni@sun.com }
6379338Srafael.vanoni@sun.com 
6389338Srafael.vanoni@sun.com void
pt_display_suggestions(char * sug)6399908Srafael.vanoni@sun.com pt_display_suggestions(char *sug)
6409338Srafael.vanoni@sun.com {
6419908Srafael.vanoni@sun.com 	(void) werase(sw[SW_SUGG]);
6429908Srafael.vanoni@sun.com 
6439908Srafael.vanoni@sun.com 	if (sug != NULL)
6449908Srafael.vanoni@sun.com 		print(sw[SW_SUGG], 0, 0, "%s", sug);
6459908Srafael.vanoni@sun.com 
6469908Srafael.vanoni@sun.com 	(void) wnoutrefresh(sw[SW_SUGG]);
6479338Srafael.vanoni@sun.com }
648