1/* 2 * Copyright 2007, Intel Corporation 3 * 4 * This file is part of PowerTOP 5 * 6 * This program file is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program in a file named COPYING; if not, write to the 17 * Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301 USA 20 * 21 * Authors: 22 * Arjan van de Ven <arjan@linux.intel.com> 23 */ 24 25#include <unistd.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <stdint.h> 30#include <sys/types.h> 31#include <dirent.h> 32#include <ncurses.h> 33#include <time.h> 34#include <wchar.h> 35 36#include "powertop.h" 37 38static WINDOW *title_bar_window; 39static WINDOW *cstate_window; 40static WINDOW *wakeup_window; 41static WINDOW *battery_power_window; 42static WINDOW *timerstat_window; 43static WINDOW *suggestion_window; 44static WINDOW *status_bar_window; 45 46#define print(win, y, x, fmt, args...) do { if (dump) printf(fmt, ## args); else mvwprintw(win, y, x, fmt, ## args); } while (0) 47 48char status_bar_slots[10][40]; 49 50static void cleanup_curses(void) { 51 endwin(); 52} 53 54static void zap_windows(void) 55{ 56 if (title_bar_window) { 57 delwin(title_bar_window); 58 title_bar_window = NULL; 59 } 60 if (cstate_window) { 61 delwin(cstate_window); 62 cstate_window = NULL; 63 } 64 if (wakeup_window) { 65 delwin(wakeup_window); 66 wakeup_window = NULL; 67 } 68 if (battery_power_window) { 69 delwin(battery_power_window); 70 battery_power_window = NULL; 71 } 72 if (timerstat_window) { 73 delwin(timerstat_window); 74 timerstat_window = NULL; 75 } 76 if (suggestion_window) { 77 delwin(suggestion_window); 78 suggestion_window = NULL; 79 } 80 if (status_bar_window) { 81 delwin(status_bar_window); 82 status_bar_window = NULL; 83 } 84} 85 86 87int maxx, maxy; 88 89int maxtimerstats = 50; 90int maxwidth = 200; 91 92void setup_windows(void) 93{ 94 getmaxyx(stdscr, maxy, maxx); 95 96 zap_windows(); 97 98 title_bar_window = subwin(stdscr, 1, maxx, 0, 0); 99 cstate_window = subwin(stdscr, 7, maxx, 2, 0); 100 wakeup_window = subwin(stdscr, 1, maxx, 9, 0); 101 battery_power_window = subwin(stdscr, 2, maxx, 10, 0); 102 timerstat_window = subwin(stdscr, maxy-16, maxx, 12, 0); 103 maxtimerstats = maxy-16 -2; 104 maxwidth = maxx - 18; 105 suggestion_window = subwin(stdscr, 3, maxx, maxy-4, 0); 106 status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0); 107 108 strcpy(status_bar_slots[0], _(" Q - Quit ")); 109 strcpy(status_bar_slots[1], _(" R - Refresh ")); 110 111 werase(stdscr); 112 refresh(); 113} 114 115void initialize_curses(void) 116{ 117 initscr(); 118 start_color(); 119 keypad(stdscr, TRUE); /* enable keyboard mapping */ 120 nonl(); /* tell curses not to do NL->CR/NL on output */ 121 cbreak(); /* take input chars one at a time, no wait for \n */ 122 noecho(); /* dont echo input */ 123 curs_set(0); /* turn off cursor */ 124 use_default_colors(); 125 126 init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); 127 init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); 128 init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); 129 init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); 130 init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); 131 init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); 132 init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE); 133 init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); 134 135 atexit(cleanup_curses); 136} 137 138void show_title_bar(void) 139{ 140 int i; 141 int x; 142 wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 143 wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); 144 werase(title_bar_window); 145 146 print(title_bar_window, 0, 0, " PowerTOP version 1.11 (C) 2007 Intel Corporation"); 147 148 wrefresh(title_bar_window); 149 150 werase(status_bar_window); 151 152 x = 0; 153 for (i=0; i<10; i++) { 154 if (strlen(status_bar_slots[i])==0) 155 continue; 156 wattron(status_bar_window, A_REVERSE); 157 print(status_bar_window, 0, x, status_bar_slots[i]); 158 wattroff(status_bar_window, A_REVERSE); 159 x+= strlen(status_bar_slots[i])+1; 160 } 161 wrefresh(status_bar_window); 162} 163 164void show_cstates(void) 165{ 166 int i, count = 0; 167 werase(cstate_window); 168 169 for (i=0; i < 10; i++) { 170 if (i == topcstate+1) 171 wattron(cstate_window, A_BOLD); 172 else 173 wattroff(cstate_window, A_BOLD); 174 if (strlen(cstate_lines[i]) && count <= 6) { 175 print(cstate_window, count, 0, "%s", cstate_lines[i]); 176 count++; 177 } 178 } 179 180 for (i=0; i<6; i++) { 181 if (i == topfreq+1) 182 wattron(cstate_window, A_BOLD); 183 else 184 wattroff(cstate_window, A_BOLD); 185 print(cstate_window, i, 38, "%s", cpufreqstrings[i]); 186 } 187 188 wrefresh(cstate_window); 189} 190 191 192void show_acpi_power_line(double rate, double cap, double capdelta, time_t ti) 193{ 194 char buffer[1024]; 195 196 sprintf(buffer, _("no ACPI power usage estimate available") ); 197 198 werase(battery_power_window); 199 if (rate > 0.001) { 200 char *c; 201 sprintf(buffer, _("Power usage (ACPI estimate): %3.1fW (%3.1f hours)"), rate, cap/rate); 202 strcat(buffer, " "); 203 c = &buffer[strlen(buffer)]; 204 if (ti>180 && capdelta > 0) 205 sprintf(c, _("(long term: %3.1fW,/%3.1fh)"), 3600*capdelta / ti, cap / (3600*capdelta/ti+0.01)); 206 } 207 else if (ti>120 && capdelta > 0.001) 208 sprintf(buffer, _("Power usage (5 minute ACPI estimate) : %5.1f W (%3.1f hours left)"), 3600*capdelta / ti, cap / (3600*capdelta/ti+0.01)); 209 210 print(battery_power_window, 0, 0, "%s\n", buffer); 211 wrefresh(battery_power_window); 212} 213 214void show_pmu_power_line(unsigned sum_voltage_mV, 215 unsigned sum_charge_mAh, unsigned sum_max_charge_mAh, 216 int sum_discharge_mA) 217{ 218 char buffer[1024]; 219 220 if (sum_discharge_mA != 0) 221 { 222 unsigned remaining_charge_mAh; 223 224 if (sum_discharge_mA < 0) 225 { 226 /* we are currently discharging */ 227 sum_discharge_mA = -sum_discharge_mA; 228 remaining_charge_mAh = sum_charge_mAh; 229 } 230 else 231 { 232 /* we are currently charging */ 233 remaining_charge_mAh = (sum_max_charge_mAh 234 - sum_charge_mAh); 235 } 236 237 snprintf(buffer, sizeof(buffer), 238 _("Power usage: %3.1fW (%3.1f hours)"), 239 sum_voltage_mV * sum_discharge_mA / 1e6, 240 (double)remaining_charge_mAh / sum_discharge_mA); 241 } 242 else 243 snprintf(buffer, sizeof(buffer), 244 _("no power usage estimate available") ); 245 246 werase(battery_power_window); 247 print(battery_power_window, 0, 0, "%s\n", buffer); 248 wrefresh(battery_power_window); 249} 250 251 252void show_wakeups(double d, double interval, double C0time) 253{ 254 werase(wakeup_window); 255 256 wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_RED)); 257 if (d <= 25.0) 258 wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_YELLOW)); 259 if (d <= 10.0) 260 wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_GREEN)); 261 262 /* 263 * if the cpu is really busy.... then make it blue to indicate 264 * that it's not the primary power consumer anymore 265 */ 266 if (C0time > 25.0) 267 wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_BLUE)); 268 269 wattron(wakeup_window, A_BOLD); 270 print(wakeup_window, 0, 0, _("Wakeups-from-idle per second : %4.1f\tinterval: %0.1fs\n"), d, interval); 271 wrefresh(wakeup_window); 272} 273 274void show_timerstats(int nostats, int ticktime) 275{ 276 int i; 277 werase(timerstat_window); 278 279 if (!nostats) { 280 int counter = 0; 281 print(timerstat_window, 0, 0, _("Top causes for wakeups:\n")); 282 for (i = 0; i < linehead; i++) 283 if (lines[i].count > 0 && counter++ < maxtimerstats) { 284 if ((lines[i].count * 1.0 / ticktime) >= 10.0) 285 wattron(timerstat_window, A_BOLD); 286 else 287 wattroff(timerstat_window, A_BOLD); 288 if (showpids) 289 print(timerstat_window, i+1, 0," %5.1f%% (%5.1f) [%6s] %s \n", lines[i].count * 100.0 / linectotal, 290 lines[i].count * 1.0 / ticktime, 291 lines[i].pid, lines[i].string); 292 else 293 print(timerstat_window, i+1, 0," %5.1f%% (%5.1f) %s \n", lines[i].count * 100.0 / linectotal, 294 lines[i].count * 1.0 / ticktime, 295 lines[i].string); 296 } 297 } else { 298 if (geteuid() == 0) { 299 print(timerstat_window, 0, 0, _("No detailed statistics available; please enable the CONFIG_TIMER_STATS kernel option\n")); 300 print(timerstat_window, 1, 0, _("This option is located in the Kernel Debugging section of menuconfig\n")); 301 print(timerstat_window, 2, 0, _("(which is CONFIG_DEBUG_KERNEL=y in the config file)\n")); 302 print(timerstat_window, 3, 0, _("Note: this is only available in 2.6.21 and later kernels\n")); 303 } else 304 print(timerstat_window, 0, 0, _("No detailed statistics available; PowerTOP needs root privileges for that\n")); 305 } 306 307 308 wrefresh(timerstat_window); 309} 310 311void show_suggestion(char *sug) 312{ 313 werase(suggestion_window); 314 print(suggestion_window, 0, 0, "%s", sug); 315 wrefresh(suggestion_window); 316} 317