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