xref: /titanic_44/usr/src/cmd/powertop/common/display.c (revision 9bbf5ba14ae201f78f3d6b47a9fac96d68649275)
1b47b5b34SRafael Vanoni /*
2b47b5b34SRafael Vanoni  * Copyright 2009, Intel Corporation
3b47b5b34SRafael Vanoni  * Copyright 2009, Sun Microsystems, Inc
4b47b5b34SRafael Vanoni  *
5b47b5b34SRafael Vanoni  * This file is part of PowerTOP
6b47b5b34SRafael Vanoni  *
7b47b5b34SRafael Vanoni  * This program file is free software; you can redistribute it and/or modify it
8b47b5b34SRafael Vanoni  * under the terms of the GNU General Public License as published by the
9b47b5b34SRafael Vanoni  * Free Software Foundation; version 2 of the License.
10b47b5b34SRafael Vanoni  *
11b47b5b34SRafael Vanoni  * This program is distributed in the hope that it will be useful, but WITHOUT
12b47b5b34SRafael Vanoni  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13b47b5b34SRafael Vanoni  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14b47b5b34SRafael Vanoni  * for more details.
15b47b5b34SRafael Vanoni  *
16b47b5b34SRafael Vanoni  * You should have received a copy of the GNU General Public License
17b47b5b34SRafael Vanoni  * along with this program in a file named COPYING; if not, write to the
18b47b5b34SRafael Vanoni  * Free Software Foundation, Inc.,
19b47b5b34SRafael Vanoni  * 51 Franklin Street, Fifth Floor,
20b47b5b34SRafael Vanoni  * Boston, MA 02110-1301 USA
21b47b5b34SRafael Vanoni  *
22b47b5b34SRafael Vanoni  * Authors:
23b47b5b34SRafael Vanoni  *	Arjan van de Ven <arjan@linux.intel.com>
24b47b5b34SRafael Vanoni  *	Eric C Saxe <eric.saxe@sun.com>
25b47b5b34SRafael Vanoni  *	Aubrey Li <aubrey.li@intel.com>
26b47b5b34SRafael Vanoni  */
27b47b5b34SRafael Vanoni 
28b47b5b34SRafael Vanoni /*
29b47b5b34SRafael Vanoni  * GPL Disclaimer
30b47b5b34SRafael Vanoni  *
31b47b5b34SRafael Vanoni  * For the avoidance of doubt, except that if any license choice other
32b47b5b34SRafael Vanoni  * than GPL or LGPL is available it will apply instead, Sun elects to
33b47b5b34SRafael Vanoni  * use only the General Public License version 2 (GPLv2) at this time
34b47b5b34SRafael Vanoni  * for any software where a choice of GPL license versions is made
35b47b5b34SRafael Vanoni  * available with the language indicating that GPLv2 or any later
36b47b5b34SRafael Vanoni  * version may be used, or where a choice of which version of the GPL
37b47b5b34SRafael Vanoni  * is applied is otherwise unspecified.
38b47b5b34SRafael Vanoni  */
39b47b5b34SRafael Vanoni 
40b47b5b34SRafael Vanoni #include <stdlib.h>
41b47b5b34SRafael Vanoni #include <string.h>
42*9bbf5ba1SRafael Vanoni #include <unistd.h>
43b47b5b34SRafael Vanoni #include <curses.h>
44*9bbf5ba1SRafael Vanoni #include <signal.h>
45*9bbf5ba1SRafael Vanoni #include <fcntl.h>
46b47b5b34SRafael Vanoni #include "powertop.h"
47b47b5b34SRafael Vanoni 
48*9bbf5ba1SRafael Vanoni /*
49*9bbf5ba1SRafael Vanoni  * Minimum terminal height and width to run PowerTOP on curses mode.
50*9bbf5ba1SRafael Vanoni  */
51*9bbf5ba1SRafael Vanoni #define	PT_MIN_COLS		70
52*9bbf5ba1SRafael Vanoni #define	PT_MIN_ROWS		15
53*9bbf5ba1SRafael Vanoni 
54*9bbf5ba1SRafael Vanoni /*
55*9bbf5ba1SRafael Vanoni  * Display colors
56*9bbf5ba1SRafael Vanoni  */
57*9bbf5ba1SRafael Vanoni #define	PT_COLOR_DEFAULT	1
58*9bbf5ba1SRafael Vanoni #define	PT_COLOR_HEADER_BAR	2
59*9bbf5ba1SRafael Vanoni #define	PT_COLOR_ERROR		3
60*9bbf5ba1SRafael Vanoni #define	PT_COLOR_RED		4
61*9bbf5ba1SRafael Vanoni #define	PT_COLOR_YELLOW		5
62*9bbf5ba1SRafael Vanoni #define	PT_COLOR_GREEN		6
63*9bbf5ba1SRafael Vanoni #define	PT_COLOR_BRIGHT		7
64*9bbf5ba1SRafael Vanoni #define	PT_COLOR_BLUE		8
65*9bbf5ba1SRafael Vanoni 
66*9bbf5ba1SRafael Vanoni /*
67*9bbf5ba1SRafael Vanoni  * Constants for pt_display_setup()
68*9bbf5ba1SRafael Vanoni  */
69*9bbf5ba1SRafael Vanoni #define	SINGLE_LINE_SW 		1
70*9bbf5ba1SRafael Vanoni #define	LENGTH_SUGG_SW		2
71*9bbf5ba1SRafael Vanoni #define	TITLE_LINE		1
72*9bbf5ba1SRafael Vanoni #define	BLANK_LINE		1
73*9bbf5ba1SRafael Vanoni #define	NEXT_LINE		1
74b47b5b34SRafael Vanoni 
75b47b5b34SRafael Vanoni #define	print(win, y, x, fmt, args...)				\
76636423dbSRafael Vanoni 	if (PT_ON_DUMP)						\
77b47b5b34SRafael Vanoni 		(void) printf(fmt, ## args);			\
78b47b5b34SRafael Vanoni 	else							\
79b47b5b34SRafael Vanoni 		(void) mvwprintw(win, y, x, fmt, ## args);
80b47b5b34SRafael Vanoni 
81*9bbf5ba1SRafael Vanoni enum pt_subwindows {
82*9bbf5ba1SRafael Vanoni 	SW_TITLE,
83*9bbf5ba1SRafael Vanoni 	SW_IDLE,
84*9bbf5ba1SRafael Vanoni 	SW_FREQ,
85*9bbf5ba1SRafael Vanoni 	SW_WAKEUPS,
86*9bbf5ba1SRafael Vanoni 	SW_POWER,
87*9bbf5ba1SRafael Vanoni 	SW_EVENTS,
88*9bbf5ba1SRafael Vanoni 	SW_SUGG,
89*9bbf5ba1SRafael Vanoni 	SW_STATUS,
90*9bbf5ba1SRafael Vanoni 	SW_COUNT
91*9bbf5ba1SRafael Vanoni };
92b47b5b34SRafael Vanoni 
93*9bbf5ba1SRafael Vanoni typedef struct sb_slot {
94*9bbf5ba1SRafael Vanoni 	char *msg;
95*9bbf5ba1SRafael Vanoni 	struct sb_slot *prev;
96*9bbf5ba1SRafael Vanoni 	struct sb_slot *next;
97*9bbf5ba1SRafael Vanoni } sb_slot_t;
98*9bbf5ba1SRafael Vanoni 
99*9bbf5ba1SRafael Vanoni static WINDOW *sw[SW_COUNT];
100*9bbf5ba1SRafael Vanoni static int win_cols, win_rows;
101*9bbf5ba1SRafael Vanoni static sb_slot_t *status_bar;
102b47b5b34SRafael Vanoni 
103b47b5b34SRafael Vanoni static void
104*9bbf5ba1SRafael Vanoni pt_display_cleanup(void)
105b47b5b34SRafael Vanoni {
106*9bbf5ba1SRafael Vanoni 	(void) endwin();
107b47b5b34SRafael Vanoni }
108*9bbf5ba1SRafael Vanoni 
109*9bbf5ba1SRafael Vanoni static void
110*9bbf5ba1SRafael Vanoni pt_display_get_size(void)
111*9bbf5ba1SRafael Vanoni {
112*9bbf5ba1SRafael Vanoni 	getmaxyx(stdscr, win_rows, win_cols);
113*9bbf5ba1SRafael Vanoni 
114*9bbf5ba1SRafael Vanoni 	if (win_rows < PT_MIN_ROWS || win_cols < PT_MIN_COLS) {
115*9bbf5ba1SRafael Vanoni 		pt_display_cleanup();
116*9bbf5ba1SRafael Vanoni 		(void) printf("\n\nPowerTOP cannot run in such a small "
117*9bbf5ba1SRafael Vanoni 		    "terminal window. Please resize it.\n\n");
118*9bbf5ba1SRafael Vanoni 		exit(EXIT_FAILURE);
119b47b5b34SRafael Vanoni 	}
120b47b5b34SRafael Vanoni }
121b47b5b34SRafael Vanoni 
122*9bbf5ba1SRafael Vanoni /*
123*9bbf5ba1SRafael Vanoni  * Signal handler, currently only used for window resizing.
124*9bbf5ba1SRafael Vanoni  */
125*9bbf5ba1SRafael Vanoni static void
126*9bbf5ba1SRafael Vanoni pt_display_resize(int sig)
127b47b5b34SRafael Vanoni {
128*9bbf5ba1SRafael Vanoni 	int i;
129*9bbf5ba1SRafael Vanoni 
130*9bbf5ba1SRafael Vanoni 	switch (sig) {
131*9bbf5ba1SRafael Vanoni 	case SIGWINCH:
132*9bbf5ba1SRafael Vanoni 		for (i = 0; i < SW_COUNT; i++)
133*9bbf5ba1SRafael Vanoni 			if (sw[i] != NULL) {
134*9bbf5ba1SRafael Vanoni 				(void) delwin(sw[i]);
135*9bbf5ba1SRafael Vanoni 				sw[i] = NULL;
136*9bbf5ba1SRafael Vanoni 			}
137*9bbf5ba1SRafael Vanoni 
138*9bbf5ba1SRafael Vanoni 		pt_display_cleanup();
139*9bbf5ba1SRafael Vanoni 		(void) pt_display_init_curses();
140*9bbf5ba1SRafael Vanoni 		pt_display_setup(B_TRUE);
141*9bbf5ba1SRafael Vanoni 
142*9bbf5ba1SRafael Vanoni 		pt_display_title_bar();
143*9bbf5ba1SRafael Vanoni 
144*9bbf5ba1SRafael Vanoni 		pt_display_update();
145*9bbf5ba1SRafael Vanoni 
146*9bbf5ba1SRafael Vanoni 		break;
147*9bbf5ba1SRafael Vanoni 	}
148b47b5b34SRafael Vanoni }
149b47b5b34SRafael Vanoni 
150b47b5b34SRafael Vanoni /*
151b47b5b34SRafael Vanoni  * This part was re-written to be human readable and easy to modify. Please
152b47b5b34SRafael Vanoni  * try to keep it that way and help us save some time.
153b47b5b34SRafael Vanoni  *
154b47b5b34SRafael Vanoni  * Friendly reminder:
155b47b5b34SRafael Vanoni  * 	subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x)
156b47b5b34SRafael Vanoni  */
157b47b5b34SRafael Vanoni void
158*9bbf5ba1SRafael Vanoni pt_display_setup(boolean_t resized)
159b47b5b34SRafael Vanoni {
160b47b5b34SRafael Vanoni 	/*
161b47b5b34SRafael Vanoni 	 * These variables are used to properly set the initial y position and
162b47b5b34SRafael Vanoni 	 * number of lines in each subwindow, as the number of supported CPU
163b47b5b34SRafael Vanoni 	 * states affects their placement.
164b47b5b34SRafael Vanoni 	 */
165*9bbf5ba1SRafael Vanoni 	int cstate_lines, event_lines, pos_y = 0;
166b47b5b34SRafael Vanoni 
167*9bbf5ba1SRafael Vanoni 	/*
168*9bbf5ba1SRafael Vanoni 	 * In theory, all systems have at least two idle states. We add two here
169*9bbf5ba1SRafael Vanoni 	 * since we have to use DTrace to figure out how many this box has.
170*9bbf5ba1SRafael Vanoni 	 */
171*9bbf5ba1SRafael Vanoni 	cstate_lines = TITLE_LINE + max((g_max_cstate+2), g_npstates);
172b47b5b34SRafael Vanoni 
173*9bbf5ba1SRafael Vanoni 	sw[SW_TITLE] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
174b47b5b34SRafael Vanoni 
175b47b5b34SRafael Vanoni 	pos_y += NEXT_LINE + BLANK_LINE;
176*9bbf5ba1SRafael Vanoni 	sw[SW_IDLE] = subwin(stdscr, cstate_lines, win_cols/2 + 1, pos_y, 0);
177*9bbf5ba1SRafael Vanoni 	sw[SW_FREQ] = subwin(stdscr, cstate_lines, win_cols/2 - 8, pos_y,
178*9bbf5ba1SRafael Vanoni 	    win_cols/2 + 8);
179b47b5b34SRafael Vanoni 
180b47b5b34SRafael Vanoni 	pos_y += cstate_lines + BLANK_LINE;
181*9bbf5ba1SRafael Vanoni 	sw[SW_WAKEUPS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
182b47b5b34SRafael Vanoni 
183b47b5b34SRafael Vanoni 	pos_y += NEXT_LINE;
184*9bbf5ba1SRafael Vanoni 	sw[SW_POWER] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
185b47b5b34SRafael Vanoni 
186b47b5b34SRafael Vanoni 	pos_y += NEXT_LINE + BLANK_LINE;
187*9bbf5ba1SRafael Vanoni 	event_lines = win_rows - SINGLE_LINE_SW - NEXT_LINE - LENGTH_SUGG_SW -
188b47b5b34SRafael Vanoni 	    pos_y;
189b47b5b34SRafael Vanoni 
190*9bbf5ba1SRafael Vanoni 	if (event_lines > 0) {
191*9bbf5ba1SRafael Vanoni 		sw[SW_EVENTS] = subwin(stdscr, event_lines, win_cols, pos_y, 0);
192*9bbf5ba1SRafael Vanoni 	} else {
193*9bbf5ba1SRafael Vanoni 		(void) printf("\n\nPowerTOP cannot run in such a small "
194*9bbf5ba1SRafael Vanoni 		    "terminal window, please resize it.\n\n");
195*9bbf5ba1SRafael Vanoni 		exit(EXIT_FAILURE);
196b47b5b34SRafael Vanoni 	}
197b47b5b34SRafael Vanoni 
198*9bbf5ba1SRafael Vanoni 	pos_y += event_lines + NEXT_LINE;
199*9bbf5ba1SRafael Vanoni 	sw[SW_SUGG] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
200*9bbf5ba1SRafael Vanoni 
201*9bbf5ba1SRafael Vanoni 	pos_y += BLANK_LINE + NEXT_LINE;
202*9bbf5ba1SRafael Vanoni 	sw[SW_STATUS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
203*9bbf5ba1SRafael Vanoni 
204*9bbf5ba1SRafael Vanoni 	if (!resized) {
205*9bbf5ba1SRafael Vanoni 		status_bar = NULL;
206*9bbf5ba1SRafael Vanoni 
207*9bbf5ba1SRafael Vanoni 		pt_display_mod_status_bar(_("Q - Quit"));
208*9bbf5ba1SRafael Vanoni 		pt_display_mod_status_bar(_("R - Refresh"));
209*9bbf5ba1SRafael Vanoni 	}
210*9bbf5ba1SRafael Vanoni 
211*9bbf5ba1SRafael Vanoni 	pt_display_status_bar();
212*9bbf5ba1SRafael Vanoni }
213*9bbf5ba1SRafael Vanoni 
214*9bbf5ba1SRafael Vanoni /*
215*9bbf5ba1SRafael Vanoni  * This routine handles all the necessary curses initialization.
216*9bbf5ba1SRafael Vanoni  */
217b47b5b34SRafael Vanoni void
218*9bbf5ba1SRafael Vanoni pt_display_init_curses(void)
219b47b5b34SRafael Vanoni {
220b47b5b34SRafael Vanoni 	(void) initscr();
221*9bbf5ba1SRafael Vanoni 
222*9bbf5ba1SRafael Vanoni 	(void) atexit(pt_display_cleanup);
223*9bbf5ba1SRafael Vanoni 	(void) signal(SIGWINCH, pt_display_resize);
224*9bbf5ba1SRafael Vanoni 
225*9bbf5ba1SRafael Vanoni 	pt_display_get_size();
226*9bbf5ba1SRafael Vanoni 
227b47b5b34SRafael Vanoni 	(void) start_color();
228b47b5b34SRafael Vanoni 
229b47b5b34SRafael Vanoni 	/*
230b47b5b34SRafael Vanoni 	 * Enable keyboard mapping
231b47b5b34SRafael Vanoni 	 */
232b47b5b34SRafael Vanoni 	(void) keypad(stdscr, TRUE);
233b47b5b34SRafael Vanoni 
234b47b5b34SRafael Vanoni 	/*
235b47b5b34SRafael Vanoni 	 * Tell curses not to do NL->CR/NL on output
236b47b5b34SRafael Vanoni 	 */
237b47b5b34SRafael Vanoni 	(void) nonl();
238b47b5b34SRafael Vanoni 
239b47b5b34SRafael Vanoni 	/*
240b47b5b34SRafael Vanoni 	 * Take input chars one at a time, no wait for \n
241b47b5b34SRafael Vanoni 	 */
242b47b5b34SRafael Vanoni 	(void) cbreak();
243b47b5b34SRafael Vanoni 
244b47b5b34SRafael Vanoni 	/*
245b47b5b34SRafael Vanoni 	 * Dont echo input
246b47b5b34SRafael Vanoni 	 */
247b47b5b34SRafael Vanoni 	(void) noecho();
248b47b5b34SRafael Vanoni 
249b47b5b34SRafael Vanoni 	/*
250b47b5b34SRafael Vanoni 	 * Turn off cursor
251b47b5b34SRafael Vanoni 	 */
252b47b5b34SRafael Vanoni 	(void) curs_set(0);
253b47b5b34SRafael Vanoni 
254b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
255b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
256b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
257b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
258b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
259b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
260b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
261b47b5b34SRafael Vanoni 	(void) init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
262b47b5b34SRafael Vanoni }
263b47b5b34SRafael Vanoni 
264b47b5b34SRafael Vanoni void
265*9bbf5ba1SRafael Vanoni pt_display_update(void)
266b47b5b34SRafael Vanoni {
267*9bbf5ba1SRafael Vanoni 	(void) doupdate();
268*9bbf5ba1SRafael Vanoni }
269*9bbf5ba1SRafael Vanoni 
270*9bbf5ba1SRafael Vanoni void
271*9bbf5ba1SRafael Vanoni pt_display_title_bar(void)
272*9bbf5ba1SRafael Vanoni {
273b47b5b34SRafael Vanoni 	char	title_pad[10];
274b47b5b34SRafael Vanoni 
275*9bbf5ba1SRafael Vanoni 	(void) wattrset(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
276*9bbf5ba1SRafael Vanoni 	(void) wbkgd(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
277*9bbf5ba1SRafael Vanoni 	(void) werase(sw[SW_TITLE]);
278b47b5b34SRafael Vanoni 
279b47b5b34SRafael Vanoni 	(void) snprintf(title_pad, 10, "%%%ds",
280*9bbf5ba1SRafael Vanoni 	    (win_cols - strlen(TITLE))/2 + strlen(TITLE));
281*9bbf5ba1SRafael Vanoni 
282b47b5b34SRafael Vanoni 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
283*9bbf5ba1SRafael Vanoni 	print(sw[SW_TITLE], 0, 0, title_pad, TITLE);
284b47b5b34SRafael Vanoni 
285*9bbf5ba1SRafael Vanoni 	(void) wnoutrefresh(sw[SW_TITLE]);
286b47b5b34SRafael Vanoni }
287b47b5b34SRafael Vanoni 
288b47b5b34SRafael Vanoni void
289*9bbf5ba1SRafael Vanoni pt_display_status_bar(void)
290*9bbf5ba1SRafael Vanoni {
291*9bbf5ba1SRafael Vanoni 	sb_slot_t *n = status_bar;
292*9bbf5ba1SRafael Vanoni 	int x = 0;
293*9bbf5ba1SRafael Vanoni 
294*9bbf5ba1SRafael Vanoni 	(void) werase(sw[SW_STATUS]);
295*9bbf5ba1SRafael Vanoni 
296*9bbf5ba1SRafael Vanoni 	while (n && x < win_cols) {
297*9bbf5ba1SRafael Vanoni 		(void) wattron(sw[SW_STATUS], A_REVERSE);
298*9bbf5ba1SRafael Vanoni 		print(sw[SW_STATUS], 0, x, "%s", n->msg);
299*9bbf5ba1SRafael Vanoni 		(void) wattroff(sw[SW_STATUS], A_REVERSE);
300*9bbf5ba1SRafael Vanoni 		x += strlen(n->msg) + 1;
301*9bbf5ba1SRafael Vanoni 
302*9bbf5ba1SRafael Vanoni 		n = n->next;
303*9bbf5ba1SRafael Vanoni 	}
304*9bbf5ba1SRafael Vanoni 
305*9bbf5ba1SRafael Vanoni 	(void) wnoutrefresh(sw[SW_STATUS]);
306*9bbf5ba1SRafael Vanoni }
307*9bbf5ba1SRafael Vanoni 
308*9bbf5ba1SRafael Vanoni /*
309*9bbf5ba1SRafael Vanoni  * Adds or removes items to the status bar automatically.
310*9bbf5ba1SRafael Vanoni  * Only one instance of an item allowed.
311*9bbf5ba1SRafael Vanoni  */
312*9bbf5ba1SRafael Vanoni void
313*9bbf5ba1SRafael Vanoni pt_display_mod_status_bar(char *msg)
314*9bbf5ba1SRafael Vanoni {
315*9bbf5ba1SRafael Vanoni 	sb_slot_t *new, *n;
316*9bbf5ba1SRafael Vanoni 	boolean_t found = B_FALSE, first = B_FALSE;
317*9bbf5ba1SRafael Vanoni 
318*9bbf5ba1SRafael Vanoni 	if (msg == NULL) {
319*9bbf5ba1SRafael Vanoni 		pt_error("%s : can't add an empty status bar item.", __FILE__);
320*9bbf5ba1SRafael Vanoni 		return;
321*9bbf5ba1SRafael Vanoni 	}
322*9bbf5ba1SRafael Vanoni 
323*9bbf5ba1SRafael Vanoni 	if (status_bar != NULL) {
324*9bbf5ba1SRafael Vanoni 		/*
325*9bbf5ba1SRafael Vanoni 		 * Non-empty status bar. Look for an entry matching this msg.
326*9bbf5ba1SRafael Vanoni 		 */
327*9bbf5ba1SRafael Vanoni 		for (n = status_bar; n != NULL; n = n->next) {
328*9bbf5ba1SRafael Vanoni 
329*9bbf5ba1SRafael Vanoni 			if (strcmp(msg, n->msg) == 0) {
330*9bbf5ba1SRafael Vanoni 				if (n != status_bar)
331*9bbf5ba1SRafael Vanoni 					n->prev->next = n->next;
332*9bbf5ba1SRafael Vanoni 				else
333*9bbf5ba1SRafael Vanoni 					first = B_TRUE;
334*9bbf5ba1SRafael Vanoni 
335*9bbf5ba1SRafael Vanoni 				if (n->next != NULL) {
336*9bbf5ba1SRafael Vanoni 					n->next->prev = n->prev;
337*9bbf5ba1SRafael Vanoni 					if (first)
338*9bbf5ba1SRafael Vanoni 						status_bar = n->next;
339*9bbf5ba1SRafael Vanoni 				} else {
340*9bbf5ba1SRafael Vanoni 					if (first)
341*9bbf5ba1SRafael Vanoni 						status_bar = NULL;
342*9bbf5ba1SRafael Vanoni 				}
343*9bbf5ba1SRafael Vanoni 
344*9bbf5ba1SRafael Vanoni 				free(n);
345*9bbf5ba1SRafael Vanoni 				found = B_TRUE;
346*9bbf5ba1SRafael Vanoni 			}
347*9bbf5ba1SRafael Vanoni 		}
348*9bbf5ba1SRafael Vanoni 
349*9bbf5ba1SRafael Vanoni 		/*
350*9bbf5ba1SRafael Vanoni 		 * Found and removed at least one occurrance of msg, refresh
351*9bbf5ba1SRafael Vanoni 		 * the bar and return.
352*9bbf5ba1SRafael Vanoni 		 */
353*9bbf5ba1SRafael Vanoni 		if (found) {
354*9bbf5ba1SRafael Vanoni 			return;
355*9bbf5ba1SRafael Vanoni 		} else {
356*9bbf5ba1SRafael Vanoni 			/*
357*9bbf5ba1SRafael Vanoni 			 * Inserting a new msg, walk to the end of the bar.
358*9bbf5ba1SRafael Vanoni 			 */
359*9bbf5ba1SRafael Vanoni 			for (n = status_bar; n->next != NULL; n = n->next)
360*9bbf5ba1SRafael Vanoni 				;
361*9bbf5ba1SRafael Vanoni 		}
362*9bbf5ba1SRafael Vanoni 	}
363*9bbf5ba1SRafael Vanoni 
364*9bbf5ba1SRafael Vanoni 	if ((new = calloc(1, sizeof (sb_slot_t))) == NULL) {
365*9bbf5ba1SRafael Vanoni 		pt_error("%s : failed to allocate a new slot\n", __FILE__);
366*9bbf5ba1SRafael Vanoni 	} else {
367*9bbf5ba1SRafael Vanoni 		new->msg = strdup(msg);
368*9bbf5ba1SRafael Vanoni 
369*9bbf5ba1SRafael Vanoni 		/*
370*9bbf5ba1SRafael Vanoni 		 * Check if it's the first entry.
371*9bbf5ba1SRafael Vanoni 		 */
372*9bbf5ba1SRafael Vanoni 		if (status_bar == NULL) {
373*9bbf5ba1SRafael Vanoni 			status_bar = new;
374*9bbf5ba1SRafael Vanoni 			new->prev = NULL;
375*9bbf5ba1SRafael Vanoni 		} else {
376*9bbf5ba1SRafael Vanoni 			new->prev = n;
377*9bbf5ba1SRafael Vanoni 			n->next = new;
378*9bbf5ba1SRafael Vanoni 		}
379*9bbf5ba1SRafael Vanoni 		new->next = NULL;
380*9bbf5ba1SRafael Vanoni 	}
381*9bbf5ba1SRafael Vanoni }
382*9bbf5ba1SRafael Vanoni 
383*9bbf5ba1SRafael Vanoni void
384*9bbf5ba1SRafael Vanoni pt_display_states(void)
385b47b5b34SRafael Vanoni {
386b47b5b34SRafael Vanoni 	char		c[100];
387b47b5b34SRafael Vanoni 	int		i;
388b47b5b34SRafael Vanoni 	double		total_pstates = 0.0, avg, res;
389b47b5b34SRafael Vanoni 	uint64_t	p0_speed, p1_speed;
390b47b5b34SRafael Vanoni 
391*9bbf5ba1SRafael Vanoni 	print(sw[SW_IDLE], 0, 0, "%s\tAvg\tResidency\n", g_msg_idle_state);
392b47b5b34SRafael Vanoni 
393*9bbf5ba1SRafael Vanoni 	if (g_features & FEATURE_CSTATE) {
394*9bbf5ba1SRafael Vanoni 		res =  (((double)g_cstate_info[0].total_time / g_total_c_time))
395*9bbf5ba1SRafael Vanoni 		    * 100;
396b47b5b34SRafael Vanoni 		(void) sprintf(c, "C0 (cpu running)\t\t(%.1f%%)\n", (float)res);
397*9bbf5ba1SRafael Vanoni 		print(sw[SW_IDLE], 1, 0, "%s", c);
398b47b5b34SRafael Vanoni 
399b47b5b34SRafael Vanoni 		for (i = 1; i <= g_max_cstate; i++) {
400b47b5b34SRafael Vanoni 			/*
401*9bbf5ba1SRafael Vanoni 			 * In situations where the load is too intensive, the
402*9bbf5ba1SRafael Vanoni 			 * system might not transition at all.
403b47b5b34SRafael Vanoni 			 */
404b47b5b34SRafael Vanoni 			if (g_cstate_info[i].events > 0)
405b47b5b34SRafael Vanoni 				avg = (((double)g_cstate_info[i].total_time/
406636423dbSRafael Vanoni 				    MICROSEC)/g_cstate_info[i].events);
407b47b5b34SRafael Vanoni 			else
408b47b5b34SRafael Vanoni 				avg = 0;
409b47b5b34SRafael Vanoni 
410*9bbf5ba1SRafael Vanoni 			res = ((double)g_cstate_info[i].total_time/
411*9bbf5ba1SRafael Vanoni 			    g_total_c_time) * 100;
412b47b5b34SRafael Vanoni 
413*9bbf5ba1SRafael Vanoni 			(void) sprintf(c, "C%d\t\t\t%.1fms\t(%.1f%%)\n",
414*9bbf5ba1SRafael Vanoni 			    i, (float)avg, (float)res);
415*9bbf5ba1SRafael Vanoni 			print(sw[SW_IDLE], i + 1, 0, "%s", c);
416*9bbf5ba1SRafael Vanoni 		}
417b47b5b34SRafael Vanoni 	}
418b47b5b34SRafael Vanoni 
419*9bbf5ba1SRafael Vanoni 	if (!PT_ON_DUMP)
420*9bbf5ba1SRafael Vanoni 		(void) wnoutrefresh(sw[SW_IDLE]);
421b47b5b34SRafael Vanoni 
422*9bbf5ba1SRafael Vanoni 	print(sw[SW_FREQ], 0, 0, "%s\n", g_msg_freq_state);
423*9bbf5ba1SRafael Vanoni 
424*9bbf5ba1SRafael Vanoni 	if (g_features & FEATURE_PSTATE) {
425b47b5b34SRafael Vanoni 		for (i = 0; i < g_npstates; i++) {
426*9bbf5ba1SRafael Vanoni 			total_pstates +=
427*9bbf5ba1SRafael Vanoni 			    (double)(g_pstate_info[i].total_time/
428636423dbSRafael Vanoni 			    g_ncpus_observed/MICROSEC);
429b47b5b34SRafael Vanoni 		}
430b47b5b34SRafael Vanoni 
431b47b5b34SRafael Vanoni 		/*
432b47b5b34SRafael Vanoni 		 * display ACPI_PSTATE from P(n) to P(1)
433b47b5b34SRafael Vanoni 		 */
434b47b5b34SRafael Vanoni 		for (i = 0;  i < g_npstates - 1; i++) {
435b47b5b34SRafael Vanoni 			(void) sprintf(c, "%4lu Mhz\t%.1f%%",
436b47b5b34SRafael Vanoni 			    (long)g_pstate_info[i].speed,
437*9bbf5ba1SRafael Vanoni 			    100 * (g_pstate_info[i].total_time/
438*9bbf5ba1SRafael Vanoni 			    g_ncpus_observed/MICROSEC/total_pstates));
439*9bbf5ba1SRafael Vanoni 			print(sw[SW_FREQ], i+1, 0, "%s\n", c);
440b47b5b34SRafael Vanoni 		}
441b47b5b34SRafael Vanoni 
442b47b5b34SRafael Vanoni 		/*
443b47b5b34SRafael Vanoni 		 * Display ACPI_PSTATE P0 according to if turbo
444b47b5b34SRafael Vanoni 		 * mode is supported
445b47b5b34SRafael Vanoni 		 */
446b47b5b34SRafael Vanoni 		if (g_turbo_supported) {
447b47b5b34SRafael Vanoni 			p1_speed = g_pstate_info[g_npstates - 2].speed;
448b47b5b34SRafael Vanoni 
449b47b5b34SRafael Vanoni 			/*
450b47b5b34SRafael Vanoni 			 * If g_turbo_ratio <= 1.0, it will be ignored.
451b47b5b34SRafael Vanoni 			 * we display P(0) as P(1) + 1.
452b47b5b34SRafael Vanoni 			 */
453b47b5b34SRafael Vanoni 			if (g_turbo_ratio <= 1.0) {
454b47b5b34SRafael Vanoni 				p0_speed = p1_speed + 1;
455b47b5b34SRafael Vanoni 			} else {
456b47b5b34SRafael Vanoni 				/*
457*9bbf5ba1SRafael Vanoni 				 * If g_turbo_ratio > 1.0, that means
458*9bbf5ba1SRafael Vanoni 				 * turbo mode works. So, P(0) = ratio *
459*9bbf5ba1SRafael Vanoni 				 *  P(1);
460b47b5b34SRafael Vanoni 				 */
461*9bbf5ba1SRafael Vanoni 				p0_speed = (uint64_t)(p1_speed *
462*9bbf5ba1SRafael Vanoni 				    g_turbo_ratio);
463b47b5b34SRafael Vanoni 				if (p0_speed < (p1_speed + 1))
464b47b5b34SRafael Vanoni 					p0_speed = p1_speed + 1;
465b47b5b34SRafael Vanoni 			}
466b47b5b34SRafael Vanoni 			/*
467b47b5b34SRafael Vanoni 			 * Reset the ratio for the next round
468b47b5b34SRafael Vanoni 			 */
469b47b5b34SRafael Vanoni 			g_turbo_ratio = 0.0;
470b47b5b34SRafael Vanoni 
471b47b5b34SRafael Vanoni 			/*
472b47b5b34SRafael Vanoni 			 * Setup the string for the display
473b47b5b34SRafael Vanoni 			 */
474b47b5b34SRafael Vanoni 			(void) sprintf(c, "%4lu Mhz(turbo)\t%.1f%%",
475b47b5b34SRafael Vanoni 			    (long)p0_speed,
476b47b5b34SRafael Vanoni 			    100 * (g_pstate_info[i].total_time/
477636423dbSRafael Vanoni 			    g_ncpus_observed/MICROSEC/total_pstates));
478b47b5b34SRafael Vanoni 		} else {
479b47b5b34SRafael Vanoni 			(void) sprintf(c, "%4lu Mhz\t%.1f%%",
480b47b5b34SRafael Vanoni 			    (long)g_pstate_info[i].speed,
481b47b5b34SRafael Vanoni 			    100 * (g_pstate_info[i].total_time/
482636423dbSRafael Vanoni 			    g_ncpus_observed/MICROSEC/total_pstates));
483b47b5b34SRafael Vanoni 		}
484*9bbf5ba1SRafael Vanoni 		print(sw[SW_FREQ], i+1, 0, "%s\n", c);
485*9bbf5ba1SRafael Vanoni 	} else {
486*9bbf5ba1SRafael Vanoni 		if (g_npstates == 1) {
487*9bbf5ba1SRafael Vanoni 			(void) sprintf(c, "%4lu Mhz\t%.1f%%",
488*9bbf5ba1SRafael Vanoni 			    (long)g_pstate_info[0].speed, 100.0);
489*9bbf5ba1SRafael Vanoni 			print(sw[SW_FREQ], 1, 0, "%s\n", c);
490*9bbf5ba1SRafael Vanoni 		}
491b47b5b34SRafael Vanoni 	}
492b47b5b34SRafael Vanoni 
493636423dbSRafael Vanoni 	if (!PT_ON_DUMP)
494*9bbf5ba1SRafael Vanoni 		(void) wnoutrefresh(sw[SW_FREQ]);
495b47b5b34SRafael Vanoni }
496b47b5b34SRafael Vanoni 
497b47b5b34SRafael Vanoni void
498*9bbf5ba1SRafael Vanoni pt_display_acpi_power(uint32_t flag, double rate, double rem_cap, double cap,
499b47b5b34SRafael Vanoni     uint32_t state)
500b47b5b34SRafael Vanoni {
501b47b5b34SRafael Vanoni 	char	buffer[1024];
502b47b5b34SRafael Vanoni 
503b47b5b34SRafael Vanoni 	(void) sprintf(buffer,  _("no ACPI power usage estimate available"));
504b47b5b34SRafael Vanoni 
505636423dbSRafael Vanoni 	if (!PT_ON_DUMP)
506*9bbf5ba1SRafael Vanoni 		(void) werase(sw[SW_POWER]);
507*9bbf5ba1SRafael Vanoni 
508b47b5b34SRafael Vanoni 	if (flag) {
509b47b5b34SRafael Vanoni 		char *c;
510b47b5b34SRafael Vanoni 		(void) sprintf(buffer, "Power usage (ACPI estimate): %.3fW",
511b47b5b34SRafael Vanoni 		    rate);
512b47b5b34SRafael Vanoni 		(void) strcat(buffer, " ");
513b47b5b34SRafael Vanoni 		c = &buffer[strlen(buffer)];
514b47b5b34SRafael Vanoni 		switch (state) {
515b47b5b34SRafael Vanoni 		case 0:
516b47b5b34SRafael Vanoni 			(void) sprintf(c, "(running on AC power, fully "
517b47b5b34SRafael Vanoni 			    "charged)");
518b47b5b34SRafael Vanoni 			break;
519b47b5b34SRafael Vanoni 		case 1:
520b47b5b34SRafael Vanoni 			(void) sprintf(c, "(discharging: %3.1f hours)",
521b47b5b34SRafael Vanoni 			    (uint32_t)rem_cap/rate);
522b47b5b34SRafael Vanoni 			break;
523b47b5b34SRafael Vanoni 		case 2:
524b47b5b34SRafael Vanoni 			(void) sprintf(c, "(charging: %3.1f hours)",
525b47b5b34SRafael Vanoni 			    (uint32_t)(cap - rem_cap)/rate);
526b47b5b34SRafael Vanoni 			break;
527b47b5b34SRafael Vanoni 		case 4:
528b47b5b34SRafael Vanoni 			(void) sprintf(c, "(##critically low battery power##)");
529b47b5b34SRafael Vanoni 			break;
530b47b5b34SRafael Vanoni 		}
531b47b5b34SRafael Vanoni 
532b47b5b34SRafael Vanoni 	}
533*9bbf5ba1SRafael Vanoni 
534*9bbf5ba1SRafael Vanoni 	print(sw[SW_POWER], 0, 0, "%s\n", buffer);
535636423dbSRafael Vanoni 	if (!PT_ON_DUMP)
536*9bbf5ba1SRafael Vanoni 		(void) wnoutrefresh(sw[SW_POWER]);
537b47b5b34SRafael Vanoni }
538b47b5b34SRafael Vanoni 
539b47b5b34SRafael Vanoni void
540*9bbf5ba1SRafael Vanoni pt_display_wakeups(double interval)
541b47b5b34SRafael Vanoni {
542b47b5b34SRafael Vanoni 	char		c[100];
543b47b5b34SRafael Vanoni 	int		i, event_sum = 0;
544636423dbSRafael Vanoni 	event_info_t	*event = g_event_info;
545b47b5b34SRafael Vanoni 
546636423dbSRafael Vanoni 	if (!PT_ON_DUMP) {
547*9bbf5ba1SRafael Vanoni 		(void) werase(sw[SW_WAKEUPS]);
548*9bbf5ba1SRafael Vanoni 		(void) wbkgd(sw[SW_WAKEUPS], COLOR_PAIR(PT_COLOR_RED));
549*9bbf5ba1SRafael Vanoni 		(void) wattron(sw[SW_WAKEUPS], A_BOLD);
550b47b5b34SRafael Vanoni 	}
551b47b5b34SRafael Vanoni 
552b47b5b34SRafael Vanoni 	/*
553b47b5b34SRafael Vanoni 	 * calculate the actual total event number
554b47b5b34SRafael Vanoni 	 */
555636423dbSRafael Vanoni 	for (i = 0; i < g_top_events; i++, event++)
556636423dbSRafael Vanoni 		event_sum += event->total_count;
557b47b5b34SRafael Vanoni 
558b47b5b34SRafael Vanoni 	/*
559b47b5b34SRafael Vanoni 	 * g_total_events is the sum of the number of Cx->C0 transition,
560b47b5b34SRafael Vanoni 	 * So when the system is very busy, the idle thread will have no
561b47b5b34SRafael Vanoni 	 * chance or very seldom to be scheduled, this could cause >100%
562b47b5b34SRafael Vanoni 	 * event report. Re-assign g_total_events to the actual event
563b47b5b34SRafael Vanoni 	 * number is a way to avoid this issue.
564b47b5b34SRafael Vanoni 	 */
565b47b5b34SRafael Vanoni 	if (event_sum > g_total_events)
566b47b5b34SRafael Vanoni 		g_total_events = event_sum;
567b47b5b34SRafael Vanoni 
568b47b5b34SRafael Vanoni 	(void) sprintf(c, "Wakeups-from-idle per second: %4.1f\tinterval: "
569b47b5b34SRafael Vanoni 	    "%.1fs", (double)(g_total_events/interval), interval);
570*9bbf5ba1SRafael Vanoni 	print(sw[SW_WAKEUPS], 0, 0, "%s\n", c);
571b47b5b34SRafael Vanoni 
572636423dbSRafael Vanoni 	if (!PT_ON_DUMP)
573*9bbf5ba1SRafael Vanoni 		(void) wnoutrefresh(sw[SW_WAKEUPS]);
574b47b5b34SRafael Vanoni }
575b47b5b34SRafael Vanoni 
576b47b5b34SRafael Vanoni void
577*9bbf5ba1SRafael Vanoni pt_display_events(double interval)
578b47b5b34SRafael Vanoni {
579b47b5b34SRafael Vanoni 	char		c[100];
580b47b5b34SRafael Vanoni 	int		i;
581b47b5b34SRafael Vanoni 	double		events;
582636423dbSRafael Vanoni 	event_info_t	*event = g_event_info;
583b47b5b34SRafael Vanoni 
584636423dbSRafael Vanoni 	if (!PT_ON_DUMP) {
585*9bbf5ba1SRafael Vanoni 		(void) werase(sw[SW_EVENTS]);
586*9bbf5ba1SRafael Vanoni 		(void) wbkgd(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
587*9bbf5ba1SRafael Vanoni 		(void) wattron(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
588b47b5b34SRafael Vanoni 	}
589b47b5b34SRafael Vanoni 
590b47b5b34SRafael Vanoni 	/*
591b47b5b34SRafael Vanoni 	 * Sort the event report list
592b47b5b34SRafael Vanoni 	 */
593636423dbSRafael Vanoni 	if (g_top_events > EVENT_NUM_MAX)
594636423dbSRafael Vanoni 		g_top_events = EVENT_NUM_MAX;
595b47b5b34SRafael Vanoni 
596636423dbSRafael Vanoni 	qsort((void *)g_event_info, g_top_events, sizeof (event_info_t),
597b47b5b34SRafael Vanoni 	    event_compare);
598b47b5b34SRafael Vanoni 
599636423dbSRafael Vanoni 	if (PT_ON_CPU)
600b47b5b34SRafael Vanoni 		(void) sprintf(c, "Top causes for wakeups on CPU %d:\n",
601b47b5b34SRafael Vanoni 		    g_observed_cpu);
602b47b5b34SRafael Vanoni 	else
603b47b5b34SRafael Vanoni 		(void) sprintf(c, "Top causes for wakeups:\n");
604b47b5b34SRafael Vanoni 
605*9bbf5ba1SRafael Vanoni 	print(sw[SW_EVENTS], 0, 0, "%s", c);
606b47b5b34SRafael Vanoni 
607636423dbSRafael Vanoni 	for (i = 0; i < g_top_events; i++, event++) {
608b47b5b34SRafael Vanoni 
609636423dbSRafael Vanoni 		if (g_total_events > 0 && event->total_count > 0)
610636423dbSRafael Vanoni 			events = (double)event->total_count/
611b47b5b34SRafael Vanoni 			    (double)g_total_events;
612b47b5b34SRafael Vanoni 		else
613b47b5b34SRafael Vanoni 			continue;
614b47b5b34SRafael Vanoni 
615b47b5b34SRafael Vanoni 		(void) sprintf(c, "%4.1f%% (%5.1f)", 100 * events,
616636423dbSRafael Vanoni 		    (double)event->total_count/interval);
617*9bbf5ba1SRafael Vanoni 		print(sw[SW_EVENTS], i+1, 0, "%s", c);
618*9bbf5ba1SRafael Vanoni 		print(sw[SW_EVENTS], i+1, 16, "%20s :",
619636423dbSRafael Vanoni 		    event->offender_name);
620*9bbf5ba1SRafael Vanoni 		print(sw[SW_EVENTS], i+1, 40, "%-64s\n",
621636423dbSRafael Vanoni 		    event->offense_name);
622b47b5b34SRafael Vanoni 	}
623b47b5b34SRafael Vanoni 
624636423dbSRafael Vanoni 	if (!PT_ON_DUMP)
625*9bbf5ba1SRafael Vanoni 		(void) wnoutrefresh(sw[SW_EVENTS]);
626b47b5b34SRafael Vanoni }
627b47b5b34SRafael Vanoni 
628b47b5b34SRafael Vanoni void
629*9bbf5ba1SRafael Vanoni pt_display_suggestions(char *sug)
630b47b5b34SRafael Vanoni {
631*9bbf5ba1SRafael Vanoni 	(void) werase(sw[SW_SUGG]);
632b47b5b34SRafael Vanoni 
633*9bbf5ba1SRafael Vanoni 	if (sug != NULL)
634*9bbf5ba1SRafael Vanoni 		print(sw[SW_SUGG], 0, 0, "%s", sug);
635*9bbf5ba1SRafael Vanoni 
636*9bbf5ba1SRafael Vanoni 	(void) wnoutrefresh(sw[SW_SUGG]);
637*9bbf5ba1SRafael Vanoni 
638*9bbf5ba1SRafael Vanoni 	pt_display_update();
639b47b5b34SRafael Vanoni }
640