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 /* 29*9e21aac0SMarcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 30*9e21aac0SMarcel Telka */ 31*9e21aac0SMarcel Telka 32*9e21aac0SMarcel Telka /* 33b47b5b34SRafael Vanoni * GPL Disclaimer 34b47b5b34SRafael Vanoni * 35b47b5b34SRafael Vanoni * For the avoidance of doubt, except that if any license choice other 36b47b5b34SRafael Vanoni * than GPL or LGPL is available it will apply instead, Sun elects to 37b47b5b34SRafael Vanoni * use only the General Public License version 2 (GPLv2) at this time 38b47b5b34SRafael Vanoni * for any software where a choice of GPL license versions is made 39b47b5b34SRafael Vanoni * available with the language indicating that GPLv2 or any later 40b47b5b34SRafael Vanoni * version may be used, or where a choice of which version of the GPL 41b47b5b34SRafael Vanoni * is applied is otherwise unspecified. 42b47b5b34SRafael Vanoni */ 43b47b5b34SRafael Vanoni 44b47b5b34SRafael Vanoni #include <stdlib.h> 45b47b5b34SRafael Vanoni #include <string.h> 469bbf5ba1SRafael Vanoni #include <unistd.h> 47b47b5b34SRafael Vanoni #include <curses.h> 489bbf5ba1SRafael Vanoni #include <signal.h> 499bbf5ba1SRafael Vanoni #include <fcntl.h> 50b47b5b34SRafael Vanoni #include "powertop.h" 51b47b5b34SRafael Vanoni 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 78b47b5b34SRafael Vanoni 79b47b5b34SRafael Vanoni #define print(win, y, x, fmt, args...) \ 80636423dbSRafael Vanoni if (PT_ON_DUMP) \ 81b47b5b34SRafael Vanoni (void) printf(fmt, ## args); \ 82b47b5b34SRafael Vanoni else \ 83b47b5b34SRafael Vanoni (void) mvwprintw(win, y, x, fmt, ## args); 84b47b5b34SRafael Vanoni 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 }; 96b47b5b34SRafael 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 */ 111b47b5b34SRafael Vanoni static void 1129bbf5ba1SRafael Vanoni pt_display_cleanup(void) 113b47b5b34SRafael 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'); 126b47b5b34SRafael Vanoni } 1279bbf5ba1SRafael Vanoni 1289bbf5ba1SRafael Vanoni static void 1299bbf5ba1SRafael Vanoni pt_display_get_size(void) 1309bbf5ba1SRafael Vanoni { 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); 138b47b5b34SRafael Vanoni } 139b47b5b34SRafael Vanoni } 140b47b5b34SRafael Vanoni 1412d83778aSRafael Vanoni void 1422d83778aSRafael Vanoni pt_display_resize(void) 143b47b5b34SRafael Vanoni { 1449bbf5ba1SRafael Vanoni pt_display_cleanup(); 1459bbf5ba1SRafael Vanoni (void) pt_display_init_curses(); 1469bbf5ba1SRafael Vanoni pt_display_setup(B_TRUE); 1479bbf5ba1SRafael Vanoni 1489bbf5ba1SRafael Vanoni pt_display_title_bar(); 1499bbf5ba1SRafael Vanoni 1502d83778aSRafael Vanoni pt_display_states(); 1512d83778aSRafael 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 } 1562d83778aSRafael Vanoni 1572d83778aSRafael Vanoni pt_battery_print(); 1582d83778aSRafael Vanoni pt_sugg_pick(); 1592d83778aSRafael Vanoni pt_display_status_bar(); 1602d83778aSRafael Vanoni 1619bbf5ba1SRafael Vanoni pt_display_update(); 1629bbf5ba1SRafael Vanoni 1632d83778aSRafael Vanoni g_sig_resize = B_FALSE; 1642d83778aSRafael Vanoni (void) signal(SIGWINCH, pt_sig_handler); 165b47b5b34SRafael Vanoni } 166b47b5b34SRafael Vanoni 167b47b5b34SRafael Vanoni /* 168b47b5b34SRafael Vanoni * This part was re-written to be human readable and easy to modify. Please 169b47b5b34SRafael Vanoni * try to keep it that way and help us save some time. 170b47b5b34SRafael Vanoni * 171b47b5b34SRafael Vanoni * Friendly reminder: 172b47b5b34SRafael Vanoni * subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x) 173b47b5b34SRafael Vanoni */ 174b47b5b34SRafael Vanoni void 1759bbf5ba1SRafael Vanoni pt_display_setup(boolean_t resized) 176b47b5b34SRafael Vanoni { 177b47b5b34SRafael Vanoni /* 178b47b5b34SRafael Vanoni * These variables are used to properly set the initial y position and 179b47b5b34SRafael Vanoni * number of lines in each subwindow, as the number of supported CPU 180b47b5b34SRafael Vanoni * states affects their placement. 181b47b5b34SRafael Vanoni */ 1829bbf5ba1SRafael Vanoni int cstate_lines, event_lines, pos_y = 0; 183b47b5b34SRafael Vanoni 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); 189b47b5b34SRafael Vanoni 1909bbf5ba1SRafael Vanoni sw[SW_TITLE] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0); 191b47b5b34SRafael Vanoni 192b47b5b34SRafael Vanoni 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); 196b47b5b34SRafael Vanoni 197b47b5b34SRafael Vanoni pos_y += cstate_lines + BLANK_LINE; 1989bbf5ba1SRafael Vanoni sw[SW_WAKEUPS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0); 199b47b5b34SRafael Vanoni 200b47b5b34SRafael Vanoni pos_y += NEXT_LINE; 2019bbf5ba1SRafael Vanoni sw[SW_POWER] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0); 202b47b5b34SRafael Vanoni 203b47b5b34SRafael Vanoni pos_y += NEXT_LINE + BLANK_LINE; 2049bbf5ba1SRafael Vanoni event_lines = win_rows - SINGLE_LINE_SW - NEXT_LINE - LENGTH_SUGG_SW - 205b47b5b34SRafael Vanoni pos_y; 206b47b5b34SRafael 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); 214b47b5b34SRafael Vanoni } 215b47b5b34SRafael Vanoni 2169bbf5ba1SRafael Vanoni pos_y += event_lines + NEXT_LINE; 2179bbf5ba1SRafael Vanoni sw[SW_SUGG] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0); 2189bbf5ba1SRafael Vanoni 2199bbf5ba1SRafael Vanoni pos_y += BLANK_LINE + NEXT_LINE; 2209bbf5ba1SRafael Vanoni sw[SW_STATUS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0); 2219bbf5ba1SRafael Vanoni 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 } 2289bbf5ba1SRafael Vanoni } 2299bbf5ba1SRafael Vanoni 2309bbf5ba1SRafael Vanoni /* 2319bbf5ba1SRafael Vanoni * This routine handles all the necessary curses initialization. 2329bbf5ba1SRafael Vanoni */ 233b47b5b34SRafael Vanoni void 2349bbf5ba1SRafael Vanoni pt_display_init_curses(void) 235b47b5b34SRafael Vanoni { 236b47b5b34SRafael Vanoni (void) initscr(); 2379bbf5ba1SRafael Vanoni 2389bbf5ba1SRafael Vanoni (void) atexit(pt_display_cleanup); 2399bbf5ba1SRafael Vanoni 2409bbf5ba1SRafael Vanoni pt_display_get_size(); 2419bbf5ba1SRafael Vanoni 242b47b5b34SRafael Vanoni (void) start_color(); 243b47b5b34SRafael Vanoni 244b47b5b34SRafael Vanoni /* 245b47b5b34SRafael Vanoni * Enable keyboard mapping 246b47b5b34SRafael Vanoni */ 247b47b5b34SRafael Vanoni (void) keypad(stdscr, TRUE); 248b47b5b34SRafael Vanoni 249b47b5b34SRafael Vanoni /* 250b47b5b34SRafael Vanoni * Tell curses not to do NL->CR/NL on output 251b47b5b34SRafael Vanoni */ 252b47b5b34SRafael Vanoni (void) nonl(); 253b47b5b34SRafael Vanoni 254b47b5b34SRafael Vanoni /* 255b47b5b34SRafael Vanoni * Take input chars one at a time, no wait for \n 256b47b5b34SRafael Vanoni */ 257b47b5b34SRafael Vanoni (void) cbreak(); 258b47b5b34SRafael Vanoni 259b47b5b34SRafael Vanoni /* 260b47b5b34SRafael Vanoni * Dont echo input 261b47b5b34SRafael Vanoni */ 262b47b5b34SRafael Vanoni (void) noecho(); 263b47b5b34SRafael Vanoni 264b47b5b34SRafael Vanoni /* 265b47b5b34SRafael Vanoni * Turn off cursor 266b47b5b34SRafael Vanoni */ 267b47b5b34SRafael Vanoni (void) curs_set(0); 268b47b5b34SRafael Vanoni 269b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); 270b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); 271b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); 272b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); 273b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); 274b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); 275b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE); 276b47b5b34SRafael Vanoni (void) init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); 277b47b5b34SRafael Vanoni } 278b47b5b34SRafael Vanoni 279b47b5b34SRafael Vanoni void 2809bbf5ba1SRafael Vanoni pt_display_update(void) 281b47b5b34SRafael Vanoni { 2829bbf5ba1SRafael Vanoni (void) doupdate(); 2839bbf5ba1SRafael Vanoni } 2849bbf5ba1SRafael Vanoni 2859bbf5ba1SRafael Vanoni void 2869bbf5ba1SRafael Vanoni pt_display_title_bar(void) 2879bbf5ba1SRafael Vanoni { 288b47b5b34SRafael Vanoni char title_pad[10]; 289b47b5b34SRafael Vanoni 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]); 293b47b5b34SRafael Vanoni 294b47b5b34SRafael Vanoni (void) snprintf(title_pad, 10, "%%%ds", 2959bbf5ba1SRafael Vanoni (win_cols - strlen(TITLE))/2 + strlen(TITLE)); 2969bbf5ba1SRafael Vanoni 297b47b5b34SRafael Vanoni /* LINTED: E_SEC_PRINTF_VAR_FMT */ 2989bbf5ba1SRafael Vanoni print(sw[SW_TITLE], 0, 0, title_pad, TITLE); 299b47b5b34SRafael Vanoni 3009bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_TITLE]); 301b47b5b34SRafael Vanoni } 302b47b5b34SRafael Vanoni 303b47b5b34SRafael Vanoni 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; 3189bbf5ba1SRafael Vanoni } 3199bbf5ba1SRafael Vanoni 3209bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_STATUS]); 3219bbf5ba1SRafael Vanoni } 3229bbf5ba1SRafael Vanoni 3239bbf5ba1SRafael Vanoni /* 3249bbf5ba1SRafael Vanoni * Adds or removes items to the status bar automatically. 3259bbf5ba1SRafael Vanoni * Only one instance of an item allowed. 3269bbf5ba1SRafael Vanoni */ 3279bbf5ba1SRafael Vanoni void 3289bbf5ba1SRafael Vanoni pt_display_mod_status_bar(char *msg) 3299bbf5ba1SRafael Vanoni { 3309bbf5ba1SRafael Vanoni sb_slot_t *new, *n; 3319bbf5ba1SRafael Vanoni boolean_t found = B_FALSE, first = B_FALSE; 3329bbf5ba1SRafael Vanoni 3339bbf5ba1SRafael Vanoni if (msg == NULL) { 3342d83778aSRafael Vanoni pt_error("can't add an empty status bar item\n"); 3359bbf5ba1SRafael Vanoni return; 3369bbf5ba1SRafael Vanoni } 3379bbf5ba1SRafael Vanoni 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 } 3639bbf5ba1SRafael Vanoni 3649bbf5ba1SRafael Vanoni /* 3659bbf5ba1SRafael Vanoni * Found and removed at least one occurrance of msg, refresh 3669bbf5ba1SRafael Vanoni * the bar and return. 3679bbf5ba1SRafael Vanoni */ 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 } 3979bbf5ba1SRafael Vanoni 3989bbf5ba1SRafael Vanoni void 3999bbf5ba1SRafael Vanoni pt_display_states(void) 400b47b5b34SRafael Vanoni { 401b47b5b34SRafael Vanoni char c[100]; 402b47b5b34SRafael Vanoni int i; 403b47b5b34SRafael Vanoni double total_pstates = 0.0, avg, res; 404b47b5b34SRafael Vanoni uint64_t p0_speed, p1_speed; 405b47b5b34SRafael Vanoni 4069bbf5ba1SRafael Vanoni print(sw[SW_IDLE], 0, 0, "%s\tAvg\tResidency\n", g_msg_idle_state); 407b47b5b34SRafael Vanoni 4089bbf5ba1SRafael Vanoni if (g_features & FEATURE_CSTATE) { 4099bbf5ba1SRafael Vanoni res = (((double)g_cstate_info[0].total_time / g_total_c_time)) 4109bbf5ba1SRafael Vanoni * 100; 411b47b5b34SRafael Vanoni (void) sprintf(c, "C0 (cpu running)\t\t(%.1f%%)\n", (float)res); 4129bbf5ba1SRafael Vanoni print(sw[SW_IDLE], 1, 0, "%s", c); 413b47b5b34SRafael Vanoni 414b47b5b34SRafael Vanoni for (i = 1; i <= g_max_cstate; i++) { 415b47b5b34SRafael Vanoni /* 4169bbf5ba1SRafael Vanoni * In situations where the load is too intensive, the 4179bbf5ba1SRafael Vanoni * system might not transition at all. 418b47b5b34SRafael Vanoni */ 419b47b5b34SRafael Vanoni if (g_cstate_info[i].events > 0) 420b47b5b34SRafael Vanoni avg = (((double)g_cstate_info[i].total_time/ 421636423dbSRafael Vanoni MICROSEC)/g_cstate_info[i].events); 422b47b5b34SRafael Vanoni else 423b47b5b34SRafael Vanoni avg = 0; 424b47b5b34SRafael Vanoni 4259bbf5ba1SRafael Vanoni res = ((double)g_cstate_info[i].total_time/ 4269bbf5ba1SRafael Vanoni g_total_c_time) * 100; 427b47b5b34SRafael 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 } 432b47b5b34SRafael Vanoni } 433b47b5b34SRafael Vanoni 4349bbf5ba1SRafael Vanoni if (!PT_ON_DUMP) 4359bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_IDLE]); 436b47b5b34SRafael Vanoni 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); 444b47b5b34SRafael Vanoni } 445b47b5b34SRafael Vanoni 446b47b5b34SRafael Vanoni /* 447b47b5b34SRafael Vanoni * display ACPI_PSTATE from P(n) to P(1) 448b47b5b34SRafael Vanoni */ 449b47b5b34SRafael Vanoni for (i = 0; i < g_npstates - 1; i++) { 450b47b5b34SRafael Vanoni (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); 455b47b5b34SRafael Vanoni } 456b47b5b34SRafael Vanoni 457b47b5b34SRafael Vanoni /* 458b47b5b34SRafael Vanoni * Display ACPI_PSTATE P0 according to if turbo 459b47b5b34SRafael Vanoni * mode is supported 460b47b5b34SRafael Vanoni */ 461b47b5b34SRafael 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 466b47b5b34SRafael Vanoni /* 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 4765951ced0SHans Rosenfeld /* 477b47b5b34SRafael Vanoni * If g_turbo_ratio <= 1.0, it will be ignored. 4785951ced0SHans Rosenfeld * we display P(0) as P(1) + p_diff. 479b47b5b34SRafael Vanoni */ 480b47b5b34SRafael 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; 492b47b5b34SRafael Vanoni } 493b47b5b34SRafael Vanoni /* 494b47b5b34SRafael Vanoni * Reset the ratio for the next round 495b47b5b34SRafael Vanoni */ 496b47b5b34SRafael Vanoni g_turbo_ratio = 0.0; 497b47b5b34SRafael Vanoni 498b47b5b34SRafael Vanoni /* 499b47b5b34SRafael Vanoni * Setup the string for the display 500b47b5b34SRafael Vanoni */ 501b47b5b34SRafael Vanoni (void) sprintf(c, "%4lu Mhz(turbo)\t%.1f%%", 502b47b5b34SRafael Vanoni (long)p0_speed, 503b47b5b34SRafael Vanoni 100 * (g_pstate_info[i].total_time/ 504636423dbSRafael Vanoni g_ncpus_observed/MICROSEC/total_pstates)); 505b47b5b34SRafael Vanoni } else { 506b47b5b34SRafael 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)); 510b47b5b34SRafael 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 } 518b47b5b34SRafael Vanoni } 519b47b5b34SRafael Vanoni 520636423dbSRafael Vanoni if (!PT_ON_DUMP) 5219bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_FREQ]); 522b47b5b34SRafael Vanoni } 523b47b5b34SRafael Vanoni 524b47b5b34SRafael Vanoni void 5259bbf5ba1SRafael Vanoni pt_display_acpi_power(uint32_t flag, double rate, double rem_cap, double cap, 526b47b5b34SRafael Vanoni uint32_t state) 527b47b5b34SRafael Vanoni { 528b47b5b34SRafael Vanoni char buffer[1024]; 529b47b5b34SRafael Vanoni 5302d83778aSRafael Vanoni (void) sprintf(buffer, "no ACPI power usage estimate available"); 531b47b5b34SRafael Vanoni 532636423dbSRafael Vanoni if (!PT_ON_DUMP) 5339bbf5ba1SRafael Vanoni (void) werase(sw[SW_POWER]); 5349bbf5ba1SRafael Vanoni 535b47b5b34SRafael Vanoni if (flag) { 536b47b5b34SRafael Vanoni char *c; 537b47b5b34SRafael Vanoni (void) sprintf(buffer, "Power usage (ACPI estimate): %.3fW", 538b47b5b34SRafael Vanoni rate); 539b47b5b34SRafael Vanoni (void) strcat(buffer, " "); 540b47b5b34SRafael Vanoni c = &buffer[strlen(buffer)]; 541b47b5b34SRafael Vanoni switch (state) { 542b47b5b34SRafael Vanoni case 0: 543b47b5b34SRafael Vanoni (void) sprintf(c, "(running on AC power, fully " 544b47b5b34SRafael Vanoni "charged)"); 545b47b5b34SRafael Vanoni break; 546b47b5b34SRafael Vanoni case 1: 547b47b5b34SRafael Vanoni (void) sprintf(c, "(discharging: %3.1f hours)", 548b47b5b34SRafael Vanoni (uint32_t)rem_cap/rate); 549b47b5b34SRafael Vanoni break; 550b47b5b34SRafael Vanoni case 2: 551b47b5b34SRafael Vanoni (void) sprintf(c, "(charging: %3.1f hours)", 552b47b5b34SRafael Vanoni (uint32_t)(cap - rem_cap)/rate); 553b47b5b34SRafael Vanoni break; 554b47b5b34SRafael Vanoni case 4: 555b47b5b34SRafael Vanoni (void) sprintf(c, "(##critically low battery power##)"); 556b47b5b34SRafael Vanoni break; 557b47b5b34SRafael Vanoni } 558b47b5b34SRafael Vanoni 559b47b5b34SRafael Vanoni } 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]); 564b47b5b34SRafael Vanoni } 565b47b5b34SRafael Vanoni 566b47b5b34SRafael Vanoni void 5679bbf5ba1SRafael Vanoni pt_display_wakeups(double interval) 568b47b5b34SRafael Vanoni { 569b47b5b34SRafael Vanoni char c[100]; 570b47b5b34SRafael Vanoni int i, event_sum = 0; 571636423dbSRafael Vanoni event_info_t *event = g_event_info; 572b47b5b34SRafael Vanoni 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); 577b47b5b34SRafael Vanoni } 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 595b47b5b34SRafael Vanoni (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]); 601b47b5b34SRafael Vanoni } 602b47b5b34SRafael Vanoni 603b47b5b34SRafael Vanoni void 6049bbf5ba1SRafael Vanoni pt_display_events(double interval) 605b47b5b34SRafael Vanoni { 606b47b5b34SRafael Vanoni char c[100]; 607b47b5b34SRafael Vanoni int i; 608b47b5b34SRafael Vanoni double events; 609636423dbSRafael Vanoni event_info_t *event = g_event_info; 610b47b5b34SRafael Vanoni 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)); 615b47b5b34SRafael Vanoni } 616b47b5b34SRafael Vanoni 617b47b5b34SRafael Vanoni /* 618b47b5b34SRafael Vanoni * Sort the event report list 619b47b5b34SRafael Vanoni */ 620636423dbSRafael Vanoni if (g_top_events > EVENT_NUM_MAX) 621636423dbSRafael Vanoni g_top_events = EVENT_NUM_MAX; 622b47b5b34SRafael Vanoni 623636423dbSRafael Vanoni qsort((void *)g_event_info, g_top_events, sizeof (event_info_t), 6242d83778aSRafael Vanoni pt_event_compare); 625b47b5b34SRafael Vanoni 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); 633b47b5b34SRafael Vanoni 634636423dbSRafael Vanoni for (i = 0; i < g_top_events; i++, event++) { 635b47b5b34SRafael Vanoni 636636423dbSRafael Vanoni if (g_total_events > 0 && event->total_count > 0) 637636423dbSRafael Vanoni events = (double)event->total_count/ 638b47b5b34SRafael Vanoni (double)g_total_events; 639b47b5b34SRafael Vanoni else 640b47b5b34SRafael Vanoni continue; 641b47b5b34SRafael Vanoni 642b47b5b34SRafael Vanoni (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); 649b47b5b34SRafael Vanoni } 650b47b5b34SRafael Vanoni 651636423dbSRafael Vanoni if (!PT_ON_DUMP) 6529bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_EVENTS]); 653b47b5b34SRafael Vanoni } 654b47b5b34SRafael Vanoni 655b47b5b34SRafael Vanoni void 6569bbf5ba1SRafael Vanoni pt_display_suggestions(char *sug) 657b47b5b34SRafael Vanoni { 6589bbf5ba1SRafael Vanoni (void) werase(sw[SW_SUGG]); 659b47b5b34SRafael Vanoni 6609bbf5ba1SRafael Vanoni if (sug != NULL) 6619bbf5ba1SRafael Vanoni print(sw[SW_SUGG], 0, 0, "%s", sug); 6629bbf5ba1SRafael Vanoni 6639bbf5ba1SRafael Vanoni (void) wnoutrefresh(sw[SW_SUGG]); 664b47b5b34SRafael Vanoni } 665