/*
* Copyright 2009, Intel Corporation
*
* This file is part of PowerTOP
*
* 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>
* Eric C Saxe <eric.saxe@sun.com>
* Aubrey Li <aubrey.li@intel.com>
*/
/*
* GPL Disclaimer
*
* For the avoidance of doubt, except that if any license choice other
* than GPL or LGPL is available it will apply instead, Sun elects to
* use only the General Public License version 2 (GPLv2) at this time
* for any software where a choice of GPL license versions is made
* available with the language indicating that GPLv2 or any later
* version may be used, or where a choice of which version of the GPL
* is applied is otherwise unspecified.
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <curses.h>
#include <signal.h>
#include <fcntl.h>
#include "powertop.h"
/*
* Minimum terminal height and width to run PowerTOP on curses mode.
*/
/*
* Display colors
*/
/*
* Constants for pt_display_setup()
*/
if (PT_ON_DUMP) \
else \
enum pt_subwindows {
};
typedef struct sb_slot {
char *msg;
} sb_slot_t;
/*
* Delete all subwindows and reset the terminal to a non-visual mode. This
* routine is used during resize events and before exiting.
*/
static void
pt_display_cleanup(void)
{
int i;
for (i = 0; i < SW_COUNT; i++) {
}
}
(void) endwin();
(void) putchar('\r');
}
static void
pt_display_get_size(void)
{
(void) printf("\n\nPowerTOP cannot run in such a small "
"terminal window. Please resize it.\n\n");
}
}
void
pt_display_resize(void)
{
(void) pt_display_init_curses();
if (g_features & FEATURE_EVENTS) {
}
pt_sugg_pick();
}
/*
* This part was re-written to be human readable and easy to modify. Please
* try to keep it that way and help us save some time.
*
* Friendly reminder:
* subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x)
*/
void
{
/*
* These variables are used to properly set the initial y position and
* number of lines in each subwindow, as the number of supported CPU
* states affects their placement.
*/
/*
* In theory, all systems have at least two idle states. We add two here
* since we have to use DTrace to figure out how many this box has.
*/
if (event_lines > 0) {
} else {
(void) printf("\n\nPowerTOP cannot run in such a small "
"terminal window, please resize it.\n\n");
}
if (!resized) {
status_bar = NULL;
pt_display_mod_status_bar("Q - Quit");
pt_display_mod_status_bar("R - Refresh");
}
}
/*
* This routine handles all the necessary curses initialization.
*/
void
pt_display_init_curses(void)
{
(void) initscr();
(void) atexit(pt_display_cleanup);
(void) start_color();
/*
* Enable keyboard mapping
*/
/*
*/
(void) nonl();
/*
* Take input chars one at a time, no wait for \n
*/
(void) cbreak();
/*
* Dont echo input
*/
(void) noecho();
/*
* Turn off cursor
*/
(void) curs_set(0);
}
void
pt_display_update(void)
{
(void) doupdate();
}
void
pt_display_title_bar(void)
{
/* LINTED: E_SEC_PRINTF_VAR_FMT */
}
void
pt_display_status_bar(void)
{
sb_slot_t *n = status_bar;
int x = 0;
while (n && x < win_cols) {
n = n->next;
}
}
/*
* Adds or removes items to the status bar automatically.
* Only one instance of an item allowed.
*/
void
{
pt_error("can't add an empty status bar item\n");
return;
}
if (status_bar != NULL) {
/*
* Non-empty status bar. Look for an entry matching this msg.
*/
if (n != status_bar)
else
if (first)
status_bar = n->next;
} else {
if (first)
status_bar = NULL;
}
free(n);
}
}
/*
* Found and removed at least one occurrence of msg, refresh
* the bar and return.
*/
if (found) {
return;
} else {
/*
* Inserting a new msg, walk to the end of the bar.
*/
;
}
}
pt_error("failed to allocate a new status bar slot\n");
} else {
/*
* Check if it's the first entry.
*/
if (status_bar == NULL) {
status_bar = new;
} else {
}
}
}
void
pt_display_states(void)
{
char c[100];
int i;
int max_cstates;
if (g_features & FEATURE_CSTATE) {
g_total_c_time)) * 100;
else
res = 100;
if (max_cstates > 1) {
for (i = 1; i < max_cstates; i++) {
/*
* In situations where the load is too
* intensive, the system might not transition
* at all.
*/
if (g_cstate_info[i].events > 0)
avg = (((double)
g_cstate_info[i].total_time /
MICROSEC) /
g_cstate_info[i].events);
else
avg = 0.0;
if (g_total_c_time > 0)
res = ((double)
g_cstate_info[i].total_time /
g_total_c_time) * 100;
else
res = 0;
(void) sprintf(c, "C%d\t\t\t%.1fms\t(%.1f%%)\n",
}
}
}
if (!PT_ON_DUMP)
if (g_features & FEATURE_PSTATE) {
total_pstates = (double)(g_total_p_time /
/*
* display ACPI_PSTATE from P(n) to P(1)
*/
for (i = 0; i < npstates; i++) {
(void) sprintf(c, "%4lu Mhz\t%.1f%%",
(long)g_pstate_info[i].speed,
}
/*
* Display ACPI_PSTATE P0 according to if turbo
* mode is supported
*/
if (g_turbo_supported) {
/*
* If g_turbo_ratio <= 1.0, it will be ignored.
* we display P(0) as P(1) + 1.
*/
if (g_turbo_ratio <= 1.0) {
} else {
/*
* If g_turbo_ratio > 1.0, that means
* turbo mode works. So, P(0) = ratio * P(1);
*/
}
/*
* Reset the ratio for the next round
*/
g_turbo_ratio = 0.0;
/*
* Setup the string for the display
*/
(void) sprintf(c, "%4lu Mhz(turbo)\t%.1f%%",
(long)p0_speed, 100 *
MICROSEC / total_pstates));
} else {
(void) sprintf(c, "%4lu Mhz\t%.1f%%",
}
} else {
if (g_max_pstates == 1) {
(void) sprintf(c, "%4lu Mhz\t%.1f%%",
}
}
if (!PT_ON_DUMP)
}
void
{
if (!PT_ON_DUMP)
if (flag) {
char *c;
rate);
switch (state) {
case 0:
(void) sprintf(c, "(running on AC power, fully "
"charged)");
break;
case 1:
(void) sprintf(c, "(discharging: %3.1f hours)",
break;
case 2:
(void) sprintf(c, "(charging: %3.1f hours)",
break;
case 4:
(void) sprintf(c, "(##critically low battery power##)");
break;
}
}
if (!PT_ON_DUMP)
}
void
{
char c[100];
int i, event_sum = 0;
if (!PT_ON_DUMP) {
}
/*
* calculate the actual total event number
*/
for (i = 0; i < g_top_events; i++, event++)
/*
* g_total_events is the sum of the number of Cx->C0 transition,
* So when the system is very busy, the idle thread will have no
* chance or very seldom to be scheduled, this could cause >100%
* event report. Re-assign g_total_events to the actual event
* number is a way to avoid this issue.
*/
if (event_sum > g_total_events)
(void) sprintf(c, "Wakeups-from-idle per second: %4.1f\tinterval: "
if (!PT_ON_DUMP)
}
void
{
char c[100];
int i;
double events;
if (!PT_ON_DUMP) {
}
/*
* Sort the event report list
*/
if (g_top_events > EVENT_NUM_MAX)
if (PT_ON_CPU)
(void) sprintf(c, "Top causes for wakeups on CPU %d:\n",
else
(void) sprintf(c, "Top causes for wakeups:\n");
for (i = 0; i < g_top_events; i++, event++) {
(double)g_total_events;
else
continue;
}
if (!PT_ON_DUMP)
}
void
{
}