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
38 static WINDOW *title_bar_window;
39 static WINDOW *cstate_window;
40 static WINDOW *wakeup_window;
41 static WINDOW *battery_power_window;
42 static WINDOW *timerstat_window;
43 static WINDOW *suggestion_window;
44 static 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
48 char status_bar_slots[10][40];
49
cleanup_curses(void)50 static void cleanup_curses(void) {
51 endwin();
52 }
53
zap_windows(void)54 static 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
87 int maxx, maxy;
88
89 int maxtimerstats = 50;
90 int maxwidth = 200;
91
setup_windows(void)92 void 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
initialize_curses(void)115 void 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
show_title_bar(void)138 void 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
show_cstates(void)164 void 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
show_acpi_power_line(double rate,double cap,double capdelta,time_t ti)192 void 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
show_pmu_power_line(unsigned sum_voltage_mV,unsigned sum_charge_mAh,unsigned sum_max_charge_mAh,int sum_discharge_mA)214 void 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
show_wakeups(double d,double interval,double C0time)252 void 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
show_timerstats(int nostats,int ticktime)274 void 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
show_suggestion(char * sug)311 void show_suggestion(char *sug)
312 {
313 werase(suggestion_window);
314 print(suggestion_window, 0, 0, "%s", sug);
315 wrefresh(suggestion_window);
316 }
317