/* * Copyright 2010, Intel Corporation * * This 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 * or just google for it. * * getopt code is taken from "The GNU C Library" reference manual, * section 24.2 "Parsing program options using getopt" * http://www.gnu.org/s/libc/manual/html_node/Getopt-Long-Option-Example.html * Manual published under the terms of the Free Documentation License. * * Authors: * Arjan van de Ven */ #include #include #include #include #include #include #include #include #include #include "cpu/cpu.h" #include "process/process.h" #include "perf/perf.h" #include "perf/perf_bundle.h" #include "lib.h" #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "devices/device.h" #include "devices/usb.h" #include "measurement/measurement.h" #include "parameters/parameters.h" #include "calibrate/calibrate.h" #include "tuning/tuning.h" #include "display.h" #include "devlist.h" #include "report.h" #define DEBUGFS_MAGIC 0x64626720 int debug_learning = 0; unsigned time_out = 20; int leave_powertop = 0; static const struct option long_options[] = { /* These options set a flag. */ {"debug", no_argument, &debug_learning, 'd'}, {"version", no_argument, NULL, 'V'}, {"help",no_argument, NULL, 'u'}, /* u for usage */ {"calibrate",no_argument, NULL, 'c'}, {"html", optional_argument, NULL, 'h'}, {"csv", optional_argument, NULL, 'C'}, {"extech", optional_argument, NULL, 'e'}, {"time", optional_argument, NULL, 't'}, {"iteration", optional_argument, NULL, 'i'}, {"workload", optional_argument, NULL, 'w'}, {"quiet", optional_argument, NULL, 'q'}, {NULL, 0, NULL, 0} }; static void print_version() { printf(_("PowerTOP version" POWERTOP_VERSION ", compiled on " __DATE__ "\n")); } static bool set_refresh_timeout() { static char buf[4]; mvprintw(1, 0, "%s (currently %u): ", _("Set refresh time out"), time_out); memset(buf, '\0', sizeof(buf)); get_user_input(buf, sizeof(buf) - 1); show_tab(0); unsigned time = strtoul(buf, NULL, 0); if (!time) return 0; if (time > 32) time = 32; time_out = time; return 1; } static void print_usage() { printf("%s\n\n",_("Usage: powertop [OPTIONS]")); printf("--debug \t\t %s\n",_("run in \"debug\" mode")); printf("--version \t\t %s\n",_("print version information")); printf("--calibrate \t\t %s\n",_("runs powertop in calibration mode")); printf("--extech%s \t %s\n",_("[=devnode]"),_("uses an Extech Power Analyzer for measurements")); printf("--html%s \t %s\n",_("[=FILENAME]"),_("generate a html report")); printf("--csv%s \t %s\n",_("[=FILENAME]"),_("generate a csv report")); printf("--time%s \t %s\n",_("[=seconds]"), _("generate a report for 'x' seconds")); printf("--iteration%s\n", _("[=iterations] number of times to run each test")); printf("--workload%s \t %s\n", _("[=workload]"), _("file to execute for workload")); printf("--quiet \t\t %s\n", _("supress stderr output")); printf("--help \t\t\t %s\n",_("print this help menu")); printf("\n"); printf("%s\n\n",_("For more help please refer to the README")); } static void do_sleep(int seconds) { time_t target; int delta; if (!ncurses_initialized()) { sleep(seconds); return; } target = time(NULL) + seconds; delta = seconds; do { int c; usleep(6000); halfdelay(delta * 10); c = getch(); switch (c) { case 353: show_prev_tab(); break; case 9: show_next_tab(); break; case KEY_RIGHT: cursor_right(); break; case KEY_LEFT: cursor_left(); break; case KEY_NPAGE: case KEY_DOWN: cursor_down(); break; case KEY_PPAGE: case KEY_UP: cursor_up(); break; case 32: case 10: cursor_enter(); break; case 's': if (set_refresh_timeout()) return; break; case 'r': window_refresh(); return; case KEY_EXIT: case 'q': case 27: leave_powertop = 1; return; } delta = target - time(NULL); if (delta <= 0) break; } while (1); } void one_measurement(int seconds, char *workload) { create_all_usb_devices(); start_power_measurement(); devices_start_measurement(); start_process_measurement(); start_cpu_measurement(); if (workload && workload[0]) { system(workload); } else { do_sleep(seconds); } end_cpu_measurement(); end_process_measurement(); collect_open_devices(); devices_end_measurement(); end_power_measurement(); process_cpu_data(); process_process_data(); /* output stats */ process_update_display(); report_summary(); w_display_cpu_cstates(); w_display_cpu_pstates(); report_display_cpu_cstates(); report_display_cpu_pstates(); report_process_update_display(); tuning_update_display(); end_process_data(); global_joules_consumed(); compute_bundle(); show_report_devices(); report_show_open_devices(); report_devices(); store_results(measurement_time); end_cpu_data(); } void out_of_memory() { reset_display(); printf("%s...\n",_("PowerTOP is out of memory. PowerTOP is Aborting")); abort(); } void report(int time, char *workload, int iterations, char *file) { /* one to warm up everything */ fprintf(stderr, _("Preparing to take measurements\n")); utf_ok = 0; one_measurement(1, NULL); if (!workload[0]) fprintf(stderr, _("Taking %d measurement(s) for a duration of %d second(s) each.\n"),iterations,time); else fprintf(stderr, _("Measuring workload %s.\n"), workload); for (int i=0; i != iterations; i++){ init_report_output(file, iterations); initialize_tuning(); /* and then the real measurement */ one_measurement(time, workload); report_show_tunables(); finish_report_output(); clear_tuning(); } /* and wrap up */ learn_parameters(50, 0); save_all_results("saved_results.powertop"); save_parameters("saved_parameters.powertop"); end_pci_access(); exit(0); } static void checkroot() { int uid; uid = getuid(); if (uid != 0) { printf(_("PowerTOP " POWERTOP_VERSION " must be run with root privileges.\n")); printf(_("exiting...\n")); exit(EXIT_FAILURE); } } static void powertop_init(void) { static char initialized = 0; int ret; struct statfs st_fs; if (initialized) return; checkroot(); ret = system("/sbin/modprobe cpufreq_stats > /dev/null 2>&1"); ret = system("/sbin/modprobe msr > /dev/null 2>&1"); statfs("/sys/kernel/debug", &st_fs); if (st_fs.f_type != (long) DEBUGFS_MAGIC) { if (access("/bin/mount", X_OK) == 0) { ret = system("/bin/mount -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1"); } else { ret = system("mount -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1"); } if (ret != 0) { printf(_("Failed to mount debugfs!\n")); printf(_("exiting...\n")); exit(EXIT_FAILURE); } } srand(time(NULL)); if (access("/var/cache/", W_OK) == 0) mkdir("/var/cache/powertop", 0600); else mkdir("/data/local/powertop", 0600); load_results("saved_results.powertop"); load_parameters("saved_parameters.powertop"); enumerate_cpus(); create_all_devices(); detect_power_meters(); register_parameter("base power", 100, 0.5); register_parameter("cpu-wakeups", 39.5); register_parameter("cpu-consumption", 1.56); register_parameter("gpu-operations", 0.5576); register_parameter("disk-operations-hard", 0.2); register_parameter("disk-operations", 0.0); register_parameter("xwakes", 0.1); load_parameters("saved_parameters.powertop"); initialized = 1; } int main(int argc, char **argv) { int option_index; int c; bool wantreport = false; char filename[4096]; char workload[4096] = {0,}; int iterations = 1; set_new_handler(out_of_memory); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); #ifdef DEFAULT_TERM if (!getenv("TERM")) setenv("TERM", DEFAULT_TERM, 1); #endif #ifdef TERMINFO_PATH if (!getenv("TERMINFO")) setenv("TERMINFO", TERMINFO_PATH, 1); #endif while (1) { /* parse commandline options */ c = getopt_long (argc, argv, "ch:C:i:t:uVw:q", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; switch (c) { case 'V': print_version(); exit(0); break; case 'e': /* Extech power analyzer support */ checkroot(); extech_power_meter(optarg ? optarg : "/dev/ttyUSB0"); break; case 'u': print_usage(); exit(0); break; case 'c': powertop_init(); calibrate(); break; case 'h': /* html report */ wantreport = true; reporttype = 1; sprintf(filename, "%s", optarg ? optarg : "powertop.html" ); break; case 't': time_out = (optarg ? atoi(optarg) : 20); break; case 'i': iterations = (optarg ? atoi(optarg) : 1); break; case 'w': /* measure workload */ sprintf(workload, "%s", optarg ? optarg :'\0' ); break; case 'q': freopen("/dev/null", "a", stderr); break; case 'C': /* csv report*/ wantreport = true; reporttype = 0; sprintf(filename, "%s", optarg ? optarg : "powertop.csv"); break; case '?': /* Unknown option */ /* getopt_long already printed an error message. */ exit(0); break; } } powertop_init(); if (wantreport) report(time_out, workload, iterations, filename); if (debug_learning) printf("Learning debugging enabled\n"); learn_parameters(250, 0); save_parameters("saved_parameters.powertop"); if (debug_learning) { learn_parameters(1000, 1); dump_parameter_bundle(); end_pci_access(); exit(0); } /* first one is short to not let the user wait too long */ init_display(); one_measurement(1, NULL); initialize_tuning(); tuning_update_display(); show_tab(0); while (!leave_powertop) { show_cur_tab(); one_measurement(time_out, NULL); learn_parameters(15, 0); } endwin(); printf("%s\n", _("Leaving PowerTOP")); end_process_data(); clear_process_data(); end_cpu_data(); clear_cpu_data(); save_all_results("saved_results.powertop"); save_parameters("saved_parameters.powertop"); learn_parameters(500, 0); save_parameters("saved_parameters.powertop"); end_pci_access(); clear_tuning(); reset_display(); clear_all_devices(); clear_all_cpus(); return 0; }