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