--- a/usr/src/cmd/powertop/common/display.c Fri Jun 19 20:12:07 2009 +0800
+++ b/usr/src/cmd/powertop/common/display.c Fri Jun 19 06:14:38 2009 -0700
@@ -39,16 +39,38 @@
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <curses.h>
+#include <signal.h>
+#include <fcntl.h>
#include "powertop.h"
-static WINDOW *title_bar_window;
-static WINDOW *cstate_window;
-static WINDOW *wakeup_window;
-static WINDOW *acpi_power_window;
-static WINDOW *eventstat_window;
-static WINDOW *suggestion_window;
-static WINDOW *status_bar_window;
+/*
+ * Minimum terminal height and width to run PowerTOP on curses mode.
+ */
+#define PT_MIN_COLS 70
+#define PT_MIN_ROWS 15
+
+/*
+ * Display colors
+ */
+#define PT_COLOR_DEFAULT 1
+#define PT_COLOR_HEADER_BAR 2
+#define PT_COLOR_ERROR 3
+#define PT_COLOR_RED 4
+#define PT_COLOR_YELLOW 5
+#define PT_COLOR_GREEN 6
+#define PT_COLOR_BRIGHT 7
+#define PT_COLOR_BLUE 8
+
+/*
+ * Constants for pt_display_setup()
+ */
+#define SINGLE_LINE_SW 1
+#define LENGTH_SUGG_SW 2
+#define TITLE_LINE 1
+#define BLANK_LINE 1
+#define NEXT_LINE 1
#define print(win, y, x, fmt, args...) \
if (PT_ON_DUMP) \
@@ -56,48 +78,73 @@
else \
(void) mvwprintw(win, y, x, fmt, ## args);
-char g_status_bar_slots[PT_BAR_NSLOTS][PT_BAR_LENGTH];
-char g_suggestion_key;
+enum pt_subwindows {
+ SW_TITLE,
+ SW_IDLE,
+ SW_FREQ,
+ SW_WAKEUPS,
+ SW_POWER,
+ SW_EVENTS,
+ SW_SUGG,
+ SW_STATUS,
+ SW_COUNT
+};
-static int maxx, maxy;
+typedef struct sb_slot {
+ char *msg;
+ struct sb_slot *prev;
+ struct sb_slot *next;
+} sb_slot_t;
+
+static WINDOW *sw[SW_COUNT];
+static int win_cols, win_rows;
+static sb_slot_t *status_bar;
static void
-zap_windows(void)
+pt_display_cleanup(void)
+{
+ (void) endwin();
+}
+
+static void
+pt_display_get_size(void)
{
- if (title_bar_window) {
- (void) delwin(title_bar_window);
- title_bar_window = NULL;
- }
- if (cstate_window) {
- (void) delwin(cstate_window);
- cstate_window = NULL;
- }
- if (wakeup_window) {
- (void) delwin(wakeup_window);
- wakeup_window = NULL;
- }
- if (acpi_power_window) {
- (void) delwin(acpi_power_window);
- acpi_power_window = NULL;
- }
- if (eventstat_window) {
- (void) delwin(eventstat_window);
- eventstat_window = NULL;
- }
- if (suggestion_window) {
- (void) delwin(suggestion_window);
- suggestion_window = NULL;
- }
- if (status_bar_window) {
- (void) delwin(status_bar_window);
- status_bar_window = NULL;
+ getmaxyx(stdscr, win_rows, win_cols);
+
+ if (win_rows < PT_MIN_ROWS || win_cols < PT_MIN_COLS) {
+ pt_display_cleanup();
+ (void) printf("\n\nPowerTOP cannot run in such a small "
+ "terminal window. Please resize it.\n\n");
+ exit(EXIT_FAILURE);
}
}
-void
-cleanup_curses(void)
+/*
+ * Signal handler, currently only used for window resizing.
+ */
+static void
+pt_display_resize(int sig)
{
- (void) endwin();
+ int i;
+
+ switch (sig) {
+ case SIGWINCH:
+ for (i = 0; i < SW_COUNT; i++)
+ if (sw[i] != NULL) {
+ (void) delwin(sw[i]);
+ sw[i] = NULL;
+ }
+
+ pt_display_cleanup();
+ (void) pt_display_init_curses();
+ pt_display_setup(B_TRUE);
+
+ pt_display_title_bar();
+
+ pt_display_update();
+
+ break;
+ }
}
/*
@@ -108,55 +155,75 @@
* subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x)
*/
void
-setup_windows(void)
+pt_display_setup(boolean_t resized)
{
/*
* 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.
*/
- int cstate_lines, event_lines, pos_y;
-
- getmaxyx(stdscr, maxy, maxx);
+ int cstate_lines, event_lines, pos_y = 0;
- zap_windows();
+ /*
+ * 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.
+ */
+ cstate_lines = TITLE_LINE + max((g_max_cstate+2), g_npstates);
- cstate_lines = TITLE_LINE + max((g_max_cstate+1), g_npstates);
-
- pos_y = 0;
- title_bar_window = subwin(stdscr, SINGLE_LINE_SW, maxx, pos_y, 0);
+ sw[SW_TITLE] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
pos_y += NEXT_LINE + BLANK_LINE;
- cstate_window = subwin(stdscr, cstate_lines, maxx, pos_y, 0);
+ sw[SW_IDLE] = subwin(stdscr, cstate_lines, win_cols/2 + 1, pos_y, 0);
+ sw[SW_FREQ] = subwin(stdscr, cstate_lines, win_cols/2 - 8, pos_y,
+ win_cols/2 + 8);
pos_y += cstate_lines + BLANK_LINE;
- wakeup_window = subwin(stdscr, SINGLE_LINE_SW, maxx, pos_y, 0);
+ sw[SW_WAKEUPS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
pos_y += NEXT_LINE;
- acpi_power_window = subwin(stdscr, SINGLE_LINE_SW, maxx, pos_y, 0);
+ sw[SW_POWER] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
pos_y += NEXT_LINE + BLANK_LINE;
- event_lines = maxy - SINGLE_LINE_SW - NEXT_LINE - LENGTH_SUGG_SW -
+ event_lines = win_rows - SINGLE_LINE_SW - NEXT_LINE - LENGTH_SUGG_SW -
pos_y;
- eventstat_window = subwin(stdscr, event_lines, maxx, pos_y, 0);
+
+ if (event_lines > 0) {
+ sw[SW_EVENTS] = subwin(stdscr, event_lines, win_cols, pos_y, 0);
+ } else {
+ (void) printf("\n\nPowerTOP cannot run in such a small "
+ "terminal window, please resize it.\n\n");
+ exit(EXIT_FAILURE);
+ }
pos_y += event_lines + NEXT_LINE;
- suggestion_window = subwin(stdscr, SINGLE_LINE_SW, maxx, pos_y, 0);
+ sw[SW_SUGG] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
pos_y += BLANK_LINE + NEXT_LINE;
- status_bar_window = subwin(stdscr, SINGLE_LINE_SW, maxx, pos_y, 0);
+ sw[SW_STATUS] = subwin(stdscr, SINGLE_LINE_SW, win_cols, pos_y, 0);
+
+ if (!resized) {
+ status_bar = NULL;
- (void) strcpy(g_status_bar_slots[0], _(" Q - Quit "));
- (void) strcpy(g_status_bar_slots[1], _(" R - Refresh "));
+ pt_display_mod_status_bar(_("Q - Quit"));
+ pt_display_mod_status_bar(_("R - Refresh"));
+ }
- (void) werase(stdscr);
- (void) wrefresh(status_bar_window);
+ pt_display_status_bar();
}
+/*
+ * This routine handles all the necessary curses initialization.
+ */
void
-initialize_curses(void)
+pt_display_init_curses(void)
{
(void) initscr();
+
+ (void) atexit(pt_display_cleanup);
+ (void) signal(SIGWINCH, pt_display_resize);
+
+ pt_display_get_size();
+
(void) start_color();
/*
@@ -192,86 +259,172 @@
(void) init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
(void) init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
(void) init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
+}
- (void) atexit(cleanup_curses);
+void
+pt_display_update(void)
+{
+ (void) doupdate();
+}
+
+void
+pt_display_title_bar(void)
+{
+ char title_pad[10];
+
+ (void) wattrset(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
+ (void) wbkgd(sw[SW_TITLE], COLOR_PAIR(PT_COLOR_HEADER_BAR));
+ (void) werase(sw[SW_TITLE]);
+
+ (void) snprintf(title_pad, 10, "%%%ds",
+ (win_cols - strlen(TITLE))/2 + strlen(TITLE));
+
+ /* LINTED: E_SEC_PRINTF_VAR_FMT */
+ print(sw[SW_TITLE], 0, 0, title_pad, TITLE);
+
+ (void) wnoutrefresh(sw[SW_TITLE]);
}
void
-show_title_bar(void)
+pt_display_status_bar(void)
{
- int i, x = 0, y = 0;
- char title_pad[10];
+ sb_slot_t *n = status_bar;
+ int x = 0;
+
+ (void) werase(sw[SW_STATUS]);
+
+ while (n && x < win_cols) {
+ (void) wattron(sw[SW_STATUS], A_REVERSE);
+ print(sw[SW_STATUS], 0, x, "%s", n->msg);
+ (void) wattroff(sw[SW_STATUS], A_REVERSE);
+ x += strlen(n->msg) + 1;
+
+ n = n->next;
+ }
+
+ (void) wnoutrefresh(sw[SW_STATUS]);
+}
- (void) wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
- (void) wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR));
- (void) werase(title_bar_window);
+/*
+ * Adds or removes items to the status bar automatically.
+ * Only one instance of an item allowed.
+ */
+void
+pt_display_mod_status_bar(char *msg)
+{
+ sb_slot_t *new, *n;
+ boolean_t found = B_FALSE, first = B_FALSE;
+
+ if (msg == NULL) {
+ pt_error("%s : can't add an empty status bar item.", __FILE__);
+ return;
+ }
+
+ if (status_bar != NULL) {
+ /*
+ * Non-empty status bar. Look for an entry matching this msg.
+ */
+ for (n = status_bar; n != NULL; n = n->next) {
+
+ if (strcmp(msg, n->msg) == 0) {
+ if (n != status_bar)
+ n->prev->next = n->next;
+ else
+ first = B_TRUE;
- (void) snprintf(title_pad, 10, "%%%ds",
- (maxx - strlen(TITLE))/2 + strlen(TITLE));
- /* LINTED: E_SEC_PRINTF_VAR_FMT */
- print(title_bar_window, y, x, title_pad, TITLE);
+ if (n->next != NULL) {
+ n->next->prev = n->prev;
+ if (first)
+ status_bar = n->next;
+ } else {
+ if (first)
+ status_bar = NULL;
+ }
- (void) wrefresh(title_bar_window);
- (void) werase(status_bar_window);
+ free(n);
+ found = B_TRUE;
+ }
+ }
- for (i = 0; i < PT_BAR_NSLOTS; i++) {
- if (strlen(g_status_bar_slots[i]) == 0)
- continue;
- (void) wattron(status_bar_window, A_REVERSE);
- print(status_bar_window, y, x, "%s", g_status_bar_slots[i]);
- (void) wattroff(status_bar_window, A_REVERSE);
- x += strlen(g_status_bar_slots[i]) + 1;
+ /*
+ * Found and removed at least one occurrance of msg, refresh
+ * the bar and return.
+ */
+ if (found) {
+ return;
+ } else {
+ /*
+ * Inserting a new msg, walk to the end of the bar.
+ */
+ for (n = status_bar; n->next != NULL; n = n->next)
+ ;
+ }
}
- (void) wnoutrefresh(status_bar_window);
+
+ if ((new = calloc(1, sizeof (sb_slot_t))) == NULL) {
+ pt_error("%s : failed to allocate a new slot\n", __FILE__);
+ } else {
+ new->msg = strdup(msg);
+
+ /*
+ * Check if it's the first entry.
+ */
+ if (status_bar == NULL) {
+ status_bar = new;
+ new->prev = NULL;
+ } else {
+ new->prev = n;
+ n->next = new;
+ }
+ new->next = NULL;
+ }
}
void
-show_cstates(void)
+pt_display_states(void)
{
char c[100];
int i;
double total_pstates = 0.0, avg, res;
uint64_t p0_speed, p1_speed;
- if (!PT_ON_DUMP) {
- (void) werase(cstate_window);
- (void) wattrset(cstate_window, COLOR_PAIR(PT_COLOR_DEFAULT));
- (void) wbkgd(cstate_window, COLOR_PAIR(PT_COLOR_DEFAULT));
+ print(sw[SW_IDLE], 0, 0, "%s\tAvg\tResidency\n", g_msg_idle_state);
+
+ if (g_features & FEATURE_CSTATE) {
+ res = (((double)g_cstate_info[0].total_time / g_total_c_time))
+ * 100;
+ (void) sprintf(c, "C0 (cpu running)\t\t(%.1f%%)\n", (float)res);
+ print(sw[SW_IDLE], 1, 0, "%s", c);
+
+ for (i = 1; i <= g_max_cstate; 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;
+
+ res = ((double)g_cstate_info[i].total_time/
+ g_total_c_time) * 100;
+
+ (void) sprintf(c, "C%d\t\t\t%.1fms\t(%.1f%%)\n",
+ i, (float)avg, (float)res);
+ print(sw[SW_IDLE], i + 1, 0, "%s", c);
+ }
}
- print(cstate_window, 0, 0, "%s\tAvg\tresidency\n", g_msg_idle_state);
- res = (((double)g_cstate_info[0].total_time / g_total_c_time)) * 100;
- (void) sprintf(c, "C0 (cpu running)\t\t(%.1f%%)\n", (float)res);
- print(cstate_window, 1, 0, "%s", c);
+ if (!PT_ON_DUMP)
+ (void) wnoutrefresh(sw[SW_IDLE]);
- for (i = 1; i <= g_max_cstate; 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;
+ print(sw[SW_FREQ], 0, 0, "%s\n", g_msg_freq_state);
- res = ((double)g_cstate_info[i].total_time/g_total_c_time)
- * 100;
-
- (void) sprintf(c, "C%d\t\t\t%.1fms\t(%.1f%%)\n", i, (float)avg,
- (float)res);
- print(cstate_window, i + 1, 0, "%s", c);
- }
-
- print(cstate_window, 0, 48, "%s\n", g_msg_freq_state);
-
- if (g_npstates < 2) {
- (void) sprintf(c, "%4lu Mhz\t%.1f%%",
- (long)g_pstate_info[0].speed, 100.0);
- print(cstate_window, 1, 48, "%s\n", c);
- } else {
+ if (g_features & FEATURE_PSTATE) {
for (i = 0; i < g_npstates; i++) {
- total_pstates += (double)(g_pstate_info[i].total_time/
+ total_pstates +=
+ (double)(g_pstate_info[i].total_time/
g_ncpus_observed/MICROSEC);
}
@@ -281,9 +434,9 @@
for (i = 0; i < g_npstates - 1; i++) {
(void) sprintf(c, "%4lu Mhz\t%.1f%%",
(long)g_pstate_info[i].speed,
- 100 * (g_pstate_info[i].total_time/g_ncpus_observed/
- MICROSEC/total_pstates));
- print(cstate_window, i+1, 48, "%s\n", c);
+ 100 * (g_pstate_info[i].total_time/
+ g_ncpus_observed/MICROSEC/total_pstates));
+ print(sw[SW_FREQ], i+1, 0, "%s\n", c);
}
/*
@@ -301,12 +454,14 @@
p0_speed = p1_speed + 1;
} else {
/*
- * If g_turbo_ratio > 1.0, that means turbo
- * mode works. So, P(0) = ratio * P(1);
+ * If g_turbo_ratio > 1.0, that means
+ * turbo mode works. So, P(0) = ratio *
+ * P(1);
*/
- p0_speed = (uint64_t)(p1_speed * g_turbo_ratio);
+ p0_speed = (uint64_t)(p1_speed *
+ g_turbo_ratio);
if (p0_speed < (p1_speed + 1))
- p0_speed = p1_speed + 1;
+ p0_speed = p1_speed + 1;
}
/*
* Reset the ratio for the next round
@@ -326,15 +481,21 @@
100 * (g_pstate_info[i].total_time/
g_ncpus_observed/MICROSEC/total_pstates));
}
- print(cstate_window, i+1, 48, "%s\n", c);
+ print(sw[SW_FREQ], i+1, 0, "%s\n", c);
+ } else {
+ if (g_npstates == 1) {
+ (void) sprintf(c, "%4lu Mhz\t%.1f%%",
+ (long)g_pstate_info[0].speed, 100.0);
+ print(sw[SW_FREQ], 1, 0, "%s\n", c);
+ }
}
if (!PT_ON_DUMP)
- (void) wnoutrefresh(cstate_window);
+ (void) wnoutrefresh(sw[SW_FREQ]);
}
void
-show_acpi_power_line(uint32_t flag, double rate, double rem_cap, double cap,
+pt_display_acpi_power(uint32_t flag, double rate, double rem_cap, double cap,
uint32_t state)
{
char buffer[1024];
@@ -342,7 +503,8 @@
(void) sprintf(buffer, _("no ACPI power usage estimate available"));
if (!PT_ON_DUMP)
- (void) werase(acpi_power_window);
+ (void) werase(sw[SW_POWER]);
+
if (flag) {
char *c;
(void) sprintf(buffer, "Power usage (ACPI estimate): %.3fW",
@@ -368,22 +530,23 @@
}
}
- print(acpi_power_window, 0, 0, "%s\n", buffer);
+
+ print(sw[SW_POWER], 0, 0, "%s\n", buffer);
if (!PT_ON_DUMP)
- (void) wnoutrefresh(acpi_power_window);
+ (void) wnoutrefresh(sw[SW_POWER]);
}
void
-show_wakeups(double interval)
+pt_display_wakeups(double interval)
{
char c[100];
int i, event_sum = 0;
event_info_t *event = g_event_info;
if (!PT_ON_DUMP) {
- (void) werase(wakeup_window);
- (void) wbkgd(wakeup_window, COLOR_PAIR(PT_COLOR_RED));
- (void) wattron(wakeup_window, A_BOLD);
+ (void) werase(sw[SW_WAKEUPS]);
+ (void) wbkgd(sw[SW_WAKEUPS], COLOR_PAIR(PT_COLOR_RED));
+ (void) wattron(sw[SW_WAKEUPS], A_BOLD);
}
/*
@@ -404,14 +567,14 @@
(void) sprintf(c, "Wakeups-from-idle per second: %4.1f\tinterval: "
"%.1fs", (double)(g_total_events/interval), interval);
- print(wakeup_window, 0, 0, "%s\n", c);
+ print(sw[SW_WAKEUPS], 0, 0, "%s\n", c);
if (!PT_ON_DUMP)
- (void) wnoutrefresh(wakeup_window);
+ (void) wnoutrefresh(sw[SW_WAKEUPS]);
}
void
-show_eventstats(double interval)
+pt_display_events(double interval)
{
char c[100];
int i;
@@ -419,9 +582,9 @@
event_info_t *event = g_event_info;
if (!PT_ON_DUMP) {
- (void) werase(eventstat_window);
- (void) wattrset(eventstat_window, COLOR_PAIR(PT_COLOR_DEFAULT));
- (void) wbkgd(eventstat_window, COLOR_PAIR(PT_COLOR_DEFAULT));
+ (void) werase(sw[SW_EVENTS]);
+ (void) wbkgd(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
+ (void) wattron(sw[SW_EVENTS], COLOR_PAIR(PT_COLOR_DEFAULT));
}
/*
@@ -439,7 +602,7 @@
else
(void) sprintf(c, "Top causes for wakeups:\n");
- print(eventstat_window, 0, 0, "%s", c);
+ print(sw[SW_EVENTS], 0, 0, "%s", c);
for (i = 0; i < g_top_events; i++, event++) {
@@ -451,27 +614,26 @@
(void) sprintf(c, "%4.1f%% (%5.1f)", 100 * events,
(double)event->total_count/interval);
- print(eventstat_window, i+1, 0, "%s", c);
- print(eventstat_window, i+1, 16, "%20s :",
+ print(sw[SW_EVENTS], i+1, 0, "%s", c);
+ print(sw[SW_EVENTS], i+1, 16, "%20s :",
event->offender_name);
- print(eventstat_window, i+1, 40, "%-64s\n",
+ print(sw[SW_EVENTS], i+1, 40, "%-64s\n",
event->offense_name);
}
if (!PT_ON_DUMP)
- (void) wnoutrefresh(eventstat_window);
+ (void) wnoutrefresh(sw[SW_EVENTS]);
}
void
-show_suggestion(char *sug)
+pt_display_suggestions(char *sug)
{
- (void) werase(suggestion_window);
- print(suggestion_window, 0, 0, "%s", sug);
- (void) wnoutrefresh(suggestion_window);
+ (void) werase(sw[SW_SUGG]);
+
+ if (sug != NULL)
+ print(sw[SW_SUGG], 0, 0, "%s", sug);
+
+ (void) wnoutrefresh(sw[SW_SUGG]);
+
+ pt_display_update();
}
-
-void
-update_windows(void)
-{
- (void) doupdate();
-}
--- a/usr/src/cmd/powertop/common/powertop.c Fri Jun 19 20:12:07 2009 +0800
+++ b/usr/src/cmd/powertop/common/powertop.c Fri Jun 19 06:14:38 2009 -0700
@@ -41,6 +41,7 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>
@@ -52,11 +53,11 @@
*/
double g_ticktime, g_ticktime_usr;
double g_interval;
-double g_displaytime;
int g_bit_depth;
int g_total_events, g_top_events;
int g_npstates, g_max_cstate, g_longest_cstate;
+uint_t g_features;
uint_t g_ncpus;
uint_t g_ncpus_observed;
@@ -72,7 +73,6 @@
state_info_t g_cstate_info[NSTATES];
freq_state_info_t g_pstate_info[NSTATES];
cpu_power_info_t *g_cpu_power_states;
-suggestion_func *g_suggestion_activate;
boolean_t g_turbo_supported;
@@ -87,10 +87,11 @@
main(int argc, char **argv)
{
hrtime_t last, now;
- uint_t features = 0, user_interval = 0;
- int ncursesinited = 0, index2 = 0, c, ret, dump_count = 0;
+ uint_t user_interval = 0;
+ int index2 = 0, c, ret, dump_count = 0;
double last_time;
char *endptr;
+ boolean_t root_user = B_FALSE;
static struct option opts[] = {
{ "dump", 1, NULL, 'd' },
@@ -108,8 +109,7 @@
pt_set_progname(argv[0]);
/*
- * Enumerate the system's CPUs
- * Populate cpu_table, g_ncpus
+ * Enumerate the system's CPUs, populate cpu_table, g_ncpus
*/
if ((g_ncpus = g_ncpus_observed = enumerate_cpus()) == 0)
exit(EXIT_FAILURE);
@@ -117,15 +117,16 @@
if ((g_bit_depth = get_bit_depth()) < 0)
exit(EXIT_FAILURE);
+ g_features = 0;
g_ticktime = g_ticktime_usr = INTERVAL_DEFAULT;
- g_displaytime = 0.0;
- g_op_mode = PT_MODE_DEFAULT;
- g_gui = B_FALSE;
- g_max_cstate = 0;
- g_argv = NULL;
- g_argc = 0;
- g_observed_cpu = 0;
+ g_op_mode = PT_MODE_DEFAULT;
+ g_gui = B_FALSE;
+ g_max_cstate = 0;
+ g_argv = NULL;
+ g_argc = 0;
+ g_observed_cpu = 0;
g_turbo_supported = B_FALSE;
+ g_curr_sugg = NULL;
while ((c = getopt_long(argc, argv, "d:t:h:vc:", opts, &index2))
!= EOF) {
@@ -189,22 +190,22 @@
}
}
- if (optind < argc) {
+ if (optind < argc)
usage();
- }
(void) printf("%s %s\n\n", TITLE, COPYRIGHT_INTEL);
- /*
- * If the system is running on battery, find out what's
- * the kstat module for it
- */
- battery_mod_lookup();
+ (void) printf(_("Collecting data for %.2f second(s) \n"),
+ (float)g_ticktime);
+
+ /* Prepare P-state statistics */
+ if (pt_cpufreq_stat_prepare() == 0)
+ g_features |= FEATURE_PSTATE;
/* Prepare C-state statistics */
ret = pt_cpuidle_stat_prepare();
if (ret == 0)
- features |= FEATURE_CSTATE;
+ g_features |= FEATURE_CSTATE;
else
/*
* PowerTop was unable to run a DTrace program,
@@ -212,31 +213,51 @@
*/
exit(EXIT_FAILURE);
- /* Prepare P-state statistics */
- if (pt_cpufreq_stat_prepare() == 0)
- features |= FEATURE_PSTATE;
+ /*
+ * We need to initiate the display to make sure there's enough space
+ * in the terminal for all of PowerTOP's subwindows, but after
+ * pt_cpufreq_stat_prepare() which finds out how many states the
+ * system supports.
+ */
+ if (!PT_ON_DUMP) {
+ pt_display_init_curses();
+ pt_display_setup(B_FALSE);
+ g_gui = B_TRUE;
+ pt_display_title_bar();
+ pt_display_status_bar();
+ }
/* Prepare event statistics */
if (pt_events_stat_prepare() != -1)
- features |= FEATURE_EVENTS;
+ g_features |= FEATURE_EVENTS;
+
+ /*
+ * If the system is running on battery, find out what's
+ * the kstat module for it
+ */
+ battery_mod_lookup();
/* Prepare turbo statistics */
- if (pt_turbo_stat_prepare() == 0) {
- features |= FEATURE_TURBO;
- }
+ if (pt_turbo_stat_prepare() == 0)
+ g_features |= FEATURE_TURBO;
- (void) printf(_("Collecting data for %.2f second(s) \n"),
- (float)g_ticktime);
-
- if (!PT_ON_DUMP)
- g_gui = B_TRUE;
+ /*
+ * Installs the initial suggestions, running as root and turning CPU
+ * power management ON.
+ */
+ if (geteuid() != 0)
+ pt_sugg_as_root();
+ else {
+ root_user = B_TRUE;
+ pt_cpufreq_suggest();
+ }
last = gethrtime();
while (true) {
fd_set rfds;
struct timeval tv;
- int key, reinit = 0;
+ int key;
char keychar;
/*
@@ -246,18 +267,18 @@
FD_ZERO(&rfds);
FD_SET(0, &rfds);
- tv.tv_sec = (long)g_ticktime;
- tv.tv_usec = (long)((g_ticktime - tv.tv_sec) * MICROSEC);
+ tv.tv_sec = (long)g_ticktime;
+ tv.tv_usec = (long)((g_ticktime - tv.tv_sec) * MICROSEC);
- if (!PT_ON_DUMP)
+ if (!PT_ON_DUMP) {
key = select(1, &rfds, NULL, NULL, &tv);
- else
+ } else
key = select(1, NULL, NULL, NULL, &tv);
- now = gethrtime();
+ now = gethrtime();
- g_interval = (double)(now - last)/NANOSEC;
- last = now;
+ g_interval = (double)(now - last)/NANOSEC;
+ last = now;
g_top_events = 0;
g_total_events = 0;
@@ -268,145 +289,114 @@
NSTATES * sizeof (state_info_t));
/* Collect idle state transition stats */
- if (features & FEATURE_CSTATE &&
+ if (g_features & FEATURE_CSTATE &&
pt_cpuidle_stat_collect(g_interval) < 0) {
/* Reinitialize C-state statistics */
if (pt_cpuidle_stat_prepare() != 0)
exit(EXIT_FAILURE);
- reinit = 1;
+ continue;
}
/* Collect frequency change stats */
- if (features & FEATURE_PSTATE &&
+ if (g_features & FEATURE_PSTATE &&
pt_cpufreq_stat_collect(g_interval) < 0) {
/* Reinitialize P-state statistics */
if (pt_cpufreq_stat_prepare() != 0)
exit(EXIT_FAILURE);
- reinit = 1;
+ continue;
}
/* Collect event statistics */
- if (features & FEATURE_EVENTS &&
+ if (g_features & FEATURE_EVENTS &&
pt_events_stat_collect() < 0) {
/* Reinitialize event statistics */
if (pt_events_stat_prepare() != 0)
exit(EXIT_FAILURE);
- reinit = 1;
- }
-
- if (reinit)
continue;
-
- /* Collect turbo statistics */
- if (features & FEATURE_TURBO &&
- pt_turbo_stat_collect() < 0) {
- exit(EXIT_FAILURE);
}
- /*
- * Initialize curses if we're not dumping and
- * haven't already done it
- */
- if (!PT_ON_DUMP) {
- if (!ncursesinited) {
- initialize_curses();
- ncursesinited++;
- }
- setup_windows();
- show_title_bar();
+ /* Collect turbo statistics */
+ if (g_features & FEATURE_TURBO &&
+ pt_turbo_stat_collect() < 0)
+ exit(EXIT_FAILURE);
+
+ /* Show CPU power states */
+ pt_display_states();
+
+ /* Show wakeups events affecting PM */
+ if (g_features & FEATURE_EVENTS) {
+ pt_display_wakeups(g_interval);
+ pt_display_events(g_interval);
}
- /* Show CPU power states */
- if (features & FEATURE_CSTATE)
- show_cstates();
-
- /* Show wakeups events affecting PM */
- if (features & FEATURE_EVENTS) {
- show_wakeups(g_interval);
- show_eventstats(g_interval);
- }
-
- print_battery();
-
- g_displaytime = g_displaytime - g_ticktime;
+ pt_battery_print();
if (key && !PT_ON_DUMP) {
keychar = toupper(fgetc(stdin));
switch (keychar) {
case 'Q':
- cleanup_curses();
exit(EXIT_SUCCESS);
break;
+
case 'R':
g_ticktime = 3;
break;
}
- if (keychar == g_suggestion_key &&
- g_suggestion_activate) {
- g_suggestion_activate();
- g_displaytime = -1.0;
- }
- }
- reset_suggestions();
- /* suggests PM */
- if (geteuid() == 0) {
- suggest_p_state();
- } else {
- suggest_as_root();
+ /*
+ * Check if the user has activated the current
+ * suggestion.
+ */
+ if (g_curr_sugg != NULL &&
+ keychar == g_curr_sugg->key && g_curr_sugg->func)
+ g_curr_sugg->func();
}
if (dump_count)
dump_count--;
/* Exits if user requested a dump */
- if (PT_ON_DUMP && !dump_count) {
- print_all_suggestions();
+ if (PT_ON_DUMP && !dump_count)
exit(EXIT_SUCCESS);
- }
/* No key pressed, will suggest something */
if (!key && !dump_count)
- pick_suggestion();
+ pt_sugg_pick();
/* Refresh display */
- if (!PT_ON_DUMP) {
- show_title_bar();
- update_windows();
- }
+ if (!PT_ON_DUMP)
+ pt_display_update();
+
+ if (root_user)
+ pt_cpufreq_suggest();
/*
* Update the interval based on how long the CPU was in the
* longest c-state during the last snapshot. If the user
* specified an interval we skip this bit and keep it fixed.
*/
- last_time = (((double)g_cstate_info[g_longest_cstate].total_time
- /MICROSEC/g_ncpus)/g_cstate_info[g_longest_cstate].events);
+ if (g_features & FEATURE_CSTATE && !user_interval) {
+ last_time = (((double)
+ g_cstate_info[g_longest_cstate].total_time/MICROSEC
+ /g_ncpus)/g_cstate_info[g_longest_cstate].events);
- if (!user_interval)
if (last_time < INTERVAL_DEFAULT ||
(g_total_events/g_ticktime) < 1)
g_ticktime = INTERVAL_DEFAULT;
else
g_ticktime = INTERVAL_UPDATE(last_time);
+ } else {
+ /*
+ * Restore interval after a refresh.
+ */
+ if (key)
+ g_ticktime = g_ticktime_usr;
+ }
+ }
- /*
- * Restore user specified interval after a refresh
- */
- if (keychar == 'R' && user_interval)
- g_ticktime = g_ticktime_usr;
- }
return (EXIT_SUCCESS);
}
-
-void
-suggest_as_root(void)
-{
- add_suggestion("Suggestion: run as root to get suggestions"
- " for reducing system power consumption", 40, NULL, NULL,
- NULL);
-}