1 /* 2 * Copyright 2009, Intel Corporation 3 * Copyright 2009, Sun Microsystems, Inc 4 * 5 * This file is part of PowerTOP 6 * 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. 10 * 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. 15 * 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 21 * 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> 26 */ 27 28 /* 29 * GPL Disclaimer 30 * 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. 38 */ 39 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 <locale.h> 48 #include "powertop.h" 49 50 /* 51 * Global variables, see powertop.h for comments and extern declarations. 52 * These are ordered by type, grouped by usage. 53 */ 54 double g_ticktime, g_ticktime_usr; 55 double g_interval; 56 57 int g_bit_depth; 58 int g_total_events, g_top_events; 59 int g_npstates, g_max_cstate, g_longest_cstate; 60 uint_t g_features; 61 uint_t g_ncpus; 62 uint_t g_ncpus_observed; 63 64 processorid_t *g_cpu_table; 65 66 hrtime_t g_total_c_time; 67 68 uchar_t g_op_mode; 69 boolean_t g_gui; 70 uint_t g_observed_cpu; 71 72 event_info_t g_event_info[EVENT_NUM_MAX]; 73 state_info_t g_cstate_info[NSTATES]; 74 freq_state_info_t g_pstate_info[NSTATES]; 75 cpu_power_info_t *g_cpu_power_states; 76 77 boolean_t g_turbo_supported; 78 79 uint_t g_argc; 80 char **g_argv; 81 82 char *optarg; 83 84 static const int true = 1; 85 86 int 87 main(int argc, char **argv) 88 { 89 hrtime_t last, now; 90 uint_t user_interval = 0; 91 int index2 = 0, c, ret, dump_count = 0; 92 double last_time; 93 char *endptr; 94 boolean_t root_user = B_FALSE; 95 96 static struct option opts[] = { 97 { "dump", 1, NULL, 'd' }, 98 { "time", 1, NULL, 't' }, 99 { "help", 0, NULL, 'h' }, 100 { "cpu", 1, NULL, 'c' }, 101 { "verbose", 0, NULL, 'v' }, 102 { 0, 0, NULL, 0 } 103 }; 104 105 (void) setlocale(LC_ALL, ""); 106 (void) bindtextdomain("powertop", "/usr/share/locale"); 107 (void) textdomain("powertop"); 108 109 pt_set_progname(argv[0]); 110 111 /* 112 * Enumerate the system's CPUs, populate cpu_table, g_ncpus 113 */ 114 if ((g_ncpus = g_ncpus_observed = enumerate_cpus()) == 0) 115 exit(EXIT_FAILURE); 116 117 if ((g_bit_depth = get_bit_depth()) < 0) 118 exit(EXIT_FAILURE); 119 120 g_features = 0; 121 g_ticktime = g_ticktime_usr = INTERVAL_DEFAULT; 122 g_op_mode = PT_MODE_DEFAULT; 123 g_gui = B_FALSE; 124 g_max_cstate = 0; 125 g_argv = NULL; 126 g_argc = 0; 127 g_observed_cpu = 0; 128 g_turbo_supported = B_FALSE; 129 g_curr_sugg = NULL; 130 131 while ((c = getopt_long(argc, argv, "d:t:h:vc:", opts, &index2)) 132 != EOF) { 133 if (c == -1) 134 break; 135 136 switch (c) { 137 case 'd': 138 if (PT_ON_DUMP) 139 usage(); 140 141 g_op_mode |= PT_MODE_DUMP; 142 dump_count = (int)strtod(optarg, &endptr); 143 144 if (dump_count <= 0 || *endptr != NULL) 145 usage(); 146 break; 147 case 't': 148 if (user_interval) 149 usage(); 150 151 user_interval = 1; 152 g_ticktime = g_ticktime_usr = (double)strtod(optarg, 153 &endptr); 154 155 if (*endptr != NULL || g_ticktime < 1 || 156 g_ticktime > INTERVAL_MAX) 157 usage(); 158 break; 159 case 'v': 160 if (PT_ON_CPU || PT_ON_VERBOSE) 161 usage(); 162 163 g_op_mode |= PT_MODE_VERBOSE; 164 break; 165 case 'c': 166 if (PT_ON_CPU || PT_ON_VERBOSE) 167 usage(); 168 169 g_op_mode |= PT_MODE_CPU; 170 g_observed_cpu = (uint_t)strtod(optarg, &endptr); 171 172 if (g_observed_cpu >= g_ncpus) 173 usage(); 174 175 g_argc = 1; 176 g_ncpus_observed = 1; 177 178 if ((g_argv = malloc(sizeof (char *))) == NULL) 179 return (EXIT_FAILURE); 180 181 if ((*g_argv = malloc(sizeof (char) * 5)) == NULL) 182 return (EXIT_FAILURE); 183 184 (void) snprintf(*g_argv, 5, "%d\0", g_observed_cpu); 185 break; 186 case 'h': 187 default: 188 usage(); 189 return (EXIT_USAGE); 190 } 191 } 192 193 if (optind < argc) 194 usage(); 195 196 (void) printf("%s %s\n\n", TITLE, COPYRIGHT_INTEL); 197 198 (void) printf(_("Collecting data for %.2f second(s) \n"), 199 (float)g_ticktime); 200 201 /* Prepare P-state statistics */ 202 if (pt_cpufreq_stat_prepare() == 0) 203 g_features |= FEATURE_PSTATE; 204 205 /* Prepare C-state statistics */ 206 ret = pt_cpuidle_stat_prepare(); 207 if (ret == 0) 208 g_features |= FEATURE_CSTATE; 209 else 210 /* 211 * PowerTop was unable to run a DTrace program, 212 * most likely for lack of permissions. 213 */ 214 exit(EXIT_FAILURE); 215 216 /* 217 * We need to initiate the display to make sure there's enough space 218 * in the terminal for all of PowerTOP's subwindows, but after 219 * pt_cpufreq_stat_prepare() which finds out how many states the 220 * system supports. 221 */ 222 if (!PT_ON_DUMP) { 223 pt_display_init_curses(); 224 pt_display_setup(B_FALSE); 225 g_gui = B_TRUE; 226 pt_display_title_bar(); 227 pt_display_status_bar(); 228 } 229 230 /* Prepare event statistics */ 231 if (pt_events_stat_prepare() != -1) 232 g_features |= FEATURE_EVENTS; 233 234 /* 235 * If the system is running on battery, find out what's 236 * the kstat module for it 237 */ 238 battery_mod_lookup(); 239 240 /* Prepare turbo statistics */ 241 if (pt_turbo_stat_prepare() == 0) 242 g_features |= FEATURE_TURBO; 243 244 /* 245 * Installs the initial suggestions, running as root and turning CPU 246 * power management ON. 247 */ 248 if (geteuid() != 0) 249 pt_sugg_as_root(); 250 else { 251 root_user = B_TRUE; 252 pt_cpufreq_suggest(); 253 } 254 255 last = gethrtime(); 256 257 while (true) { 258 fd_set rfds; 259 struct timeval tv; 260 int key; 261 char keychar; 262 263 /* 264 * Sleep for a while waiting either for input (if we're not 265 * in dump mode) or for the timeout to elapse 266 */ 267 FD_ZERO(&rfds); 268 FD_SET(0, &rfds); 269 270 tv.tv_sec = (long)g_ticktime; 271 tv.tv_usec = (long)((g_ticktime - tv.tv_sec) * MICROSEC); 272 273 if (!PT_ON_DUMP) { 274 key = select(1, &rfds, NULL, NULL, &tv); 275 } else 276 key = select(1, NULL, NULL, NULL, &tv); 277 278 now = gethrtime(); 279 280 g_interval = (double)(now - last)/NANOSEC; 281 last = now; 282 283 g_top_events = 0; 284 g_total_events = 0; 285 286 (void) memset(g_event_info, 0, 287 EVENT_NUM_MAX * sizeof (event_info_t)); 288 (void) memset(g_cstate_info, 0, 289 NSTATES * sizeof (state_info_t)); 290 291 /* Collect idle state transition stats */ 292 if (g_features & FEATURE_CSTATE && 293 pt_cpuidle_stat_collect(g_interval) < 0) { 294 /* Reinitialize C-state statistics */ 295 if (pt_cpuidle_stat_prepare() != 0) 296 exit(EXIT_FAILURE); 297 298 continue; 299 } 300 301 /* Collect frequency change stats */ 302 if (g_features & FEATURE_PSTATE && 303 pt_cpufreq_stat_collect(g_interval) < 0) { 304 /* Reinitialize P-state statistics */ 305 if (pt_cpufreq_stat_prepare() != 0) 306 exit(EXIT_FAILURE); 307 308 continue; 309 } 310 311 /* Collect event statistics */ 312 if (g_features & FEATURE_EVENTS && 313 pt_events_stat_collect() < 0) { 314 /* Reinitialize event statistics */ 315 if (pt_events_stat_prepare() != 0) 316 exit(EXIT_FAILURE); 317 318 continue; 319 } 320 321 /* Collect turbo statistics */ 322 if (g_features & FEATURE_TURBO && 323 pt_turbo_stat_collect() < 0) 324 exit(EXIT_FAILURE); 325 326 /* Show CPU power states */ 327 pt_display_states(); 328 329 /* Show wakeups events affecting PM */ 330 if (g_features & FEATURE_EVENTS) { 331 pt_display_wakeups(g_interval); 332 pt_display_events(g_interval); 333 } 334 335 pt_battery_print(); 336 337 if (key && !PT_ON_DUMP) { 338 keychar = toupper(fgetc(stdin)); 339 340 switch (keychar) { 341 case 'Q': 342 exit(EXIT_SUCCESS); 343 break; 344 345 case 'R': 346 g_ticktime = 3; 347 break; 348 } 349 350 /* 351 * Check if the user has activated the current 352 * suggestion. 353 */ 354 if (g_curr_sugg != NULL && 355 keychar == g_curr_sugg->key && g_curr_sugg->func) 356 g_curr_sugg->func(); 357 } 358 359 if (dump_count) 360 dump_count--; 361 362 /* Exits if user requested a dump */ 363 if (PT_ON_DUMP && !dump_count) 364 exit(EXIT_SUCCESS); 365 366 /* No key pressed, will suggest something */ 367 if (!key && !dump_count) 368 pt_sugg_pick(); 369 370 /* Refresh display */ 371 if (!PT_ON_DUMP) 372 pt_display_update(); 373 374 if (root_user) 375 pt_cpufreq_suggest(); 376 377 /* 378 * Update the interval based on how long the CPU was in the 379 * longest c-state during the last snapshot. If the user 380 * specified an interval we skip this bit and keep it fixed. 381 */ 382 if (g_features & FEATURE_CSTATE && !user_interval) { 383 last_time = (((double) 384 g_cstate_info[g_longest_cstate].total_time/MICROSEC 385 /g_ncpus)/g_cstate_info[g_longest_cstate].events); 386 387 if (last_time < INTERVAL_DEFAULT || 388 (g_total_events/g_ticktime) < 1) 389 g_ticktime = INTERVAL_DEFAULT; 390 else 391 g_ticktime = INTERVAL_UPDATE(last_time); 392 } else { 393 /* 394 * Restore interval after a refresh. 395 */ 396 if (key) 397 g_ticktime = g_ticktime_usr; 398 } 399 } 400 401 return (EXIT_SUCCESS); 402 } 403