summaryrefslogtreecommitdiffstats
path: root/src/calibrate/calibrate.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/calibrate/calibrate.cpp435
1 files changed, 435 insertions, 0 deletions
diff --git a/src/calibrate/calibrate.cpp b/src/calibrate/calibrate.cpp
new file mode 100644
index 0000000..745d544
--- /dev/null
+++ b/src/calibrate/calibrate.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file 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.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+
+#include "calibrate.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <math.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "../parameters/parameters.h"
+extern "C" {
+#include "../tuning/iw.h"
+}
+
+#include <map>
+#include <vector>
+#include <string>
+
+using namespace std;
+
+
+static vector<string> usb_devices;
+static vector<string> rfkill_devices;
+static vector<string> backlight_devices;
+static vector<string> scsi_link_devices;
+static int blmax;
+
+static map<string, string> saved_sysfs;
+
+
+static volatile int stop_measurement;
+
+static int wireless_PS;
+
+
+static void save_sysfs(const char *filename)
+{
+ char line[4096];
+ ifstream file;
+
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+ file.getline(line, 4096);
+ file.close();
+
+ saved_sysfs[filename] = line;
+}
+
+static void restore_all_sysfs(void)
+{
+ map<string, string>::iterator it;
+
+ for (it = saved_sysfs.begin(); it != saved_sysfs.end(); it++)
+ write_sysfs(it->first, it->second);
+
+ set_wifi_power_saving("wlan0", wireless_PS);
+}
+
+static void find_all_usb_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/active_duration", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/idVendor", d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(filename, sizeof(filename));
+ file.close();
+ if (strcmp(filename, "1d6b") == 0)
+ return;
+ }
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/control", d_name);
+ save_sysfs(filename);
+ usb_devices.push_back(filename);
+}
+
+static void find_all_usb(void)
+{
+ process_directory("/sys/bus/usb/devices/", find_all_usb_callback);
+}
+
+static void suspend_all_usb_devices(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < usb_devices.size(); i++)
+ write_sysfs(usb_devices[i], "auto\n");
+}
+
+static void find_all_rfkill_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/rfkill/%s/soft", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+ save_sysfs(filename);
+ rfkill_devices.push_back(filename);
+}
+
+static void find_all_rfkill(void)
+{
+ process_directory("/sys/class/rfkill/", find_all_rfkill_callback);
+}
+
+static void rfkill_all_radios(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < rfkill_devices.size(); i++)
+ write_sysfs(rfkill_devices[i], "1\n");
+}
+static void unrfkill_all_radios(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < rfkill_devices.size(); i++)
+ write_sysfs(rfkill_devices[i], "0\n");
+}
+
+static void find_backlight_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/backlight/%s/brightness", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ save_sysfs(filename);
+ backlight_devices.push_back(filename);
+ snprintf(filename, sizeof(filename), "/sys/class/backlight/%s/max_brightness", d_name);
+ blmax = read_sysfs(filename);
+}
+
+static void find_backlight(void)
+{
+ process_directory("/sys/class/backlight/", find_backlight_callback);
+}
+
+static void lower_backlight(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < backlight_devices.size(); i++)
+ write_sysfs(backlight_devices[i], "0\n");
+}
+
+static void find_scsi_link_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s/link_power_management_policy", d_name);
+ if (access(filename, R_OK)!=0)
+ return;
+
+ save_sysfs(filename);
+ scsi_link_devices.push_back(filename);
+}
+
+static void find_scsi_link(void)
+{
+ process_directory("/sys/class/scsi_host/", find_scsi_link_callback);
+}
+
+static void set_scsi_link(const char *state)
+{
+ unsigned int i;
+
+ for (i = 0; i < scsi_link_devices.size(); i++)
+ write_sysfs(scsi_link_devices[i], state);
+}
+
+
+static void *burn_cpu(void *dummy)
+{
+ volatile double d = 1.1;
+
+ while (!stop_measurement) {
+ d = pow(d, 1.0001);
+ }
+ return NULL;
+}
+
+static void *burn_cpu_wakeups(void *dummy)
+{
+ struct timespec tm;
+
+ while (!stop_measurement) {
+ tm.tv_sec = 0;
+ tm.tv_nsec = (unsigned long)dummy;
+ nanosleep(&tm, NULL);
+ }
+ return NULL;
+}
+
+static void *burn_disk(void *dummy)
+{
+ int fd;
+ char buffer[64*1024];
+ char filename[256];
+
+ strcpy(filename ,"/tmp/powertop.XXXXXX");
+ fd = mkstemp(filename);
+
+ if (fd < 0) {
+ printf(_("Cannot create temp file\n"));
+ return NULL;
+ }
+
+ while (!stop_measurement) {
+ lseek(fd, 0, SEEK_SET);
+ if(write(fd, buffer, 64*1024) == -1)
+ printf("Error: %s\n", strerror(errno));
+ fdatasync(fd);
+ }
+ unlink(filename);
+ return NULL;
+}
+
+
+static void cpu_calibration(int threads)
+{
+ int i;
+ pthread_t thr;
+
+ printf(_("Calibrating: CPU usage on %i threads\n"), threads);
+
+ stop_measurement = 0;
+ for (i = 0; i < threads; i++)
+ pthread_create(&thr, NULL, burn_cpu, NULL);
+
+ one_measurement(15, 15, NULL);
+ stop_measurement = 1;
+ sleep(1);
+}
+
+static void wakeup_calibration(unsigned long interval)
+{
+ pthread_t thr;
+
+ printf(_("Calibrating: CPU wakeup power consumption\n"));
+
+ stop_measurement = 0;
+
+ pthread_create(&thr, NULL, burn_cpu_wakeups, (void *)interval);
+
+ one_measurement(15, 15, NULL);
+ stop_measurement = 1;
+ sleep(1);
+}
+
+static void usb_calibration(void)
+{
+ unsigned int i;
+
+ /* chances are one of the USB devices is bluetooth; unrfkill first */
+ unrfkill_all_radios();
+ printf(_("Calibrating USB devices\n"));
+ for (i = 0; i < usb_devices.size(); i++) {
+ printf(_(".... device %s \n"), usb_devices[i].c_str());
+ suspend_all_usb_devices();
+ write_sysfs(usb_devices[i], "on\n");
+ one_measurement(15, 15, NULL);
+ suspend_all_usb_devices();
+ sleep(3);
+ }
+ rfkill_all_radios();
+ sleep(4);
+}
+
+static void rfkill_calibration(void)
+{
+ unsigned int i;
+
+ printf(_("Calibrating radio devices\n"));
+ for (i = 0; i < rfkill_devices.size(); i++) {
+ printf(_(".... device %s \n"), rfkill_devices[i].c_str());
+ rfkill_all_radios();
+ write_sysfs(rfkill_devices[i], "0\n");
+ one_measurement(15, 15, NULL);
+ rfkill_all_radios();
+ sleep(3);
+ }
+ for (i = 0; i < rfkill_devices.size(); i++) {
+ printf(_(".... device %s \n"), rfkill_devices[i].c_str());
+ unrfkill_all_radios();
+ write_sysfs(rfkill_devices[i], "1\n");
+ one_measurement(15, 15, NULL);
+ unrfkill_all_radios();
+ sleep(3);
+ }
+ rfkill_all_radios();
+}
+
+static void backlight_calibration(void)
+{
+ unsigned int i;
+
+ printf(_("Calibrating backlight\n"));
+ for (i = 0; i < backlight_devices.size(); i++) {
+ char str[4096];
+ printf(_(".... device %s \n"), backlight_devices[i].c_str());
+ lower_backlight();
+ one_measurement(15, 15, NULL);
+ sprintf(str, "%i\n", blmax / 4);
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+
+ sprintf(str, "%i\n", blmax / 2);
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+
+ sprintf(str, "%i\n", 3 * blmax / 4 );
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+
+ sprintf(str, "%i\n", blmax);
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+ lower_backlight();
+ sleep(1);
+ }
+ printf(_("Calibrating idle\n"));
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force off"))
+ printf("System is not available\n");
+ one_measurement(15, 15, NULL);
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force on"))
+ printf("System is not available\n");
+}
+
+static void idle_calibration(void)
+{
+ printf(_("Calibrating idle\n"));
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force off"))
+ printf("System is not available\n");
+ one_measurement(15, 15, NULL);
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force on"))
+ printf("System is not available\n");
+}
+
+
+static void disk_calibration(void)
+{
+ pthread_t thr;
+
+ printf(_("Calibrating: disk usage \n"));
+
+ set_scsi_link("min_power");
+
+ stop_measurement = 0;
+ pthread_create(&thr, NULL, burn_disk, NULL);
+
+ one_measurement(15, 15, NULL);
+ stop_measurement = 1;
+ sleep(1);
+
+
+}
+
+
+void calibrate(void)
+{
+ find_all_usb();
+ find_all_rfkill();
+ find_backlight();
+ find_scsi_link();
+ wireless_PS = get_wifi_power_saving("wlan0");
+
+ save_sysfs("/sys/module/snd_hda_intel/parameters/power_save");
+
+ cout << _("Starting PowerTOP power estimate calibration \n");
+ suspend_all_usb_devices();
+ rfkill_all_radios();
+ lower_backlight();
+ set_wifi_power_saving("wlan0", 1);
+
+ sleep(4);
+
+
+ idle_calibration();
+ disk_calibration();
+ backlight_calibration();
+
+ write_sysfs("/sys/module/snd_hda_intel/parameters/power_save", "1\n");
+ cpu_calibration(1);
+ cpu_calibration(4);
+ wakeup_calibration(10000);
+ wakeup_calibration(100000);
+ wakeup_calibration(1000000);
+ set_wifi_power_saving("wlan0", 0);
+ usb_calibration();
+ rfkill_calibration();
+
+ cout << _("Finishing PowerTOP power estimate calibration \n");
+
+ restore_all_sysfs();
+ learn_parameters(300, 1);
+ printf(_("Parameters after calibration:\n"));
+ dump_parameter_bundle();
+ save_parameters("saved_parameters.powertop");
+ save_all_results("saved_results.powertop");
+
+}