dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / powertop / common / powertop.c
blob823375dfa49587a255e6d98d2010b9095b32ecc4
1 /*
2 * Copyright 2009, Intel Corporation
3 * Copyright 2009, Sun Microsystems, Inc
5 * This file is part of PowerTOP
7 * This program file is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program in a file named COPYING; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
22 * Authors:
23 * Arjan van de Ven <arjan@linux.intel.com>
24 * Eric C Saxe <eric.saxe@sun.com>
25 * Aubrey Li <aubrey.li@intel.com>
29 * GPL Disclaimer
31 * For the avoidance of doubt, except that if any license choice other
32 * than GPL or LGPL is available it will apply instead, Sun elects to
33 * use only the General Public License version 2 (GPLv2) at this time
34 * for any software where a choice of GPL license versions is made
35 * available with the language indicating that GPLv2 or any later
36 * version may be used, or where a choice of which version of the GPL
37 * is applied is otherwise unspecified.
40 #include <getopt.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <signal.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include <poll.h>
48 #include "powertop.h"
51 * Global variables, see powertop.h for comments and extern declarations.
52 * These are ordered by type, grouped by usage.
54 int g_bit_depth;
55 int g_total_events, g_top_events;
56 int g_npstates, g_max_cstate, g_longest_cstate;
57 uint_t g_features;
58 uint_t g_ncpus;
59 uint_t g_ncpus_observed;
61 processorid_t *g_cpu_table;
63 double g_interval_length;
64 hrtime_t g_total_c_time;
66 uchar_t g_op_mode;
67 boolean_t g_gui;
68 uint_t g_observed_cpu;
70 event_info_t g_event_info[EVENT_NUM_MAX];
71 state_info_t g_cstate_info[NSTATES];
72 freq_state_info_t g_pstate_info[NSTATES];
73 cpu_power_info_t *g_cpu_power_states;
75 boolean_t g_turbo_supported;
76 boolean_t g_sig_resize;
78 uint_t g_argc;
79 char **g_argv;
81 static const int true = 1;
83 void
84 pt_sig_handler(int sig)
86 switch (sig) {
87 case SIGWINCH:
88 g_sig_resize = B_TRUE;
89 break;
93 int
94 main(int argc, char **argv)
96 double interval, interval_usr;
97 hrtime_t interval_start;
98 int index2 = 0, c, dump_count = 0;
99 char *endptr, key;
100 boolean_t root_user = B_FALSE;
101 struct pollfd pollset;
103 static struct option opts[] = {
104 { "dump", 1, NULL, 'd' },
105 { "time", 1, NULL, 't' },
106 { "help", 0, NULL, 'h' },
107 { "cpu", 1, NULL, 'c' },
108 { "verbose", 0, NULL, 'v' },
109 { 0, 0, NULL, 0 }
112 pt_set_progname(argv[0]);
115 * Enumerate the system's CPUs, populate cpu_table, g_ncpus
117 if ((g_ncpus = g_ncpus_observed = pt_enumerate_cpus()) == 0)
118 exit(EXIT_FAILURE);
120 if ((g_bit_depth = pt_get_bit_depth()) < 0)
121 exit(EXIT_FAILURE);
123 g_features = 0;
124 interval = interval_usr = INTERVAL_DEFAULT;
125 g_op_mode = PT_MODE_DEFAULT;
126 g_max_cstate = 0;
127 g_argv = NULL;
128 g_argc = 0;
129 g_observed_cpu = 0;
130 g_turbo_supported = B_FALSE;
131 g_sig_resize = B_FALSE;
132 g_curr_sugg = NULL;
134 while ((c = getopt_long(argc, argv, "d:t:hvc:", opts, &index2))
135 != EOF) {
136 if (c == -1)
137 break;
139 switch (c) {
140 case 'd':
141 if (PT_ON_DUMP) {
142 pt_usage();
143 exit(EXIT_USAGE);
146 g_op_mode |= PT_MODE_DUMP;
147 g_gui = B_FALSE;
148 dump_count = (int)strtod(optarg, &endptr);
150 if (dump_count <= 0 || *endptr != '\0') {
151 pt_usage();
152 exit(EXIT_USAGE);
155 break;
156 case 't':
157 if (PT_ON_TIME) {
158 pt_usage();
159 exit(EXIT_USAGE);
162 g_op_mode |= PT_MODE_TIME;
163 interval = interval_usr = (double)strtod(optarg,
164 &endptr);
166 if (*endptr != '\0' || interval < 1 ||
167 interval > INTERVAL_MAX) {
168 pt_usage();
169 exit(EXIT_USAGE);
172 break;
173 case 'v':
174 if (PT_ON_CPU || PT_ON_VERBOSE) {
175 pt_usage();
176 exit(EXIT_USAGE);
179 g_op_mode |= PT_MODE_VERBOSE;
180 break;
181 case 'c':
182 if (PT_ON_CPU || PT_ON_VERBOSE) {
183 pt_usage();
184 exit(EXIT_USAGE);
187 g_op_mode |= PT_MODE_CPU;
188 g_observed_cpu = (uint_t)strtod(optarg, &endptr);
190 if (g_observed_cpu >= g_ncpus) {
191 pt_usage();
192 exit(EXIT_USAGE);
195 g_argc = 1;
196 g_ncpus_observed = 1;
198 if ((g_argv = malloc(sizeof (char *))) == NULL)
199 return (EXIT_FAILURE);
201 if ((*g_argv = malloc(sizeof (char) * 5)) == NULL)
202 return (EXIT_FAILURE);
204 (void) snprintf(*g_argv, 5, "%d\0", g_observed_cpu);
205 break;
206 case 'h':
207 pt_usage();
208 exit(EXIT_SUCCESS);
209 default:
210 pt_usage();
211 exit(EXIT_USAGE);
215 if (optind < argc) {
216 pt_usage();
217 exit(EXIT_USAGE);
220 (void) printf("%s %s\n\n", TITLE, COPYRIGHT_INTEL);
222 (void) printf("Collecting data for %.2f second(s) \n",
223 (float)interval);
225 /* Prepare P-state statistics */
226 if (pt_cpufreq_stat_prepare() == 0)
227 g_features |= FEATURE_PSTATE;
229 /* Prepare C-state statistics */
230 if (pt_cpuidle_stat_prepare() == 0)
231 g_features |= FEATURE_CSTATE;
232 else
234 * PowerTop was unable to run a DTrace program,
235 * most likely for lack of permissions.
237 exit(EXIT_FAILURE);
239 /* Prepare event statistics */
240 if (pt_events_stat_prepare() != -1)
241 g_features |= FEATURE_EVENTS;
244 * If the system is running on battery, find out what's
245 * the kstat module for it
247 pt_battery_mod_lookup();
249 /* Prepare turbo statistics */
250 if (pt_turbo_stat_prepare() == 0)
251 g_features |= FEATURE_TURBO;
254 * Initialize the display.
256 if (!PT_ON_DUMP) {
257 pt_display_init_curses();
258 pt_display_setup(B_FALSE);
259 (void) signal(SIGWINCH, pt_sig_handler);
261 pt_display_title_bar();
262 pt_display_status_bar();
264 g_gui = B_TRUE;
265 pollset.fd = STDIN_FILENO;
266 pollset.events = POLLIN;
270 * Installs the initial suggestions, running as root and turning CPU
271 * power management ON.
273 if (geteuid() != 0) {
274 pt_sugg_as_root();
275 } else {
276 root_user = B_TRUE;
277 pt_cpufreq_suggest();
280 while (true) {
281 key = 0;
283 if (g_sig_resize)
284 pt_display_resize();
286 interval_start = gethrtime();
288 if (!PT_ON_DUMP) {
289 if (poll(&pollset, (nfds_t)1,
290 (int)(interval * MILLISEC)) > 0)
291 (void) read(STDIN_FILENO, &key, 1);
292 } else {
293 (void) sleep((int)interval);
296 g_interval_length = (double)(gethrtime() - interval_start)
297 /NANOSEC;
299 g_top_events = 0;
300 g_total_events = 0;
302 (void) memset(g_event_info, 0,
303 EVENT_NUM_MAX * sizeof (event_info_t));
304 (void) memset(g_cstate_info, 0,
305 NSTATES * sizeof (state_info_t));
307 /* Collect idle state transition stats */
308 if (g_features & FEATURE_CSTATE &&
309 pt_cpuidle_stat_collect(g_interval_length) < 0) {
310 /* Reinitialize C-state statistics */
311 if (pt_cpuidle_stat_prepare() != 0)
312 exit(EXIT_FAILURE);
314 continue;
317 /* Collect frequency change stats */
318 if (g_features & FEATURE_PSTATE &&
319 pt_cpufreq_stat_collect(g_interval_length) < 0) {
320 /* Reinitialize P-state statistics */
321 if (pt_cpufreq_stat_prepare() != 0)
322 exit(EXIT_FAILURE);
324 continue;
327 /* Collect event statistics */
328 if (g_features & FEATURE_EVENTS &&
329 pt_events_stat_collect() < 0) {
330 /* Reinitialize event statistics */
331 if (pt_events_stat_prepare() != 0)
332 exit(EXIT_FAILURE);
334 continue;
337 /* Collect turbo statistics */
338 if (g_features & FEATURE_TURBO &&
339 pt_turbo_stat_collect() < 0)
340 exit(EXIT_FAILURE);
342 /* Show CPU power states */
343 pt_display_states();
345 /* Show wakeups events affecting PM */
346 if (g_features & FEATURE_EVENTS) {
347 pt_display_wakeups(g_interval_length);
348 pt_display_events(g_interval_length);
351 pt_battery_print();
353 if (key && !PT_ON_DUMP) {
354 switch (toupper(key)) {
355 case 'Q':
356 exit(EXIT_SUCCESS);
357 break;
359 case 'R':
360 interval = 3;
361 break;
365 * Check if the user has activated the current
366 * suggestion.
368 if (g_curr_sugg != NULL &&
369 toupper(key) == g_curr_sugg->key &&
370 g_curr_sugg->func)
371 g_curr_sugg->func();
374 if (dump_count)
375 dump_count--;
377 /* Exits if user requested a dump */
378 if (PT_ON_DUMP && !dump_count)
379 exit(EXIT_SUCCESS);
381 /* No key pressed, will suggest something */
382 if (!key && !dump_count)
383 pt_sugg_pick();
385 /* Refresh display */
386 if (!PT_ON_DUMP)
387 pt_display_update();
389 if (root_user)
390 pt_cpufreq_suggest();
393 * Update the interval based on how long the CPU was in the
394 * longest c-state during the last snapshot. If the user
395 * specified an interval we skip this bit and keep it fixed.
397 if (g_features & FEATURE_CSTATE && !PT_ON_TIME &&
398 g_longest_cstate > 0 &&
399 g_cstate_info[g_longest_cstate].events > 0) {
400 double deep_idle_res = (((double)
401 g_cstate_info[g_longest_cstate].total_time/MICROSEC
402 /g_ncpus)/g_cstate_info[g_longest_cstate].events);
404 if (deep_idle_res < INTERVAL_DEFAULT ||
405 (g_total_events/interval) < 1)
406 interval = INTERVAL_DEFAULT;
407 else
408 interval = INTERVAL_UPDATE(deep_idle_res);
409 } else {
411 * Restore interval after a refresh.
413 if (key)
414 interval = interval_usr;
418 return (EXIT_SUCCESS);