386 lines
10 KiB
C
386 lines
10 KiB
C
/*
|
|
* Copyright 2007, Intel Corporation
|
|
*
|
|
* This file is part of PowerTOP
|
|
*
|
|
* This program file is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program in a file named COPYING; if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA
|
|
*
|
|
* Authors:
|
|
* Arjan van de Ven <arjan@linux.intel.com>
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <time.h>
|
|
#include "powertop.h"
|
|
|
|
#ifndef NO_NCURSES
|
|
#include <ncurses.h>
|
|
#include <wchar.h>
|
|
#endif
|
|
|
|
|
|
#ifdef NO_NCURSES
|
|
#define WINDOW void
|
|
#endif
|
|
|
|
static WINDOW *title_bar_window;
|
|
static WINDOW *cstate_window;
|
|
static WINDOW *wakeup_window;
|
|
static WINDOW *battery_power_window;
|
|
static WINDOW *timerstat_window;
|
|
static WINDOW *suggestion_window;
|
|
static WINDOW *status_bar_window;
|
|
|
|
#ifndef NO_NCURSES
|
|
#define print(win, y, x, fmt, args...) do { if (dump) printf(fmt, ## args); else mvwprintw(win, y, x, fmt, ## args); } while (0)
|
|
|
|
#else
|
|
|
|
#define print(win, y, x, fmt, args...) do { printf(fmt, ## args); } while (0)
|
|
#define endwin(x)
|
|
#define delwin(x)
|
|
#define werase(x)
|
|
#define wrefresh(x) printf("\n")
|
|
#define wattron(x, y)
|
|
#define wattroff(x, y)
|
|
#define wbkgd(x, y)
|
|
#define wattrset(x, y)
|
|
#define COLOR_PAIR(x)
|
|
|
|
#endif
|
|
|
|
char status_bar_slots[10][40];
|
|
|
|
static void cleanup_curses(void) {
|
|
endwin();
|
|
}
|
|
|
|
static void zap_windows(void)
|
|
{
|
|
if (title_bar_window) {
|
|
delwin(title_bar_window);
|
|
title_bar_window = NULL;
|
|
}
|
|
if (cstate_window) {
|
|
delwin(cstate_window);
|
|
cstate_window = NULL;
|
|
}
|
|
if (wakeup_window) {
|
|
delwin(wakeup_window);
|
|
wakeup_window = NULL;
|
|
}
|
|
if (battery_power_window) {
|
|
delwin(battery_power_window);
|
|
battery_power_window = NULL;
|
|
}
|
|
if (timerstat_window) {
|
|
delwin(timerstat_window);
|
|
timerstat_window = NULL;
|
|
}
|
|
if (suggestion_window) {
|
|
delwin(suggestion_window);
|
|
suggestion_window = NULL;
|
|
}
|
|
if (status_bar_window) {
|
|
delwin(status_bar_window);
|
|
status_bar_window = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
int maxx, maxy;
|
|
|
|
int maxtimerstats = 50;
|
|
int maxwidth = 200;
|
|
|
|
void setup_windows(void)
|
|
{
|
|
#ifndef NO_NCURSES
|
|
getmaxyx(stdscr, maxy, maxx);
|
|
|
|
zap_windows();
|
|
|
|
title_bar_window = subwin(stdscr, 1, maxx, 0, 0);
|
|
cstate_window = subwin(stdscr, 7, maxx, 2, 0);
|
|
wakeup_window = subwin(stdscr, 1, maxx, 9, 0);
|
|
battery_power_window = subwin(stdscr, 2, maxx, 10, 0);
|
|
timerstat_window = subwin(stdscr, maxy-16, maxx, 12, 0);
|
|
maxtimerstats = maxy-16 -2;
|
|
maxwidth = maxx - 18;
|
|
suggestion_window = subwin(stdscr, 3, maxx, maxy-4, 0);
|
|
status_bar_window = subwin(stdscr, 1, maxx, maxy-1, 0);
|
|
|
|
strcpy(status_bar_slots[0], _(" Q - Quit "));
|
|
strcpy(status_bar_slots[1], _(" R - Refresh "));
|
|
|
|
werase(stdscr);
|
|
refresh();
|
|
#endif
|
|
}
|
|
|
|
void initialize_curses(void)
|
|
{
|
|
#ifndef NO_NCURSES
|
|
initscr();
|
|
start_color();
|
|
keypad(stdscr, TRUE); /* enable keyboard mapping */
|
|
nonl(); /* tell curses not to do NL->CR/NL on output */
|
|
cbreak(); /* take input chars one at a time, no wait for \n */
|
|
noecho(); /* dont echo input */
|
|
curs_set(0); /* turn off cursor */
|
|
use_default_colors();
|
|
|
|
init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
|
|
init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE);
|
|
init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
|
|
init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
|
|
init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
|
|
init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
|
|
init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
|
|
init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
|
|
|
|
atexit(cleanup_curses);
|
|
#endif
|
|
}
|
|
|
|
void show_title_bar(void)
|
|
{
|
|
int i;
|
|
int x;
|
|
wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
|
|
wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
|
|
werase(title_bar_window);
|
|
|
|
/*
|
|
print(title_bar_window, 0, 0, " PowerTOP version 1.11 (C) 2007 Intel Corporation");
|
|
*/
|
|
|
|
wrefresh(title_bar_window);
|
|
|
|
werase(status_bar_window);
|
|
|
|
x = 0;
|
|
for (i=0; i<10; i++) {
|
|
if (strlen(status_bar_slots[i])==0)
|
|
continue;
|
|
wattron(status_bar_window, A_REVERSE);
|
|
print(status_bar_window, 0, x, "%s", status_bar_slots[i]);
|
|
wattroff(status_bar_window, A_REVERSE);
|
|
x+= strlen(status_bar_slots[i])+1;
|
|
}
|
|
wrefresh(status_bar_window);
|
|
}
|
|
|
|
void show_cstates(void)
|
|
{
|
|
int i, count = 0;
|
|
werase(cstate_window);
|
|
|
|
for (i=0; i < 10; i++) {
|
|
if (i == topcstate+1)
|
|
wattron(cstate_window, A_BOLD);
|
|
else
|
|
wattroff(cstate_window, A_BOLD);
|
|
if (strlen(cstate_lines[i]) && count <= 6) {
|
|
print(cstate_window, count, 0, "%s", cstate_lines[i]);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<25; i++) {
|
|
if (i == topfreq+1)
|
|
wattron(cstate_window, A_BOLD);
|
|
else
|
|
wattroff(cstate_window, A_BOLD);
|
|
print(cstate_window, i, 38, "%s", cpufreqstrings[i]);
|
|
}
|
|
|
|
wrefresh(cstate_window);
|
|
}
|
|
|
|
void show_msm_pm_stats(void)
|
|
{
|
|
int i = 0;
|
|
for (i=0; i < 12; i++)
|
|
print(cstate_window, i, 38, "%s", msm_pm_stat_lines[i]);
|
|
wrefresh(cstate_window);
|
|
}
|
|
|
|
void show_acpi_power_line(double rate, double cap, double capdelta, time_t ti)
|
|
{
|
|
char buffer[1024];
|
|
|
|
sprintf(buffer, _("no ACPI power usage estimate available") );
|
|
|
|
werase(battery_power_window);
|
|
if (rate > 0.001) {
|
|
char *c;
|
|
sprintf(buffer, _("Power usage (ACPI estimate): %3.1fW (%3.1f hours)"), rate, cap/rate);
|
|
strcat(buffer, " ");
|
|
c = &buffer[strlen(buffer)];
|
|
if (ti>180 && capdelta > 0)
|
|
sprintf(c, _("(long term: %3.1fW,/%3.1fh)"), 3600*capdelta / ti, cap / (3600*capdelta/ti+0.01));
|
|
}
|
|
else if (ti>120 && capdelta > 0.001)
|
|
sprintf(buffer, _("Power usage (5 minute ACPI estimate) : %5.1f W (%3.1f hours left)"), 3600*capdelta / ti, cap / (3600*capdelta/ti+0.01));
|
|
|
|
print(battery_power_window, 0, 0, "%s\n", buffer);
|
|
wrefresh(battery_power_window);
|
|
}
|
|
|
|
void show_pmu_power_line(unsigned sum_voltage_mV,
|
|
unsigned sum_charge_mAh, unsigned sum_max_charge_mAh,
|
|
int sum_discharge_mA)
|
|
{
|
|
char buffer[1024];
|
|
|
|
if (sum_discharge_mA != 0)
|
|
{
|
|
unsigned remaining_charge_mAh;
|
|
|
|
if (sum_discharge_mA < 0)
|
|
{
|
|
/* we are currently discharging */
|
|
sum_discharge_mA = -sum_discharge_mA;
|
|
remaining_charge_mAh = sum_charge_mAh;
|
|
}
|
|
else
|
|
{
|
|
/* we are currently charging */
|
|
remaining_charge_mAh = (sum_max_charge_mAh
|
|
- sum_charge_mAh);
|
|
}
|
|
|
|
snprintf(buffer, sizeof(buffer),
|
|
_("Power usage: %3.1fW (%3.1f hours)"),
|
|
sum_voltage_mV * sum_discharge_mA / 1e6,
|
|
(double)remaining_charge_mAh / sum_discharge_mA);
|
|
}
|
|
else
|
|
snprintf(buffer, sizeof(buffer),
|
|
_("no power usage estimate available") );
|
|
|
|
werase(battery_power_window);
|
|
print(battery_power_window, 0, 0, "%s\n", buffer);
|
|
wrefresh(battery_power_window);
|
|
}
|
|
|
|
|
|
void show_wakeups(double d, double interval, double C0time)
|
|
{
|
|
werase(wakeup_window);
|
|
|
|
wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_RED));
|
|
if (d <= 25.0)
|
|
wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_YELLOW));
|
|
if (d <= 10.0)
|
|
wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_GREEN));
|
|
|
|
/*
|
|
* if the cpu is really busy.... then make it blue to indicate
|
|
* that it's not the primary power consumer anymore
|
|
*/
|
|
if (C0time > 25.0)
|
|
wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_BLUE));
|
|
|
|
wattron(wakeup_window, A_BOLD);
|
|
print(wakeup_window, 0, 0, _("Wakeups-from-idle per second : %4.1f\tinterval: %0.1fs\n"), d, interval);
|
|
wrefresh(wakeup_window);
|
|
}
|
|
|
|
void show_timerstats(int nostats, int ticktime)
|
|
{
|
|
int i;
|
|
werase(timerstat_window);
|
|
|
|
if (!nostats) {
|
|
int counter = 0;
|
|
print(timerstat_window, 0, 0, _("Top causes for wakeups:\n"));
|
|
for (i = 0; i < linehead; i++)
|
|
if (lines[i].count > 0 && counter++ < maxtimerstats) {
|
|
if ((lines[i].count * 1.0 / ticktime) >= 10.0)
|
|
wattron(timerstat_window, A_BOLD);
|
|
else
|
|
wattroff(timerstat_window, A_BOLD);
|
|
#ifdef PLATFORM_NO_INT0
|
|
if (strstr(lines[i].string, "<interrupt>") == 0) continue;
|
|
#endif
|
|
if (showpids)
|
|
print(timerstat_window, i+1, 0," %5.1f%% (%5.1f) [%6s] %s \n", lines[i].count * 100.0 /
|
|
#ifdef PLATFORM_NO_INT0
|
|
(int) total_interrupt,
|
|
#else
|
|
(int) linectotal,
|
|
#endif
|
|
lines[i].count * 1.0 / ticktime,
|
|
lines[i].pid, lines[i].string);
|
|
else{
|
|
print(timerstat_window, i+1, 0," %5.1f%% (%5.1f) %s \n", lines[i].count * 100.0 /
|
|
#ifdef PLATFORM_NO_INT0
|
|
(int) total_interrupt,
|
|
#else
|
|
(int) linectotal,
|
|
#endif
|
|
lines[i].count * 1.0 / ticktime,
|
|
lines[i].string);
|
|
}
|
|
}
|
|
#ifdef PLATFORM_NO_INT0
|
|
print(timerstat_window, i, 0, "\nTimer breakdown (dg_timer or gp_timer):\n");
|
|
for (i = 0; i < linehead; i++)
|
|
if (lines[i].count > 0 && counter++ < maxtimerstats) {
|
|
if ((lines[i].count * 1.0 / ticktime) >= 10.0)
|
|
wattron(timerstat_window, A_BOLD);
|
|
else
|
|
wattroff(timerstat_window, A_BOLD);
|
|
if (strstr(lines[i].string, "<interrupt>") != 0) continue;
|
|
|
|
if (showpids)
|
|
print(timerstat_window, i+1, 0," %5.1f%% (%5.1f) [%6s] %s \n", lines[i].count * 100.0 / (linectotal - (int) total_interrupt),
|
|
lines[i].count * 1.0 / ticktime,
|
|
lines[i].pid, lines[i].string);
|
|
else
|
|
print(timerstat_window, i+1, 0," %5.1f%% (%5.1f) %s \n", lines[i].count * 100.0 / (linectotal - (int) total_interrupt),
|
|
lines[i].count * 1.0 / ticktime,
|
|
lines[i].string);
|
|
}
|
|
#endif
|
|
} else {
|
|
if (geteuid() == 0) {
|
|
print(timerstat_window, 0, 0, _("No detailed statistics available; please enable the CONFIG_TIMER_STATS kernel option\n"));
|
|
print(timerstat_window, 1, 0, _("This option is located in the Kernel Debugging section of menuconfig\n"));
|
|
print(timerstat_window, 2, 0, _("(which is CONFIG_DEBUG_KERNEL=y in the config file)\n"));
|
|
print(timerstat_window, 3, 0, _("Note: this is only available in 2.6.21 and later kernels\n"));
|
|
} else
|
|
print(timerstat_window, 0, 0, _("No detailed statistics available; PowerTOP needs root privileges for that\n"));
|
|
}
|
|
|
|
|
|
wrefresh(timerstat_window);
|
|
}
|
|
|
|
void show_suggestion(char *sug)
|
|
{
|
|
werase(suggestion_window);
|
|
print(suggestion_window, 0, 0, "%s", sug);
|
|
wrefresh(suggestion_window);
|
|
}
|