summaryrefslogtreecommitdiffstats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp578
1 files changed, 578 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..45aaa58
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,578 @@
+/*
+ * 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 <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/resource.h>
+#include <limits.h>
+#include <pthread.h>
+
+#include "cpu/cpu.h"
+#include "process/process.h"
+#include "perf/perf.h"
+#include "perf/perf_bundle.h"
+#include "lib.h"
+#include "../config.h"
+
+
+#include "devices/device.h"
+#include "devices/devfreq.h"
+#include "devices/usb.h"
+#include "devices/ahci.h"
+#include "measurement/measurement.h"
+#include "parameters/parameters.h"
+#include "calibrate/calibrate.h"
+
+
+#include "tuning/tuning.h"
+#include "wakeup/wakeup.h"
+
+#include "display.h"
+#include "devlist.h"
+#include "report/report.h"
+
+#define DEBUGFS_MAGIC 0x64626720
+
+#define NR_OPEN_DEF 1024 * 1024
+
+int debug_learning = 0;
+unsigned time_out = 20;
+int leave_powertop = 0;
+void (*ui_notify_user) (const char *frmt, ...);
+
+enum {
+ OPT_AUTO_TUNE = CHAR_MAX + 1,
+ OPT_EXTECH,
+ OPT_DEBUG
+};
+
+static const struct option long_options[] =
+{
+ /* These options set a flag. */
+ {"auto-tune", no_argument, NULL, OPT_AUTO_TUNE},
+ {"calibrate", no_argument, NULL, 'c'},
+ {"csv", optional_argument, NULL, 'C'},
+ {"debug", no_argument, &debug_learning, OPT_DEBUG},
+ {"extech", optional_argument, NULL, OPT_EXTECH},
+ {"html", optional_argument, NULL, 'r'},
+ {"iteration", optional_argument, NULL, 'i'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"sample", optional_argument, NULL, 's'},
+ {"time", optional_argument, NULL, 't'},
+ {"workload", optional_argument, NULL, 'w'},
+ {"version", no_argument, NULL, 'V'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+};
+
+static void print_version()
+{
+ printf(_("PowerTOP version " PACKAGE_VERSION "\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(" --auto-tune\t %s\n", _("sets all tunable options to their GOOD setting"));
+ printf(" -c, --calibrate\t %s\n", _("runs powertop in calibration mode"));
+ printf(" -C, --csv%s\t %s\n", _("[=filename]"), _("generate a csv report"));
+ printf(" --debug\t\t %s\n", _("run in \"debug\" mode"));
+ printf(" --extech%s\t %s\n", _("[=devnode]"), _("uses an Extech Power Analyzer for measurements"));
+ printf(" -r, --html%s\t %s\n", _("[=filename]"), _("generate a html report"));
+ printf(" -i, --iteration%s\n", _("[=iterations] number of times to run each test"));
+ printf(" -q, --quiet\t\t %s\n", _("suppress stderr output"));
+ printf(" -s, --sample%s\t %s\n", _("[=seconds]"), _("interval for power consumption measurement"));
+ printf(" -t, --time%s\t %s\n", _("[=seconds]"), _("generate a report for 'x' seconds"));
+ printf(" -w, --workload%s %s\n", _("[=workload]"), _("file to execute for workload"));
+ printf(" -V, --version\t\t %s\n", _("print version information"));
+ printf(" -h, --help\t\t %s\n", _("print this help menu"));
+ printf("\n");
+ printf("%s\n\n", _("For more help please refer to the 'man 8 powertop'"));
+}
+
+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 KEY_BTAB:
+ show_prev_tab();
+ break;
+ case '\t':
+ 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 ' ':
+ case '\n':
+ cursor_enter();
+ break;
+ case 's':
+ if (set_refresh_timeout())
+ return;
+ break;
+ case 'r':
+ window_refresh();
+ return;
+ case KEY_EXIT:
+ case 'q':
+ case 27: // Escape
+ leave_powertop = 1;
+ return;
+ }
+
+ delta = target - time(NULL);
+ if (delta <= 0)
+ break;
+
+ } while (1);
+}
+
+extern "C" {
+ static volatile bool end_thread;
+ void* measure_background_thread(void *arg)
+ {
+ int sleep_time = *((int *) arg);
+ while (!end_thread) {
+ do_sleep(sleep_time);
+ global_sample_power();
+ }
+ return 0;
+ }
+}
+
+void one_measurement(int seconds, int sample_interval, char *workload)
+{
+ create_all_usb_devices();
+ start_power_measurement();
+ devices_start_measurement();
+ start_devfreq_measurement();
+ start_process_measurement();
+ start_cpu_measurement();
+
+ if (workload && workload[0]) {
+ pthread_t thread = 0UL;
+ end_thread = false;
+ if (pthread_create(&thread, NULL, measure_background_thread, &sample_interval))
+ fprintf(stderr, "ERROR: workload measurement thread creation failed\n");
+
+ if (system(workload))
+ fprintf(stderr, _("Unknown issue running workload!\n"));
+
+ if (thread)
+ {
+ end_thread = true;
+ pthread_join( thread, NULL);
+ }
+ global_sample_power();
+ } else {
+ while (seconds > 0)
+ {
+ do_sleep(sample_interval > seconds ? seconds : sample_interval);
+ seconds -= sample_interval;
+ global_sample_power();
+ }
+ }
+ end_cpu_measurement();
+ end_process_measurement();
+ collect_open_devices();
+ end_devfreq_measurement();
+ 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();
+ if (reporttype != REPORT_OFF) {
+ report_display_cpu_cstates();
+ report_display_cpu_pstates();
+ }
+ report_process_update_display();
+ tuning_update_display();
+ wakeup_update_display();
+ end_process_data();
+
+ global_power();
+ compute_bundle();
+
+ show_report_devices();
+ report_show_open_devices();
+
+ report_devices();
+ display_devfreq_devices();
+ report_devfreq_devices();
+ ahci_create_device_stats_table();
+ 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 make_report(int time, char *workload, int iterations, int sample_interval, char *file)
+{
+
+ /* one to warm up everything */
+ fprintf(stderr, _("Preparing to take measurements\n"));
+ utf_ok = 0;
+ one_measurement(1, sample_interval, 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();
+ initialize_wakeup();
+ /* and then the real measurement */
+ one_measurement(time, sample_interval, workload);
+ report_show_tunables();
+ report_show_wakeup();
+ 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 " PACKAGE_VERSION " must be run with root privileges.\n"));
+ printf(_("exiting...\n"));
+ exit(EXIT_FAILURE);
+ }
+
+}
+
+static int get_nr_open(void) {
+ int nr_open = NR_OPEN_DEF;
+ ifstream file;
+
+ file.open("/proc/sys/fs/nr_open", ios::in);
+ if (file) {
+ file >> nr_open;
+ file.close();
+ }
+ return nr_open;
+}
+
+static void powertop_init(int auto_tune)
+{
+ static char initialized = 0;
+ int ret;
+ struct statfs st_fs;
+ struct rlimit rlmt;
+
+ if (initialized)
+ return;
+
+ checkroot();
+
+ rlmt.rlim_cur = rlmt.rlim_max = get_nr_open();
+ setrlimit (RLIMIT_NOFILE, &rlmt);
+
+ if (system("/sbin/modprobe cpufreq_stats > /dev/null 2>&1"))
+ fprintf(stderr, _("modprobe cpufreq_stats failed\n"));
+#if defined(__i386__) || defined(__x86_64__)
+ if (system("/sbin/modprobe msr > /dev/null 2>&1"))
+ fprintf(stderr, _("modprobe msr failed\n"));
+#endif
+ 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) {
+ if (!auto_tune) {
+ fprintf(stderr, _("Failed to mount debugfs!\n"));
+ fprintf(stderr, _("exiting...\n"));
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(stderr, _("Failed to mount debugfs!\n"));
+ fprintf(stderr, _("Should still be able to auto tune...\n"));
+ }
+ }
+ }
+
+ 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();
+ create_all_devfreq_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;
+}
+
+void clean_shutdown()
+{
+ close_results();
+ clean_open_devices();
+ clear_all_devices();
+ clear_all_devfreq();
+ clear_all_cpus();
+
+ return;
+}
+
+
+int main(int argc, char **argv)
+{
+ int option_index;
+ int c;
+ char filename[PATH_MAX];
+ char workload[PATH_MAX] = {0};
+ int iterations = 1, auto_tune = 0, sample_interval = 5;
+
+ set_new_handler(out_of_memory);
+
+ setlocale (LC_ALL, "");
+
+#ifdef ENABLE_NLS
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+#endif
+ ui_notify_user = ui_notify_user_ncurses;
+ while (1) { /* parse commandline options */
+ c = getopt_long(argc, argv, "cC::r::i:qt:w:Vh", long_options, &option_index);
+ /* Detect the end of the options. */
+ if (c == -1)
+ break;
+ switch (c) {
+ case OPT_AUTO_TUNE:
+ auto_tune = 1;
+ leave_powertop = 1;
+ ui_notify_user = ui_notify_user_console;
+ break;
+ case 'c':
+ powertop_init(0);
+ calibrate();
+ break;
+ case 'C': /* csv report */
+ reporttype = REPORT_CSV;
+ snprintf(filename, sizeof(filename), "%s", optarg ? optarg : "powertop.csv");
+ if (!strlen(filename))
+ {
+ fprintf(stderr, _("Invalid CSV filename\n"));
+ exit(1);
+ }
+ break;
+ case OPT_DEBUG:
+ /* implemented using getopt_long(3) flag */
+ break;
+ case OPT_EXTECH: /* Extech power analyzer support */
+ checkroot();
+ extech_power_meter(optarg ? optarg : "/dev/ttyUSB0");
+ break;
+ case 'r': /* html report */
+ reporttype = REPORT_HTML;
+ snprintf(filename, sizeof(filename), "%s", optarg ? optarg : "powertop.html");
+ if (!strlen(filename))
+ {
+ fprintf(stderr, _("Invalid HTML filename\n"));
+ exit(1);
+ }
+ break;
+ case 'i':
+ iterations = (optarg ? atoi(optarg) : 1);
+ break;
+ case 'q':
+ if (freopen("/dev/null", "a", stderr))
+ fprintf(stderr, _("Quiet mode failed!\n"));
+ break;
+ case 's':
+ sample_interval = (optarg ? atoi(optarg) : 5);
+ break;
+ case 't':
+ time_out = (optarg ? atoi(optarg) : 20);
+ break;
+ case 'w': /* measure workload */
+ snprintf(workload, sizeof(workload), "%s", optarg ? optarg : "");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ case 'h':
+ print_usage();
+ exit(0);
+ break;
+ case '?': /* Unknown option */
+ /* getopt_long already printed an error message. */
+ exit(1);
+ break;
+ }
+ }
+
+ powertop_init(auto_tune);
+
+ if (reporttype != REPORT_OFF)
+ make_report(time_out, workload, iterations, sample_interval, 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);
+ }
+ if (!auto_tune)
+ init_display();
+
+ initialize_devfreq();
+ initialize_tuning();
+ initialize_wakeup();
+ /* first one is short to not let the user wait too long */
+ one_measurement(1, sample_interval, NULL);
+
+ if (!auto_tune) {
+ tuning_update_display();
+ show_tab(0);
+ } else {
+ auto_toggle_tuning();
+ }
+
+ while (!leave_powertop) {
+ if (!auto_tune)
+ show_cur_tab();
+ one_measurement(time_out, sample_interval, NULL);
+ learn_parameters(15, 0);
+ }
+ if (!auto_tune)
+ endwin();
+ fprintf(stderr, "%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();
+
+ clean_shutdown();
+
+ return 0;
+}