1bcde4861SRafael Vanoni Polanczyk /*
2b47b5b34SRafael Vanoni * Copyright 2009, Intel Corporation
3b47b5b34SRafael Vanoni * Copyright 2009, Sun Microsystems, Inc
4bcde4861SRafael Vanoni Polanczyk *
5bcde4861SRafael Vanoni Polanczyk * This file is part of PowerTOP
6bcde4861SRafael Vanoni Polanczyk *
7bcde4861SRafael Vanoni Polanczyk * This program file is free software; you can redistribute it and/or modify it
8bcde4861SRafael Vanoni Polanczyk * under the terms of the GNU General Public License as published by the
9bcde4861SRafael Vanoni Polanczyk * Free Software Foundation; version 2 of the License.
10bcde4861SRafael Vanoni Polanczyk *
11bcde4861SRafael Vanoni Polanczyk * This program is distributed in the hope that it will be useful, but WITHOUT
12bcde4861SRafael Vanoni Polanczyk * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13bcde4861SRafael Vanoni Polanczyk * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14bcde4861SRafael Vanoni Polanczyk * for more details.
15bcde4861SRafael Vanoni Polanczyk *
16bcde4861SRafael Vanoni Polanczyk * You should have received a copy of the GNU General Public License
17bcde4861SRafael Vanoni Polanczyk * along with this program in a file named COPYING; if not, write to the
18bcde4861SRafael Vanoni Polanczyk * Free Software Foundation, Inc.,
19bcde4861SRafael Vanoni Polanczyk * 51 Franklin Street, Fifth Floor,
20bcde4861SRafael Vanoni Polanczyk * Boston, MA 02110-1301 USA
21bcde4861SRafael Vanoni Polanczyk *
22bcde4861SRafael Vanoni Polanczyk * Authors:
23bcde4861SRafael Vanoni Polanczyk * Arjan van de Ven <arjan@linux.intel.com>
24bcde4861SRafael Vanoni Polanczyk * Eric C Saxe <eric.saxe@sun.com>
25bcde4861SRafael Vanoni Polanczyk * Aubrey Li <aubrey.li@intel.com>
26bcde4861SRafael Vanoni Polanczyk */
27bcde4861SRafael Vanoni Polanczyk
28*9e21aac0SMarcel Telka /*
29*9e21aac0SMarcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
30*9e21aac0SMarcel Telka */
31*9e21aac0SMarcel Telka
32bcde4861SRafael Vanoni Polanczyk /*
33bcde4861SRafael Vanoni Polanczyk * GPL Disclaimer
34bcde4861SRafael Vanoni Polanczyk *
35bcde4861SRafael Vanoni Polanczyk * For the avoidance of doubt, except that if any license choice other
36bcde4861SRafael Vanoni Polanczyk * than GPL or LGPL is available it will apply instead, Sun elects to
37bcde4861SRafael Vanoni Polanczyk * use only the General Public License version 2 (GPLv2) at this time
38bcde4861SRafael Vanoni Polanczyk * for any software where a choice of GPL license versions is made
39bcde4861SRafael Vanoni Polanczyk * available with the language indicating that GPLv2 or any later
40bcde4861SRafael Vanoni Polanczyk * version may be used, or where a choice of which version of the GPL
41bcde4861SRafael Vanoni Polanczyk * is applied is otherwise unspecified.
42bcde4861SRafael Vanoni Polanczyk */
43bcde4861SRafael Vanoni Polanczyk
44bcde4861SRafael Vanoni Polanczyk #include <stdlib.h>
45bcde4861SRafael Vanoni Polanczyk #include <string.h>
469bbf5ba1SRafael Vanoni #include <unistd.h>
47bcde4861SRafael Vanoni Polanczyk #include <curses.h>
489bbf5ba1SRafael Vanoni #include <signal.h>
499bbf5ba1SRafael Vanoni #include <fcntl.h>
50bcde4861SRafael Vanoni Polanczyk #include "powertop.h"
51bcde4861SRafael Vanoni Polanczyk
529bbf5ba1SRafael Vanoni /*
539bbf5ba1SRafael Vanoni * Minimum terminal height and width to run PowerTOP on curses mode.
549bbf5ba1SRafael Vanoni */
559bbf5ba1SRafael Vanoni #define PT_MIN_COLS 70
569bbf5ba1SRafael Vanoni #define PT_MIN_ROWS 15
579bbf5ba1SRafael Vanoni
589bbf5ba1SRafael Vanoni /*
599bbf5ba1SRafael Vanoni * Display colors
609bbf5ba1SRafael Vanoni */
619bbf5ba1SRafael Vanoni #define PT_COLOR_DEFAULT 1
629bbf5ba1SRafael Vanoni #define PT_COLOR_HEADER_BAR 2
639bbf5ba1SRafael Vanoni #define PT_COLOR_ERROR 3
649bbf5ba1SRafael Vanoni #define PT_COLOR_RED 4
659bbf5ba1SRafael Vanoni #define PT_COLOR_YELLOW 5
669bbf5ba1SRafael Vanoni #define PT_COLOR_GREEN 6
679bbf5ba1SRafael Vanoni #define PT_COLOR_BRIGHT 7
689bbf5ba1SRafael Vanoni #define PT_COLOR_BLUE 8
699bbf5ba1SRafael Vanoni
709bbf5ba1SRafael Vanoni /*
719bbf5ba1SRafael Vanoni * Constants for pt_display_setup()
729bbf5ba1SRafael Vanoni */
739bbf5ba1SRafael Vanoni #define SINGLE_LINE_SW 1
749bbf5ba1SRafael Vanoni #define LENGTH_SUGG_SW 2
759bbf5ba1SRafael Vanoni #define TITLE_LINE 1
769bbf5ba1SRafael Vanoni #define BLANK_LINE 1
779bbf5ba1SRafael Vanoni #define NEXT_LINE 1
78bcde4861SRafael Vanoni Polanczyk
79bcde4861SRafael Vanoni Polanczyk #define print(win, y, x, fmt, args...) \
80636423dbSRafael Vanoni if (PT_ON_DUMP) \
81bcde4861SRafael Vanoni Polanczyk (void) printf(fmt, ## args); \
82bcde4861SRafael Vanoni Polanczyk else \
83bcde4861SRafael Vanoni Polanczyk (void) mvwprintw(win, y, x, fmt, ## args);
84bcde4861SRafael Vanoni Polanczyk
859bbf5ba1SRafael Vanoni enum pt_subwindows {
869bbf5ba1SRafael Vanoni SW_TITLE,
879bbf5ba1SRafael Vanoni SW_IDLE,
889bbf5ba1SRafael Vanoni SW_FREQ,
899bbf5ba1SRafael Vanoni SW_WAKEUPS,
909bbf5ba1SRafael Vanoni SW_POWER,
919bbf5ba1SRafael Vanoni SW_EVENTS,
929bbf5ba1SRafael Vanoni SW_SUGG,
939bbf5ba1SRafael Vanoni SW_STATUS,
949bbf5ba1SRafael Vanoni SW_COUNT
959bbf5ba1SRafael Vanoni };
969bbf5ba1SRafael Vanoni
979bbf5ba1SRafael Vanoni typedef struct sb_slot {
989bbf5ba1SRafael Vanoni char *msg;
999bbf5ba1SRafael Vanoni struct sb_slot *prev;
1009bbf5ba1SRafael Vanoni struct sb_slot *next;
1019bbf5ba1SRafael Vanoni } sb_slot_t;
1029bbf5ba1SRafael Vanoni
1039bbf5ba1SRafael Vanoni static WINDOW *sw[SW_COUNT];
1049bbf5ba1SRafael Vanoni static int win_cols, win_rows;
1059bbf5ba1SRafael Vanoni static sb_slot_t *status_bar;
106b47b5b34SRafael Vanoni
1072d83778aSRafael Vanoni /*
1082d83778aSRafael Vanoni * Delete all subwindows and reset the terminal to a non-visual mode. This
1092d83778aSRafael Vanoni * routine is used during resize events and before exiting.
1102d83778aSRafael Vanoni */
1119bbf5ba1SRafael Vanoni static void
pt_display_cleanup(void)1129bbf5ba1SRafael Vanoni pt_display_cleanup(void)
1139bbf5ba1SRafael Vanoni {
1142d83778aSRafael Vanoni int i;
1152d83778aSRafael Vanoni
1162d83778aSRafael Vanoni for (i = 0; i < SW_COUNT; i++) {
1172d83778aSRafael Vanoni if (sw[i] != NULL) {
1182d83778aSRafael Vanoni (void) delwin(sw[i]);
1192d83778aSRafael Vanoni sw[i] = NULL;
1202d83778aSRafael Vanoni }
1212d83778aSRafael Vanoni }
1222d83778aSRafael Vanoni
1239bbf5ba1SRafael Vanoni (void) endwin();
1242d83778aSRafael Vanoni (void) fflush(stdout);
1252d83778aSRafael Vanoni (void) putchar('\r');
1269bbf5ba1SRafael Vanoni }
127bcde4861SRafael Vanoni Polanczyk
128bcde4861SRafael Vanoni Polanczyk static void
pt_display_get_size(void)1299bbf5ba1SRafael Vanoni pt_display_get_size(void)
130bcde4861SRafael Vanoni Polanczyk {
1319bbf5ba1SRafael Vanoni getmaxyx(stdscr, win_rows, win_cols);
1329bbf5ba1SRafael Vanoni
1339bbf5ba1SRafael Vanoni if (win_rows < PT_MIN_ROWS || win_cols < PT_MIN_COLS) {
1349bbf5ba1SRafael Vanoni pt_display_cleanup();
1359bbf5ba1SRafael Vanoni (void) printf("\n\nPowerTOP cannot run in such a small "
1369bbf5ba1SRafael Vanoni "terminal window. Please resize it.\n\n");
1379bbf5ba1SRafael Vanoni exit(EXIT_FAILURE);
138bcde4861SRafael Vanoni Polanczyk }
139bcde4861SRafael Vanoni Polanczyk }
140bcde4861SRafael Vanoni Polanczyk
1412d83778aSRafael Vanoni void
pt_display_resize(void)1422d83778aSRafael Vanoni pt_display_resize(void)
143bcde4861SRafael Vanoni Polanczyk {
1442d83778aSRafael Vanoni pt_display_cleanup();
1452d83778aSRafael Vanoni (void) pt_display_init_curses();
1462d83778aSRafael Vanoni pt_display_setup(B_TRUE);
1479bbf5ba1SRafael Vanoni
1482d83778aSRafael Vanoni pt_display_title_bar();
1499bbf5ba1SRafael Vanoni
1502d83778aSRafael Vanoni pt_display_states();
1519bbf5ba1SRafael Vanoni
1522d83778aSRafael Vanoni if (g_features & FEATURE_EVENTS) {
1532d83778aSRafael Vanoni pt_display_wakeups(g_interval_length);
1542d83778aSRafael Vanoni pt_display_events(g_interval_length);
1552d83778aSRafael Vanoni }
1569bbf5ba1SRafael Vanoni
1572d83778aSRafael Vanoni pt_battery_print();
1582d83778aSRafael Vanoni pt_sugg_pick();
1592d83778aSRafael Vanoni pt_display_status_bar();
1609bbf5ba1SRafael Vanoni
1612d83778aSRafael Vanoni pt_display_update();
1622d83778aSRafael Vanoni
1632d83778aSRafael Vanoni g_sig_resize = B_FALSE;
1642d83778aSRafael Vanoni (void) signal(SIGWINCH, pt_sig_handler);
165bcde4861SRafael Vanoni Polanczyk }
166bcde4861SRafael Vanoni Polanczyk
167bcde4861SRafael Vanoni Polanczyk /*
168bcde4861SRafael Vanoni Polanczyk * This part was re-written to be human readable and easy to modify. Please
169bcde4861SRafael Vanoni Polanczyk * try to keep it that way and help us save some time.
170bcde4861SRafael Vanoni Polanczyk *
171bcde4861SRafael Vanoni Polanczyk * Friendly reminder:
172bcde4861SRafael Vanoni Polanczyk * subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x)
173bcde4861SRafael Vanoni Polanczyk */
174bcde4861SRafael Vanoni Polanczyk void
pt_display_setup(boolean_t resized)1759bbf5ba1SRafael Vanoni pt_display_setup(boolean_t resized)
176bcde4861SRafael Vanoni Polanczyk {
177bcde4861SRafael Vanoni Polanczyk /*
178bcde4861SRafael Vanoni Polanczyk * These variables are used to properly set the initial y position and
179bcde4861SRafael Vanoni Polanczyk * number of lines in each subwindow, as the number of supported CPU
180bcde4861SRafael Vanoni Polanczyk * states affects their placement.
181bcde4861SRafael Vanoni Polanczyk */
1829bbf5ba1SRafael Vanoni int cstate_lines, event_lines, pos_y = 0;
183bcde4861SRafael Vanoni Polanczyk
1849bbf5ba1SRafael Vanoni /*
1859bbf5ba1SRafael Vanoni * In theory, all systems have at least two idle states. We add two here
1869bbf5ba1SRafael Vanoni * since we have to use DTrace to figure out how many this box has.
1879bbf5ba1SRafael Vanoni */
1889bbf5ba1SRafael Vanoni cstate_lines = TITLE_LINE + max((g_max_cstate+2), g_npstates);
189bcde4861SRafael Vanoni Polanczyk
1909bbf5ba1SRafael Vanoni sw[SW_TITLE] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
191bcde4861SRafael Vanoni Polanczyk
192bcde4861SRafael Vanoni Polanczyk pos_y += NEXT_LINE + BLANK_LINE;
1939bbf5ba1SRafael Vanoni sw[SW_IDLE] = subwin(stdscr, cstate_lines, win_cols/2 + 1, pos_y, 0);
1949bbf5ba1SRafael Vanoni sw[SW_FREQ] = subwin(stdscr, cstate_lines, win_cols/2 - 8, pos_y,
1959bbf5ba1SRafael Vanoni win_cols/2 + 8);
196bcde4861SRafael Vanoni Polanczyk
197bcde4861SRafael Vanoni Polanczyk pos_y += cstate_lines + BLANK_LINE;
1989bbf5ba1SRafael Vanoni sw[SW_WAKEUPS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
199bcde4861SRafael Vanoni Polanczyk
200bcde4861SRafael Vanoni Polanczyk pos_y += NEXT_LINE;
2019bbf5ba1SRafael Vanoni sw[SW_POWER] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
202bcde4861SRafael Vanoni Polanczyk
203bcde4861SRafael Vanoni Polanczyk pos_y += NEXT_LINE + BLANK_LINE;
2049bbf5ba1SRafael Vanoni event_lines = win_rows - SINGLE_LINE_SW - NEXT_LINE - LENGTH_SUGG_SW -
205bcde4861SRafael Vanoni Polanczyk pos_y;
2069bbf5ba1SRafael Vanoni
2079bbf5ba1SRafael Vanoni if (event_lines > 0) {
2089bbf5ba1SRafael Vanoni sw[SW_EVENTS] = subwin(stdscr, event_lines, win_cols, pos_y, 0);
2099bbf5ba1SRafael Vanoni } else {
210*9e21aac0SMarcel Telka pt_display_cleanup();
2119bbf5ba1SRafael Vanoni (void) printf("\n\nPowerTOP cannot run in such a small "
2129bbf5ba1SRafael Vanoni "terminal window, please resize it.\n\n");
2139bbf5ba1SRafael Vanoni exit(EXIT_FAILURE);
2149bbf5ba1SRafael Vanoni }
215bcde4861SRafael Vanoni Polanczyk
216bcde4861SRafael Vanoni Polanczyk pos_y += event_lines + NEXT_LINE;
2179bbf5ba1SRafael Vanoni sw[SW_SUGG] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
218bcde4861SRafael Vanoni Polanczyk
219bcde4861SRafael Vanoni Polanczyk pos_y += BLANK_LINE + NEXT_LINE;
2209bbf5ba1SRafael Vanoni sw[SW_STATUS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
221bcde4861SRafael Vanoni Polanczyk
2229bbf5ba1SRafael Vanoni if (!resized) {
2239bbf5ba1SRafael Vanoni status_bar = NULL;
2249bbf5ba1SRafael Vanoni
2252d83778aSRafael Vanoni pt_display_mod_status_bar("Q - Quit");
2262d83778aSRafael Vanoni pt_display_mod_status_bar("R - Refresh");
2279bbf5ba1SRafael Vanoni }
228bcde4861SRafael Vanoni Polanczyk }
229bcde4861SRafael Vanoni Polanczyk
2309bbf5ba1SRafael Vanoni /*
2319bbf5ba1SRafael Vanoni * This routine handles all the necessary curses initialization.
2329bbf5ba1SRafael Vanoni */
233bcde4861SRafael Vanoni Polanczyk void
pt_display_init_curses(void)2349bbf5ba1SRafael Vanoni pt_display_init_curses(void)
235bcde4861SRafael Vanoni Polanczyk {
236bcde4861SRafael Vanoni Polanczyk (void) initscr();
2379bbf5ba1SRafael Vanoni
2389bbf5ba1SRafael Vanoni (void) atexit(pt_display_cleanup);
2399bbf5ba1SRafael Vanoni
2409bbf5ba1SRafael Vanoni pt_display_get_size();
2419bbf5ba1SRafael Vanoni
242bcde4861SRafael Vanoni Polanczyk (void) start_color();
243bcde4861SRafael Vanoni Polanczyk
244bcde4861SRafael Vanoni Polanczyk /*
245bcde4861SRafael Vanoni Polanczyk * Enable keyboard mapping
246bcde4861SRafael Vanoni Polanczyk */
247bcde4861SRafael Vanoni Polanczyk (void) keypad(stdscr, TRUE);
248bcde4861SRafael Vanoni Polanczyk
249bcde4861SRafael Vanoni Polanczyk /*
250bcde4861SRafael Vanoni Polanczyk * Tell curses not to do NL->CR/NL on output
251bcde4861SRafael Vanoni Polanczyk */
252bcde4861SRafael Vanoni Polanczyk (void) nonl();
253bcde4861SRafael Vanoni Polanczyk
254bcde4861SRafael Vanoni Polanczyk /*
255bcde4861SRafael Vanoni Polanczyk * Take input chars one at a time, no wait for \n
256bcde4861SRafael Vanoni Polanczyk */
257bcde4861SRafael Vanoni Polanczyk (void) cbreak();
258bcde4861SRafael Vanoni Polanczyk
259bcde4861SRafael Vanoni Polanczyk /*
260bcde4861SRafael Vanoni Polanczyk * Dont echo input
261bcde4861SRafael Vanoni Polanczyk */
262bcde4861SRafael Vanoni Polanczyk (void) noecho();
263bcde4861SRafael Vanoni Polanczyk
264bcde4861SRafael Vanoni Polanczyk /*
265bcde4861SRafael Vanoni Polanczyk * Turn off cursor
266bcde4861SRafael Vanoni Polanczyk */
267bcde4861SRafael Vanoni Polanczyk (void) curs_set(0);
268bcde4861SRafael Vanoni Polanczyk
269bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
270bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
271bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
272bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
273bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
274bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
275bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
276bcde4861SRafael Vanoni Polanczyk (void) init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
2779bbf5ba1SRafael Vanoni }
278bcde4861SRafael Vanoni Polanczyk
2799bbf5ba1SRafael Vanoni void
pt_display_update(void)2809bbf5ba1SRafael Vanoni pt_display_update(void)
2819bbf5ba1SRafael Vanoni {
2829bbf5ba1SRafael Vanoni (void) doupdate();
283bcde4861SRafael Vanoni Polanczyk }
284bcde4861SRafael Vanoni Polanczyk
285bcde4861SRafael Vanoni Polanczyk void
pt_display_title_bar(void)2869bbf5ba1SRafael Vanoni pt_display_title_bar(void)
287bcde4861SRafael Vanoni Polanczyk {
2882d83778aSRafael Vanoni char title_pad[10];
289bcde4861SRafael Vanoni Polanczyk
2909bbf5ba1SRafael Vanoni (void) wattrset(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
2919bbf5ba1SRafael Vanoni (void) wbkgd(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
2929bbf5ba1SRafael Vanoni (void) werase(sw[SW_TITLE]);
293bcde4861SRafael Vanoni Polanczyk
294bcde4861SRafael Vanoni Polanczyk (void) snprintf(title_pad, 10, "%%%ds",
2959bbf5ba1SRafael Vanoni (win_cols - strlen(TITLE))/2 + strlen(TITLE));
2969bbf5ba1SRafael Vanoni
297bcde4861SRafael Vanoni Polanczyk /* LINTED: E_SEC_PRINTF_VAR_FMT */
2989bbf5ba1SRafael Vanoni print(sw[SW_TITLE], 0, 0, title_pad, TITLE);
299bcde4861SRafael Vanoni Polanczyk
3009bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_TITLE]);
3019bbf5ba1SRafael Vanoni }
302bcde4861SRafael Vanoni Polanczyk
3039bbf5ba1SRafael Vanoni void
pt_display_status_bar(void)3049bbf5ba1SRafael Vanoni pt_display_status_bar(void)
3059bbf5ba1SRafael Vanoni {
3069bbf5ba1SRafael Vanoni sb_slot_t *n = status_bar;
3079bbf5ba1SRafael Vanoni int x = 0;
3089bbf5ba1SRafael Vanoni
3099bbf5ba1SRafael Vanoni (void) werase(sw[SW_STATUS]);
3109bbf5ba1SRafael Vanoni
3119bbf5ba1SRafael Vanoni while (n && x < win_cols) {
3129bbf5ba1SRafael Vanoni (void) wattron(sw[SW_STATUS], A_REVERSE);
3139bbf5ba1SRafael Vanoni print(sw[SW_STATUS], 0, x, "%s", n->msg);
3149bbf5ba1SRafael Vanoni (void) wattroff(sw[SW_STATUS], A_REVERSE);
3159bbf5ba1SRafael Vanoni x += strlen(n->msg) + 1;
3169bbf5ba1SRafael Vanoni
3179bbf5ba1SRafael Vanoni n = n->next;
318bcde4861SRafael Vanoni Polanczyk }
3199bbf5ba1SRafael Vanoni
3209bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_STATUS]);
321bcde4861SRafael Vanoni Polanczyk }
322bcde4861SRafael Vanoni Polanczyk
3239bbf5ba1SRafael Vanoni /*
3249bbf5ba1SRafael Vanoni * Adds or removes items to the status bar automatically.
3259bbf5ba1SRafael Vanoni * Only one instance of an item allowed.
3269bbf5ba1SRafael Vanoni */
327bcde4861SRafael Vanoni Polanczyk void
pt_display_mod_status_bar(char * msg)3289bbf5ba1SRafael Vanoni pt_display_mod_status_bar(char *msg)
329bcde4861SRafael Vanoni Polanczyk {
3309bbf5ba1SRafael Vanoni sb_slot_t *new, *n;
3319bbf5ba1SRafael Vanoni boolean_t found = B_FALSE, first = B_FALSE;
332bcde4861SRafael Vanoni Polanczyk
3339bbf5ba1SRafael Vanoni if (msg == NULL) {
3342d83778aSRafael Vanoni pt_error("can't add an empty status bar item\n");
3359bbf5ba1SRafael Vanoni return;
336bcde4861SRafael Vanoni Polanczyk }
337bcde4861SRafael Vanoni Polanczyk
3389bbf5ba1SRafael Vanoni if (status_bar != NULL) {
3399bbf5ba1SRafael Vanoni /*
3409bbf5ba1SRafael Vanoni * Non-empty status bar. Look for an entry matching this msg.
3419bbf5ba1SRafael Vanoni */
3429bbf5ba1SRafael Vanoni for (n = status_bar; n != NULL; n = n->next) {
3439bbf5ba1SRafael Vanoni
3449bbf5ba1SRafael Vanoni if (strcmp(msg, n->msg) == 0) {
3459bbf5ba1SRafael Vanoni if (n != status_bar)
3469bbf5ba1SRafael Vanoni n->prev->next = n->next;
3479bbf5ba1SRafael Vanoni else
3489bbf5ba1SRafael Vanoni first = B_TRUE;
3499bbf5ba1SRafael Vanoni
3509bbf5ba1SRafael Vanoni if (n->next != NULL) {
3519bbf5ba1SRafael Vanoni n->next->prev = n->prev;
3529bbf5ba1SRafael Vanoni if (first)
3539bbf5ba1SRafael Vanoni status_bar = n->next;
3549bbf5ba1SRafael Vanoni } else {
3559bbf5ba1SRafael Vanoni if (first)
3569bbf5ba1SRafael Vanoni status_bar = NULL;
3579bbf5ba1SRafael Vanoni }
3589bbf5ba1SRafael Vanoni
3599bbf5ba1SRafael Vanoni free(n);
3609bbf5ba1SRafael Vanoni found = B_TRUE;
3619bbf5ba1SRafael Vanoni }
3629bbf5ba1SRafael Vanoni }
363bcde4861SRafael Vanoni Polanczyk
364bcde4861SRafael Vanoni Polanczyk /*
3659bbf5ba1SRafael Vanoni * Found and removed at least one occurrance of msg, refresh
3669bbf5ba1SRafael Vanoni * the bar and return.
367bcde4861SRafael Vanoni Polanczyk */
3689bbf5ba1SRafael Vanoni if (found) {
3699bbf5ba1SRafael Vanoni return;
3709bbf5ba1SRafael Vanoni } else {
3719bbf5ba1SRafael Vanoni /*
3729bbf5ba1SRafael Vanoni * Inserting a new msg, walk to the end of the bar.
3739bbf5ba1SRafael Vanoni */
3749bbf5ba1SRafael Vanoni for (n = status_bar; n->next != NULL; n = n->next)
3759bbf5ba1SRafael Vanoni ;
3769bbf5ba1SRafael Vanoni }
3779bbf5ba1SRafael Vanoni }
3789bbf5ba1SRafael Vanoni
3799bbf5ba1SRafael Vanoni if ((new = calloc(1, sizeof (sb_slot_t))) == NULL) {
3802d83778aSRafael Vanoni pt_error("failed to allocate a new status bar slot\n");
3819bbf5ba1SRafael Vanoni } else {
3829bbf5ba1SRafael Vanoni new->msg = strdup(msg);
3839bbf5ba1SRafael Vanoni
3849bbf5ba1SRafael Vanoni /*
3859bbf5ba1SRafael Vanoni * Check if it's the first entry.
3869bbf5ba1SRafael Vanoni */
3879bbf5ba1SRafael Vanoni if (status_bar == NULL) {
3889bbf5ba1SRafael Vanoni status_bar = new;
3899bbf5ba1SRafael Vanoni new->prev = NULL;
3909bbf5ba1SRafael Vanoni } else {
3919bbf5ba1SRafael Vanoni new->prev = n;
3929bbf5ba1SRafael Vanoni n->next = new;
3939bbf5ba1SRafael Vanoni }
3949bbf5ba1SRafael Vanoni new->next = NULL;
3959bbf5ba1SRafael Vanoni }
3969bbf5ba1SRafael Vanoni }
397bcde4861SRafael Vanoni Polanczyk
3989bbf5ba1SRafael Vanoni void
pt_display_states(void)3999bbf5ba1SRafael Vanoni pt_display_states(void)
4009bbf5ba1SRafael Vanoni {
4019bbf5ba1SRafael Vanoni char c[100];
4029bbf5ba1SRafael Vanoni int i;
4039bbf5ba1SRafael Vanoni double total_pstates = 0.0, avg, res;
4049bbf5ba1SRafael Vanoni uint64_t p0_speed, p1_speed;
4059bbf5ba1SRafael Vanoni
4069bbf5ba1SRafael Vanoni print(sw[SW_IDLE], 0, 0, "%s\tAvg\tResidency\n", g_msg_idle_state);
4079bbf5ba1SRafael Vanoni
4089bbf5ba1SRafael Vanoni if (g_features & FEATURE_CSTATE) {
4099bbf5ba1SRafael Vanoni res = (((double)g_cstate_info[0].total_time / g_total_c_time))
410b47b5b34SRafael Vanoni * 100;
4119bbf5ba1SRafael Vanoni (void) sprintf(c, "C0 (cpu running)\t\t(%.1f%%)\n", (float)res);
4129bbf5ba1SRafael Vanoni print(sw[SW_IDLE], 1, 0, "%s", c);
413bcde4861SRafael Vanoni Polanczyk
4149bbf5ba1SRafael Vanoni for (i = 1; i <= g_max_cstate; i++) {
4159bbf5ba1SRafael Vanoni /*
4169bbf5ba1SRafael Vanoni * In situations where the load is too intensive, the
4179bbf5ba1SRafael Vanoni * system might not transition at all.
4189bbf5ba1SRafael Vanoni */
4199bbf5ba1SRafael Vanoni if (g_cstate_info[i].events > 0)
4209bbf5ba1SRafael Vanoni avg = (((double)g_cstate_info[i].total_time/
4219bbf5ba1SRafael Vanoni MICROSEC)/g_cstate_info[i].events);
4229bbf5ba1SRafael Vanoni else
4239bbf5ba1SRafael Vanoni avg = 0;
4249bbf5ba1SRafael Vanoni
4259bbf5ba1SRafael Vanoni res = ((double)g_cstate_info[i].total_time/
4269bbf5ba1SRafael Vanoni g_total_c_time) * 100;
4279bbf5ba1SRafael Vanoni
4289bbf5ba1SRafael Vanoni (void) sprintf(c, "C%d\t\t\t%.1fms\t(%.1f%%)\n",
4299bbf5ba1SRafael Vanoni i, (float)avg, (float)res);
4309bbf5ba1SRafael Vanoni print(sw[SW_IDLE], i + 1, 0, "%s", c);
4319bbf5ba1SRafael Vanoni }
432bcde4861SRafael Vanoni Polanczyk }
433bcde4861SRafael Vanoni Polanczyk
4349bbf5ba1SRafael Vanoni if (!PT_ON_DUMP)
4359bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_IDLE]);
436bcde4861SRafael Vanoni Polanczyk
4379bbf5ba1SRafael Vanoni print(sw[SW_FREQ], 0, 0, "%s\n", g_msg_freq_state);
4389bbf5ba1SRafael Vanoni
4399bbf5ba1SRafael Vanoni if (g_features & FEATURE_PSTATE) {
440b47b5b34SRafael Vanoni for (i = 0; i < g_npstates; i++) {
4419bbf5ba1SRafael Vanoni total_pstates +=
4429bbf5ba1SRafael Vanoni (double)(g_pstate_info[i].total_time/
443636423dbSRafael Vanoni g_ncpus_observed/MICROSEC);
444bcde4861SRafael Vanoni Polanczyk }
445bcde4861SRafael Vanoni Polanczyk
446e5bbdc06SRafael Vanoni /*
447e5bbdc06SRafael Vanoni * display ACPI_PSTATE from P(n) to P(1)
448e5bbdc06SRafael Vanoni */
449b47b5b34SRafael Vanoni for (i = 0; i < g_npstates - 1; i++) {
450bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "%4lu Mhz\t%.1f%%",
451b47b5b34SRafael Vanoni (long)g_pstate_info[i].speed,
4529bbf5ba1SRafael Vanoni 100 * (g_pstate_info[i].total_time/
4539bbf5ba1SRafael Vanoni g_ncpus_observed/MICROSEC/total_pstates));
4549bbf5ba1SRafael Vanoni print(sw[SW_FREQ], i+1, 0, "%s\n", c);
455bcde4861SRafael Vanoni Polanczyk }
456e5bbdc06SRafael Vanoni
457e5bbdc06SRafael Vanoni /*
458b47b5b34SRafael Vanoni * Display ACPI_PSTATE P0 according to if turbo
459e5bbdc06SRafael Vanoni * mode is supported
460e5bbdc06SRafael Vanoni */
461e5bbdc06SRafael Vanoni if (g_turbo_supported) {
4625951ced0SHans Rosenfeld int p_diff = 1;
4635951ced0SHans Rosenfeld p0_speed = g_pstate_info[g_npstates - 1].speed;
464b47b5b34SRafael Vanoni p1_speed = g_pstate_info[g_npstates - 2].speed;
465b47b5b34SRafael Vanoni
4665951ced0SHans Rosenfeld /*
4675951ced0SHans Rosenfeld * AMD systems don't have a visible extra Pstate
4685951ced0SHans Rosenfeld * indicating turbo mode as Intel does. Use the
4695951ced0SHans Rosenfeld * actual P0 frequency in that case.
4705951ced0SHans Rosenfeld */
4715951ced0SHans Rosenfeld if (p0_speed != p1_speed + 1) {
4725951ced0SHans Rosenfeld p1_speed = p0_speed;
4735951ced0SHans Rosenfeld p_diff = 0;
4745951ced0SHans Rosenfeld }
4755951ced0SHans Rosenfeld
476e5bbdc06SRafael Vanoni /*
477b47b5b34SRafael Vanoni * If g_turbo_ratio <= 1.0, it will be ignored.
4785951ced0SHans Rosenfeld * we display P(0) as P(1) + p_diff.
479e5bbdc06SRafael Vanoni */
480e5bbdc06SRafael Vanoni if (g_turbo_ratio <= 1.0) {
4815951ced0SHans Rosenfeld p0_speed = p1_speed + p_diff;
482b47b5b34SRafael Vanoni } else {
483b47b5b34SRafael Vanoni /*
4849bbf5ba1SRafael Vanoni * If g_turbo_ratio > 1.0, that means
4859bbf5ba1SRafael Vanoni * turbo mode works. So, P(0) = ratio *
4869bbf5ba1SRafael Vanoni * P(1);
487b47b5b34SRafael Vanoni */
4889bbf5ba1SRafael Vanoni p0_speed = (uint64_t)(p1_speed *
4899bbf5ba1SRafael Vanoni g_turbo_ratio);
4905951ced0SHans Rosenfeld if (p0_speed < (p1_speed + p_diff))
4915951ced0SHans Rosenfeld p0_speed = p1_speed + p_diff;
492e5bbdc06SRafael Vanoni }
493e5bbdc06SRafael Vanoni /*
494b47b5b34SRafael Vanoni * Reset the ratio for the next round
495e5bbdc06SRafael Vanoni */
496e5bbdc06SRafael Vanoni g_turbo_ratio = 0.0;
497e5bbdc06SRafael Vanoni
498e5bbdc06SRafael Vanoni /*
499b47b5b34SRafael Vanoni * Setup the string for the display
500e5bbdc06SRafael Vanoni */
501e5bbdc06SRafael Vanoni (void) sprintf(c, "%4lu Mhz(turbo)\t%.1f%%",
502e5bbdc06SRafael Vanoni (long)p0_speed,
503b47b5b34SRafael Vanoni 100 * (g_pstate_info[i].total_time/
504636423dbSRafael Vanoni g_ncpus_observed/MICROSEC/total_pstates));
505e5bbdc06SRafael Vanoni } else {
506e5bbdc06SRafael Vanoni (void) sprintf(c, "%4lu Mhz\t%.1f%%",
507b47b5b34SRafael Vanoni (long)g_pstate_info[i].speed,
508b47b5b34SRafael Vanoni 100 * (g_pstate_info[i].total_time/
509636423dbSRafael Vanoni g_ncpus_observed/MICROSEC/total_pstates));
510e5bbdc06SRafael Vanoni }
5119bbf5ba1SRafael Vanoni print(sw[SW_FREQ], i+1, 0, "%s\n", c);
5129bbf5ba1SRafael Vanoni } else {
5139bbf5ba1SRafael Vanoni if (g_npstates == 1) {
5149bbf5ba1SRafael Vanoni (void) sprintf(c, "%4lu Mhz\t%.1f%%",
5159bbf5ba1SRafael Vanoni (long)g_pstate_info[0].speed, 100.0);
5169bbf5ba1SRafael Vanoni print(sw[SW_FREQ], 1, 0, "%s\n", c);
5179bbf5ba1SRafael Vanoni }
518bcde4861SRafael Vanoni Polanczyk }
519b47b5b34SRafael Vanoni
520636423dbSRafael Vanoni if (!PT_ON_DUMP)
5219bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_FREQ]);
522bcde4861SRafael Vanoni Polanczyk }
523bcde4861SRafael Vanoni Polanczyk
524bcde4861SRafael Vanoni Polanczyk void
pt_display_acpi_power(uint32_t flag,double rate,double rem_cap,double cap,uint32_t state)5259bbf5ba1SRafael Vanoni pt_display_acpi_power(uint32_t flag, double rate, double rem_cap, double cap,
526bcde4861SRafael Vanoni Polanczyk uint32_t state)
527bcde4861SRafael Vanoni Polanczyk {
528bcde4861SRafael Vanoni Polanczyk char buffer[1024];
529bcde4861SRafael Vanoni Polanczyk
5302d83778aSRafael Vanoni (void) sprintf(buffer, "no ACPI power usage estimate available");
531bcde4861SRafael Vanoni Polanczyk
532636423dbSRafael Vanoni if (!PT_ON_DUMP)
5339bbf5ba1SRafael Vanoni (void) werase(sw[SW_POWER]);
5349bbf5ba1SRafael Vanoni
535bcde4861SRafael Vanoni Polanczyk if (flag) {
536bcde4861SRafael Vanoni Polanczyk char *c;
537bcde4861SRafael Vanoni Polanczyk (void) sprintf(buffer, "Power usage (ACPI estimate): %.3fW",
538bcde4861SRafael Vanoni Polanczyk rate);
539bcde4861SRafael Vanoni Polanczyk (void) strcat(buffer, " ");
540bcde4861SRafael Vanoni Polanczyk c = &buffer[strlen(buffer)];
541bcde4861SRafael Vanoni Polanczyk switch (state) {
542bcde4861SRafael Vanoni Polanczyk case 0:
543bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "(running on AC power, fully "
544bcde4861SRafael Vanoni Polanczyk "charged)");
545bcde4861SRafael Vanoni Polanczyk break;
546bcde4861SRafael Vanoni Polanczyk case 1:
547bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "(discharging: %3.1f hours)",
548b47b5b34SRafael Vanoni (uint32_t)rem_cap/rate);
549bcde4861SRafael Vanoni Polanczyk break;
550bcde4861SRafael Vanoni Polanczyk case 2:
551bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "(charging: %3.1f hours)",
552b47b5b34SRafael Vanoni (uint32_t)(cap - rem_cap)/rate);
553bcde4861SRafael Vanoni Polanczyk break;
554bcde4861SRafael Vanoni Polanczyk case 4:
555bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "(##critically low battery power##)");
556bcde4861SRafael Vanoni Polanczyk break;
557bcde4861SRafael Vanoni Polanczyk }
558bcde4861SRafael Vanoni Polanczyk
559bcde4861SRafael Vanoni Polanczyk }
5609bbf5ba1SRafael Vanoni
5619bbf5ba1SRafael Vanoni print(sw[SW_POWER], 0, 0, "%s\n", buffer);
562636423dbSRafael Vanoni if (!PT_ON_DUMP)
5639bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_POWER]);
564bcde4861SRafael Vanoni Polanczyk }
565bcde4861SRafael Vanoni Polanczyk
566bcde4861SRafael Vanoni Polanczyk void
pt_display_wakeups(double interval)5679bbf5ba1SRafael Vanoni pt_display_wakeups(double interval)
568bcde4861SRafael Vanoni Polanczyk {
569b47b5b34SRafael Vanoni char c[100];
570b47b5b34SRafael Vanoni int i, event_sum = 0;
571636423dbSRafael Vanoni event_info_t *event = g_event_info;
572bcde4861SRafael Vanoni Polanczyk
573636423dbSRafael Vanoni if (!PT_ON_DUMP) {
5749bbf5ba1SRafael Vanoni (void) werase(sw[SW_WAKEUPS]);
5759bbf5ba1SRafael Vanoni (void) wbkgd(sw[SW_WAKEUPS], COLOR_PAIR(PT_COLOR_RED));
5769bbf5ba1SRafael Vanoni (void) wattron(sw[SW_WAKEUPS], A_BOLD);
577bcde4861SRafael Vanoni Polanczyk }
578b47b5b34SRafael Vanoni
579b47b5b34SRafael Vanoni /*
580b47b5b34SRafael Vanoni * calculate the actual total event number
581b47b5b34SRafael Vanoni */
582636423dbSRafael Vanoni for (i = 0; i < g_top_events; i++, event++)
583636423dbSRafael Vanoni event_sum += event->total_count;
584b47b5b34SRafael Vanoni
585b47b5b34SRafael Vanoni /*
586b47b5b34SRafael Vanoni * g_total_events is the sum of the number of Cx->C0 transition,
587b47b5b34SRafael Vanoni * So when the system is very busy, the idle thread will have no
588b47b5b34SRafael Vanoni * chance or very seldom to be scheduled, this could cause >100%
589b47b5b34SRafael Vanoni * event report. Re-assign g_total_events to the actual event
590b47b5b34SRafael Vanoni * number is a way to avoid this issue.
591b47b5b34SRafael Vanoni */
592b47b5b34SRafael Vanoni if (event_sum > g_total_events)
593b47b5b34SRafael Vanoni g_total_events = event_sum;
594b47b5b34SRafael Vanoni
595bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "Wakeups-from-idle per second: %4.1f\tinterval: "
596b47b5b34SRafael Vanoni "%.1fs", (double)(g_total_events/interval), interval);
5979bbf5ba1SRafael Vanoni print(sw[SW_WAKEUPS], 0, 0, "%s\n", c);
598b47b5b34SRafael Vanoni
599636423dbSRafael Vanoni if (!PT_ON_DUMP)
6009bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_WAKEUPS]);
601bcde4861SRafael Vanoni Polanczyk }
602bcde4861SRafael Vanoni Polanczyk
603bcde4861SRafael Vanoni Polanczyk void
pt_display_events(double interval)6049bbf5ba1SRafael Vanoni pt_display_events(double interval)
605bcde4861SRafael Vanoni Polanczyk {
606bcde4861SRafael Vanoni Polanczyk char c[100];
607bcde4861SRafael Vanoni Polanczyk int i;
608bcde4861SRafael Vanoni Polanczyk double events;
609636423dbSRafael Vanoni event_info_t *event = g_event_info;
610bcde4861SRafael Vanoni Polanczyk
611636423dbSRafael Vanoni if (!PT_ON_DUMP) {
6129bbf5ba1SRafael Vanoni (void) werase(sw[SW_EVENTS]);
6139bbf5ba1SRafael Vanoni (void) wbkgd(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
6149bbf5ba1SRafael Vanoni (void) wattron(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
615bcde4861SRafael Vanoni Polanczyk }
616bcde4861SRafael Vanoni Polanczyk
617bcde4861SRafael Vanoni Polanczyk /*
618bcde4861SRafael Vanoni Polanczyk * Sort the event report list
619bcde4861SRafael Vanoni Polanczyk */
620636423dbSRafael Vanoni if (g_top_events > EVENT_NUM_MAX)
621636423dbSRafael Vanoni g_top_events = EVENT_NUM_MAX;
622bcde4861SRafael Vanoni Polanczyk
623636423dbSRafael Vanoni qsort((void *)g_event_info, g_top_events, sizeof (event_info_t),
6242d83778aSRafael Vanoni pt_event_compare);
625bcde4861SRafael Vanoni Polanczyk
626636423dbSRafael Vanoni if (PT_ON_CPU)
627b47b5b34SRafael Vanoni (void) sprintf(c, "Top causes for wakeups on CPU %d:\n",
628b47b5b34SRafael Vanoni g_observed_cpu);
629b47b5b34SRafael Vanoni else
630b47b5b34SRafael Vanoni (void) sprintf(c, "Top causes for wakeups:\n");
631b47b5b34SRafael Vanoni
6329bbf5ba1SRafael Vanoni print(sw[SW_EVENTS], 0, 0, "%s", c);
633bcde4861SRafael Vanoni Polanczyk
634636423dbSRafael Vanoni for (i = 0; i < g_top_events; i++, event++) {
635bcde4861SRafael Vanoni Polanczyk
636636423dbSRafael Vanoni if (g_total_events > 0 && event->total_count > 0)
637636423dbSRafael Vanoni events = (double)event->total_count/
638b47b5b34SRafael Vanoni (double)g_total_events;
639bcde4861SRafael Vanoni Polanczyk else
640b47b5b34SRafael Vanoni continue;
641bcde4861SRafael Vanoni Polanczyk
642bcde4861SRafael Vanoni Polanczyk (void) sprintf(c, "%4.1f%% (%5.1f)", 100 * events,
643636423dbSRafael Vanoni (double)event->total_count/interval);
6449bbf5ba1SRafael Vanoni print(sw[SW_EVENTS], i+1, 0, "%s", c);
6459bbf5ba1SRafael Vanoni print(sw[SW_EVENTS], i+1, 16, "%20s :",
646636423dbSRafael Vanoni event->offender_name);
6479bbf5ba1SRafael Vanoni print(sw[SW_EVENTS], i+1, 40, "%-64s\n",
648636423dbSRafael Vanoni event->offense_name);
649bcde4861SRafael Vanoni Polanczyk }
650b47b5b34SRafael Vanoni
651636423dbSRafael Vanoni if (!PT_ON_DUMP)
6529bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_EVENTS]);
653bcde4861SRafael Vanoni Polanczyk }
654bcde4861SRafael Vanoni Polanczyk
655bcde4861SRafael Vanoni Polanczyk void
pt_display_suggestions(char * sug)6569bbf5ba1SRafael Vanoni pt_display_suggestions(char *sug)
657bcde4861SRafael Vanoni Polanczyk {
6589bbf5ba1SRafael Vanoni (void) werase(sw[SW_SUGG]);
659bcde4861SRafael Vanoni Polanczyk
6609bbf5ba1SRafael Vanoni if (sug != NULL)
6619bbf5ba1SRafael Vanoni print(sw[SW_SUGG], 0, 0, "%s", sug);
6629bbf5ba1SRafael Vanoni
6639bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_SUGG]);
664bcde4861SRafael Vanoni Polanczyk }
665