diff options
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/ahci.cpp | 428 | ||||
-rw-r--r-- | src/devices/ahci.h | 72 | ||||
-rw-r--r-- | src/devices/alsa.cpp | 207 | ||||
-rw-r--r-- | src/devices/alsa.h | 67 | ||||
-rw-r--r-- | src/devices/backlight.cpp | 225 | ||||
-rw-r--r-- | src/devices/backlight.h | 59 | ||||
-rw-r--r-- | src/devices/devfreq.cpp | 334 | ||||
-rw-r--r-- | src/devices/devfreq.h | 76 | ||||
-rw-r--r-- | src/devices/device.cpp | 345 | ||||
-rw-r--r-- | src/devices/device.h | 85 | ||||
-rw-r--r-- | src/devices/gpu_rapl_device.cpp | 70 | ||||
-rw-r--r-- | src/devices/gpu_rapl_device.h | 57 | ||||
-rw-r--r-- | src/devices/i915-gpu.cpp | 121 | ||||
-rw-r--r-- | src/devices/i915-gpu.h | 58 | ||||
-rw-r--r-- | src/devices/network.cpp | 441 | ||||
-rw-r--r-- | src/devices/network.h | 85 | ||||
-rw-r--r-- | src/devices/rfkill.cpp | 177 | ||||
-rw-r--r-- | src/devices/rfkill.h | 62 | ||||
-rw-r--r-- | src/devices/runtime_pm.cpp | 257 | ||||
-rw-r--r-- | src/devices/runtime_pm.h | 66 | ||||
-rw-r--r-- | src/devices/thinkpad-fan.cpp | 124 | ||||
-rw-r--r-- | src/devices/thinkpad-fan.h | 58 | ||||
-rw-r--r-- | src/devices/thinkpad-light.cpp | 113 | ||||
-rw-r--r-- | src/devices/thinkpad-light.h | 58 | ||||
-rw-r--r-- | src/devices/usb.cpp | 254 | ||||
-rw-r--r-- | src/devices/usb.h | 67 |
26 files changed, 3966 insertions, 0 deletions
diff --git a/src/devices/ahci.cpp b/src/devices/ahci.cpp new file mode 100644 index 0000000..efa66b3 --- /dev/null +++ b/src/devices/ahci.cpp @@ -0,0 +1,428 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <limits.h> + + +using namespace std; + +#include "device.h" +#include "report/report.h" +#include "report/report-maker.h" +#include "ahci.h" +#include "../parameters/parameters.h" +#include "report/report-data-html.h" +#include <string.h> + +vector <class ahci *> links; + +static string disk_name(char *path, char *target, char *shortname) +{ + + DIR *dir; + struct dirent *dirent; + char pathname[PATH_MAX]; + string diskname = ""; + + snprintf(pathname, sizeof(pathname), "%s/%s", path, target); + dir = opendir(pathname); + if (!dir) + return diskname; + + while ((dirent = readdir(dir))) { + char line[4096], *c; + FILE *file; + if (dirent->d_name[0]=='.') + continue; + + if (!strchr(dirent->d_name, ':')) + continue; + + snprintf(line, sizeof(line), "%s/%s/model", pathname, dirent->d_name); + file = fopen(line, "r"); + if (file) { + if (fgets(line, sizeof(line), file) == NULL) { + fclose(file); + break; + } + fclose(file); + c = strchr(line, '\n'); + if (c) + *c = 0; + diskname = line; + break; + } + } + closedir(dir); + + return diskname; +} + +static string model_name(char *path, char *shortname) +{ + + DIR *dir; + struct dirent *dirent; + char pathname[PATH_MAX]; + + snprintf(pathname, sizeof(pathname), "%s/device", path); + + dir = opendir(pathname); + if (!dir) + return strdup(shortname); + + while ((dirent = readdir(dir))) { + if (dirent->d_name[0]=='.') + continue; + + if (!strchr(dirent->d_name, ':')) + continue; + if (!strstr(dirent->d_name, "target")) + continue; + return disk_name(pathname, dirent->d_name, shortname); + } + closedir(dir); + + return ""; +} + +ahci::ahci(char *_name, char *path): device() +{ + char buffer[4096]; + char devname[128]; + string diskname; + + end_active = 0; + end_slumber = 0; + end_devslp = 0; + end_partial = 0; + start_active = 0; + start_slumber = 0; + start_devslp = 0; + start_partial = 0; + pt_strcpy(sysfs_path, path); + + register_sysfs_path(sysfs_path); + + snprintf(devname, sizeof(devname), "ahci:%s", _name); + pt_strcpy(name, devname); + active_index = get_param_index("ahci-link-power-active"); + partial_index = get_param_index("ahci-link-power-partial"); + + snprintf(buffer, sizeof(buffer), "%s-active", name); + active_rindex = get_result_index(buffer); + + snprintf(buffer, sizeof(buffer), "%s-partial", name); + partial_rindex = get_result_index(buffer); + + snprintf(buffer, sizeof(buffer), "%s-slumber", name); + slumber_rindex = get_result_index(buffer); + + snprintf(buffer, sizeof(buffer), "%s-devslp", name); + devslp_rindex = get_result_index(buffer); + + diskname = model_name(path, _name); + + if (strlen(diskname.c_str()) == 0) + snprintf(humanname, sizeof(humanname), _("SATA link: %s"), _name); + else + snprintf(humanname, sizeof(humanname), _("SATA disk: %s"), diskname.c_str()); +} + +void ahci::start_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + snprintf(filename, sizeof(filename), "%s/ahci_alpm_active", sysfs_path); + try { + file.open(filename, ios::in); + if (file) { + file >> start_active; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/ahci_alpm_partial", sysfs_path); + file.open(filename, ios::in); + + if (file) { + file >> start_partial; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/ahci_alpm_slumber", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> start_slumber; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/ahci_alpm_devslp", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> start_devslp; + } + file.close(); + } + catch (std::ios_base::failure &c) { + fprintf(stderr, "%s\n", c.what()); + } + +} + +void ahci::end_measurement(void) +{ + char filename[PATH_MAX]; + char powername[4096]; + ifstream file; + double p; + double total; + + try { + snprintf(filename, sizeof(filename), "%s/ahci_alpm_active", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_active; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/ahci_alpm_partial", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_partial; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/ahci_alpm_slumber", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_slumber; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/ahci_alpm_devslp", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_devslp; + } + file.close(); + } + catch (std::ios_base::failure &c) { + fprintf(stderr, "%s\n", c.what()); + } + if (end_active < start_active) + end_active = start_active; + if (end_partial < start_partial) + end_partial = start_partial; + if (end_slumber < start_slumber) + end_slumber = start_slumber; + + total = 0.001 + end_active + end_partial + end_slumber + end_devslp - + start_active - start_partial - start_slumber - start_devslp; + + /* percent in active */ + p = (end_active - start_active) / total * 100.0; + if (p < 0) + p = 0; + snprintf(powername, sizeof(powername), "%s-active", name); + report_utilization(powername, p); + + /* percent in partial */ + p = (end_partial - start_partial) / total * 100.0; + if (p < 0) + p = 0; + snprintf(powername, sizeof(powername), "%s-partial", name); + report_utilization(powername, p); + + /* percent in slumber */ + p = (end_slumber - start_slumber) / total * 100.0; + if (p < 0) + p = 0; + snprintf(powername, sizeof(powername), "%s-slumber", name); + report_utilization(powername, p); + + /* percent in devslp */ + p = (end_devslp - start_devslp) / total * 100.0; + if (p < 0) + p = 0; + snprintf(powername, sizeof(powername), "%s-devslp", name); + report_utilization(powername, p); +} + + +double ahci::utilization(void) +{ + double p; + + p = (end_partial - start_partial + end_active - start_active) / (0.001 + end_active + end_partial + end_slumber + end_devslp - start_active - start_partial - start_slumber - start_devslp) * 100.0; + + if (p < 0) + p = 0; + + return p; +} + +const char * ahci::device_name(void) +{ + return name; +} + +void create_all_ahcis(void) +{ + struct dirent *entry; + DIR *dir; + char filename[PATH_MAX]; + + dir = opendir("/sys/class/scsi_host/"); + if (!dir) + return; + while (1) { + class ahci *bl; + ofstream file; + ifstream check_file; + entry = readdir(dir); + if (!entry) + break; + if (entry->d_name[0] == '.') + continue; + snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s/ahci_alpm_accounting", entry->d_name); + + check_file.open(filename, ios::in); + check_file.get(); + check_file.close(); + if (check_file.bad()) + continue; + + file.open(filename, ios::in); + if (!file) + continue; + file << 1 ; + file.close(); + snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s", entry->d_name); + + bl = new class ahci(entry->d_name, filename); + all_devices.push_back(bl); + register_parameter("ahci-link-power-active", 0.6); /* active sata link takes about 0.6 W */ + register_parameter("ahci-link-power-partial"); + links.push_back(bl); + } + closedir(dir); + +} + + + +double ahci::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + power = 0; + + factor = get_parameter_value(active_index, bundle); + util = get_result_value(active_rindex, result); + power += util * factor / 100.0; + + + factor = get_parameter_value(partial_index, bundle); + util = get_result_value(partial_rindex, result); + power += util * factor / 100.0; + + return power; +} + +void ahci_create_device_stats_table(void) +{ + unsigned int i; + int cols=0; + int rows=0; + + /* div attr css_class and css_id */ + tag_attr div_attr; + init_div(&div_attr, "clear_block", "ahci"); + + /* Set Title attributes */ + tag_attr title_attr; + init_title_attr(&title_attr); + + /* Add section */ + report.add_div(&div_attr); + + if (links.size() == 0) { + report.add_title(&title_attr, __("AHCI ALPM Residency Statistics - Not supported on this macine")); + report.end_div(); + return; + } + + /* Set Table attributes, rows, and cols */ + table_attributes std_table_css; + cols=5; + rows=links.size()+1; + init_std_side_table_attr(&std_table_css, rows, cols); + + + + /* Set array of data in row Major order */ + string *ahci_data = new string[cols * rows]; + ahci_data[0]=__("Link"); + ahci_data[1]=__("Active"); + ahci_data[2]=__("Partial"); + ahci_data[3]=__("Slumber"); + ahci_data[4]=__("Devslp"); + + /* traverse list of all devices and put their residency in the table */ + for (i = 0; i < links.size(); i++){ + links[i]->report_device_stats(ahci_data, i); + } + report.add_title(&title_attr, __("AHCI ALPM Residency Statistics")); + report.add_table(ahci_data, &std_table_css); + report.end_div(); + delete [] ahci_data; +} + +void ahci::report_device_stats(string *ahci_data, int idx) +{ + int offset=(idx*5+5); + char util[128]; + double active_util = get_result_value(active_rindex, &all_results); + double partial_util = get_result_value(partial_rindex, &all_results); + double slumber_util = get_result_value(slumber_rindex, &all_results); + double devslp_util = get_result_value(devslp_rindex, &all_results); + + snprintf(util, sizeof(util), "%5.1f", active_util); + ahci_data[offset]= util; + offset +=1; + + snprintf(util, sizeof(util), "%5.1f", partial_util); + ahci_data[offset]= util; + offset +=1; + + snprintf(util, sizeof(util), "%5.1f", slumber_util); + ahci_data[offset]= util; + offset +=1; + + snprintf(util, sizeof(util), "%5.1f", devslp_util); + ahci_data[offset]= util; +} diff --git a/src/devices/ahci.h b/src/devices/ahci.h new file mode 100644 index 0000000..7431fb5 --- /dev/null +++ b/src/devices/ahci.h @@ -0,0 +1,72 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_AHCI_H +#define _INCLUDE_GUARD_AHCI_H + + +#include <string> +#include <limits.h> +#include "device.h" +#include "../parameters/parameters.h" +#include <stdint.h> + +class ahci: public device { + uint64_t start_active, end_active; + uint64_t start_partial, end_partial; + uint64_t start_slumber, end_slumber; + uint64_t start_devslp, end_devslp; + char sysfs_path[PATH_MAX]; + char name[4096]; + int partial_rindex; + int active_rindex; + int slumber_rindex; + int devslp_rindex; + int partial_index; + int active_index; + char humanname[4096]; +public: + + ahci(char *_name, char *path); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "ahci";}; + + virtual const char * device_name(void); + virtual const char * human_name(void) { return humanname;}; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int power_valid(void) { return utilization_power_valid(partial_rindex) + utilization_power_valid(active_rindex);}; + virtual int grouping_prio(void) { return 1; }; + virtual void report_device_stats(string *ahci_data, int idx); +}; + +extern void create_all_ahcis(void); +extern void ahci_create_device_stats_table(void); + + +#endif diff --git a/src/devices/alsa.cpp b/src/devices/alsa.cpp new file mode 100644 index 0000000..7e22975 --- /dev/null +++ b/src/devices/alsa.cpp @@ -0,0 +1,207 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +using namespace std; + +#include "device.h" +#include "alsa.h" +#include "../parameters/parameters.h" + +#include "../devlist.h" + +#include <string.h> +#include <unistd.h> + +alsa::alsa(const char *_name, const char *path): device() +{ + ifstream file; + + char devname[4096]; + char model[4096]; + char vendor[4096]; + end_active = 0; + start_active = 0; + end_inactive = 0; + start_inactive = 0; + pt_strcpy(sysfs_path, path); + + snprintf(devname, sizeof(devname), "alsa:%s", _name); + snprintf(humanname, sizeof(humanname), "alsa:%s", _name); + pt_strcpy(name, devname); + rindex = get_result_index(name); + + guilty[0] = 0; + model[0] = 0; + vendor[0] = 0; + snprintf(devname, sizeof(devname), "%s/modelname", path); + file.open(devname); + if (file) { + file.getline(model, sizeof(model)); + file.close(); + } + snprintf(devname, sizeof(devname), "%s/vendor_name", path); + file.open(devname); + if (file) { + file.getline(vendor, sizeof(vendor)); + file.close(); + } + if (strlen(model) && strlen(vendor)) + snprintf(humanname, sizeof(humanname), _("Audio codec %s: %s (%s)"), name, model, vendor); + else if (strlen(model)) + snprintf(humanname, sizeof(humanname), _("Audio codec %s: %s"), _name, model); + else if (strlen(vendor)) + snprintf(humanname, sizeof(humanname), _("Audio codec %s: %s"), _name, vendor); +} + +void alsa::start_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + snprintf(filename, sizeof(filename), "%s/power_off_acct", sysfs_path); + try { + file.open(filename, ios::in); + if (file) { + file >> start_inactive; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/power_on_acct", sysfs_path); + file.open(filename, ios::in); + + if (file) { + file >> start_active; + } + file.close(); + } + catch (std::ios_base::failure &c) { + fprintf(stderr, "%s\n", c.what()); + } +} + +void alsa::end_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + double p; + + snprintf(filename, sizeof(filename), "%s/power_off_acct", sysfs_path); + try { + file.open(filename, ios::in); + if (file) { + file >> end_inactive; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/power_on_acct", sysfs_path); + file.open(filename, ios::in); + + if (file) { + file >> end_active; + } + file.close(); + } + catch (std::ios_base::failure &c) { + fprintf(stderr, "%s\n", c.what()); + } + + p = (end_active - start_active) / (0.001 + end_active + end_inactive - start_active - start_inactive) * 100.0; + report_utilization(name, p); +} + + +double alsa::utilization(void) +{ + double p; + + p = (end_active - start_active) / (0.001 + end_active - start_active + end_inactive - start_inactive) * 100.0; + + return p; +} + +const char * alsa::device_name(void) +{ + return name; +} + +static void create_all_alsa_callback(const char *d_name) +{ + char filename[PATH_MAX]; + class alsa *bl; + + if (strncmp(d_name, "hwC", 3) != 0) + return; + + snprintf(filename, sizeof(filename), "/sys/class/sound/%s/power_on_acct", d_name); + if (access(filename, R_OK) != 0) + return; + + snprintf(filename, sizeof(filename), "/sys/class/sound/%s", d_name); + bl = new class alsa(d_name, filename); + all_devices.push_back(bl); + register_parameter("alsa-codec-power", 0.5); +} + +void create_all_alsa(void) +{ + process_directory("/sys/class/sound/", create_all_alsa_callback); +} + +double alsa::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + static int index = 0; + + power = 0; + if (!index) + index = get_param_index("alsa-codec-power"); + + factor = get_parameter_value(index, bundle); + + util = get_result_value(rindex, result); + + power += util * factor / 100.0; + + return power; +} + +void alsa::register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle) +{ + register_devpower(&name[7], power_usage(results, bundle), this); +} + +const char * alsa::human_name(void) +{ + pt_strcpy(temp_buf, humanname); + if (strlen(guilty) > 0) + snprintf(temp_buf, sizeof(temp_buf), "%s (%s)", humanname, guilty); + return temp_buf; +} diff --git a/src/devices/alsa.h b/src/devices/alsa.h new file mode 100644 index 0000000..b68203f --- /dev/null +++ b/src/devices/alsa.h @@ -0,0 +1,67 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_ALSA_H +#define _INCLUDE_GUARD_ALSA_H + + +#include "device.h" +#include "../parameters/parameters.h" + +#include <stdint.h> +#include <limits.h> + +class alsa: public device { + uint64_t start_active, end_active; + uint64_t start_inactive, end_inactive; + char sysfs_path[PATH_MAX]; + char name[4096]; + char humanname[4096]; + char temp_buf[4096]; + int rindex; +public: + + alsa(const char *_name, const char *path); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "alsa";}; + + virtual const char * device_name(void); + virtual const char * human_name(void); + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int power_valid(void) { return utilization_power_valid(rindex);}; + + virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle); + virtual int grouping_prio(void) { return 0; }; + +}; + +extern void create_all_alsa(void); + + +#endif diff --git a/src/devices/backlight.cpp b/src/devices/backlight.cpp new file mode 100644 index 0000000..c73e4c9 --- /dev/null +++ b/src/devices/backlight.cpp @@ -0,0 +1,225 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <limits.h> + + +using namespace std; + +#include "device.h" +#include "backlight.h" +#include "../parameters/parameters.h" + +#include <string.h> + + +backlight::backlight(const char *_name, const char *path): device() +{ + min_level = 0; + max_level = 0; + start_level = 0; + end_level = 0; + pt_strcpy(sysfs_path, path); + register_sysfs_path(sysfs_path); + snprintf(name, sizeof(name) - 1, "backlight:%s", _name); + r_index = get_result_index(name); + r_index_power = 0; +} + +void backlight::start_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + snprintf(filename, sizeof(filename), "%s/max_brightness", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> max_level; + } + file.close(); + + snprintf(filename, sizeof(filename), "%s/actual_brightness", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> start_level; + file.close(); + } +} + +static int dpms_screen_on(void) +{ + DIR *dir; + struct dirent *entry; + char filename[PATH_MAX]; + char line[4096]; + ifstream file; + + dir = opendir("/sys/class/drm/card0"); + if (!dir) + return 1; + while (1) { + entry = readdir(dir); + if (!entry) + break; + + if (strncmp(entry->d_name, "card", 4) != 0) + continue; + snprintf(filename, sizeof(filename), "/sys/class/drm/card0/%s/enabled", entry->d_name); + file.open(filename, ios::in); + if (!file) + continue; + file.getline(line, sizeof(line)); + file.close(); + if (strcmp(line, "enabled") != 0) + continue; + snprintf(filename, sizeof(filename), "/sys/class/drm/card0/%s/dpms", entry->d_name); + file.open(filename, ios::in); + if (!file) + continue; + file.getline(line, sizeof(line)); + file.close(); + if (strcmp(line, "On") == 0) { + closedir(dir); + return 1; + } + } + closedir(dir); + return 0; +} + +void backlight::end_measurement(void) +{ + char filename[PATH_MAX]; + char powername[4096]; + ifstream file; + double p; + int _backlight = 0; + + snprintf(filename, sizeof(filename), "%s/actual_brightness", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_level; + } + file.close(); + + if (dpms_screen_on()) { + p = 100.0 * (end_level + start_level) / 2 / max_level; + _backlight = 100; + } else { + p = 0; + } + + report_utilization(name, p); + snprintf(powername, sizeof(powername), "%s-power", name); + report_utilization(powername, _backlight); +} + + +double backlight::utilization(void) +{ + double p; + + p = 100.0 * (end_level + start_level) / 2 / max_level; + return p; +} + +const char * backlight::device_name(void) +{ + return name; +} + +static void create_all_backlights_callback(const char *d_name) +{ + class backlight *bl; + char filename[PATH_MAX]; + snprintf(filename, sizeof(filename), "/sys/class/backlight/%s", d_name); + bl = new class backlight(d_name, filename); + all_devices.push_back(bl); +} + +void create_all_backlights(void) +{ + process_directory("/sys/class/backlight/", create_all_backlights_callback); + register_parameter("backlight"); + register_parameter("backlight-power"); + register_parameter("backlight-boost-40", 0, 0.5); + register_parameter("backlight-boost-80", 0, 0.5); + register_parameter("backlight-boost-100", 0, 0.5); +} + +double backlight::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double _utilization; + char powername[4096]; + static int bl_index = 0, blp_index = 0, bl_boost_index40 = 0, bl_boost_index80, bl_boost_index100; + + if (!bl_index) + bl_index = get_param_index("backlight"); + if (!blp_index) + blp_index = get_param_index("backlight-power"); + if (!bl_boost_index40) + bl_boost_index40 = get_param_index("backlight-boost-40"); + if (!bl_boost_index80) + bl_boost_index80 = get_param_index("backlight-boost-80"); + if (!bl_boost_index100) + bl_boost_index100 = get_param_index("backlight-boost-100"); + + power = 0; + factor = get_parameter_value(bl_index, bundle); + _utilization = get_result_value(r_index, result); + + power += _utilization * factor / 100.0; + + /* + * most machines have a non-linear backlight scale. to compensate, add a fixed value + * once the brightness hits 40% and 80% + */ + + if (_utilization >=99) + power += get_parameter_value(bl_boost_index100, bundle); + else if (_utilization >=80) + power += get_parameter_value(bl_boost_index80, bundle); + else if (_utilization >=40) + power += get_parameter_value(bl_boost_index40, bundle); + + factor = get_parameter_value(blp_index, bundle); + + if (!r_index_power) { + sprintf(powername, "%s-power", name); + r_index_power = get_result_index(powername); + } + _utilization = get_result_value(r_index_power, result); + + power += _utilization * factor / 100.0; + + return power; +} diff --git a/src/devices/backlight.h b/src/devices/backlight.h new file mode 100644 index 0000000..1dac778 --- /dev/null +++ b/src/devices/backlight.h @@ -0,0 +1,59 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_BACKLIGHT_H +#define _INCLUDE_GUARD_BACKLIGHT_H + +#include <limits.h> + +#include "device.h" + +class backlight: public device { + int min_level, max_level; + int start_level, end_level; + char sysfs_path[PATH_MAX]; + char name[4096]; + int r_index; + int r_index_power; +public: + + backlight(const char *_name, const char *path); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "backlight";}; + + virtual const char * device_name(void); + virtual const char * human_name(void) { return "Display backlight";}; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int grouping_prio(void) { return 10; }; +}; + +extern void create_all_backlights(void); + + +#endif diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp new file mode 100644 index 0000000..b194ac4 --- /dev/null +++ b/src/devices/devfreq.cpp @@ -0,0 +1,334 @@ +/* + * Copyright 2012, Linaro + * + * 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: + * Rajagopal Venkat <rajagopal.venkat@linaro.org> + */ + +#include <iostream> +#include <fstream> + +#include <dirent.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include "device.h" +#include "devfreq.h" +#include "../display.h" +#include "../cpu/cpu.h" +#include "../report/report.h" +#include "../report/report-maker.h" + +static bool is_enabled = true; +static DIR *dir = NULL; + +static vector<class devfreq *> all_devfreq; + +devfreq::devfreq(const char* dpath): device() +{ + pt_strcpy(dir_name, dpath); +} + +uint64_t devfreq::parse_freq_time(char* pchr) +{ + char *cptr, *pptr = pchr; + uint64_t ctime; + + cptr = strtok(pchr, " :"); + while (cptr != NULL) { + cptr = strtok(NULL, " :"); + if (cptr ) + pptr = cptr; + } + + ctime = strtoull(pptr, NULL, 10); + return ctime; +} + +void devfreq::process_time_stamps() +{ + unsigned int i; + uint64_t active_time = 0; + + sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec)) + + ((stamp_after.tv_usec - stamp_before.tv_usec) ); + + for (i=0; i < dstates.size()-1; i++) { + struct frequency *state = dstates[i]; + state->time_after = 1000 * (state->time_after - state->time_before); + active_time += state->time_after; + } + /* Compute idle time for the device */ + dstates[i]->time_after = sample_time - active_time; +} + +void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time) +{ + struct frequency *state; + + state = new(std::nothrow) struct frequency; + if (!state) + return; + + memset(state, 0, sizeof(*state)); + dstates.push_back(state); + + state->freq = freq; + if (freq == 0) + strcpy(state->human_name, "Idle"); + else + hz_to_human(freq, state->human_name); + state->time_before = time; +} + +void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time) +{ + unsigned int i; + struct frequency *state = NULL; + + for(i=0; i < dstates.size(); i++) { + if (freq == dstates[i]->freq) + state = dstates[i]; + } + + if (state == NULL) { + add_devfreq_freq_state(freq, time); + return; + } + + state->time_after = time; +} + +void devfreq::parse_devfreq_trans_stat(char *dname) +{ + ifstream file; + char filename[256]; + + snprintf(filename, sizeof(filename), "/sys/class/devfreq/%s/trans_stat", dir_name); + file.open(filename); + + if (!file) + return; + + char line[1024]; + char *c; + + while (file) { + uint64_t freq; + uint64_t time; + char *pchr; + + memset(line, 0, sizeof(line)); + file.getline(line, sizeof(line)); + + pchr = strchr(line, '*'); + pchr = (pchr != NULL) ? pchr+1 : line; + + freq = strtoull(pchr, &c, 10); + if (!freq) + continue; + + time = parse_freq_time(pchr); + update_devfreq_freq_state(freq, time); + } + file.close(); +} + +void devfreq::start_measurement(void) +{ + unsigned int i; + + for (i=0; i < dstates.size(); i++) + delete dstates[i]; + dstates.resize(0); + sample_time = 0; + + gettimeofday(&stamp_before, NULL); + parse_devfreq_trans_stat(dir_name); + /* add device idle state */ + update_devfreq_freq_state(0, 0); +} + +void devfreq::end_measurement(void) +{ + parse_devfreq_trans_stat(dir_name); + gettimeofday(&stamp_after, NULL); + process_time_stamps(); +} + +double devfreq::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + return 0; +} + +double devfreq::utilization(void) +{ + return 0; +} + +void devfreq::fill_freq_utilization(unsigned int idx, char *buf) +{ + buf[0] = 0; + + if (idx < dstates.size() && dstates[idx]) { + struct frequency *state = dstates[idx]; + sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after / sample_time)); + } +} + +void devfreq::fill_freq_name(unsigned int idx, char *buf) +{ + buf[0] = 0; + + if (idx < dstates.size() && dstates[idx]) { + sprintf(buf, "%-15s", dstates[idx]->human_name); + } +} + +void start_devfreq_measurement(void) +{ + unsigned int i; + + for (i=0; i<all_devfreq.size(); i++) + all_devfreq[i]->start_measurement(); +} + +void end_devfreq_measurement(void) +{ + unsigned int i; + + for (i=0; i<all_devfreq.size(); i++) + all_devfreq[i]->end_measurement(); +} + +static void devfreq_dev_callback(const char *d_name) +{ + devfreq *df = new(std::nothrow) class devfreq(d_name); + if (df) + all_devfreq.push_back(df); +} + +void create_all_devfreq_devices(void) +{ + int num = 0; + + std::string p = "/sys/class/devfreq/"; + dir = opendir(p.c_str()); + if (dir == NULL) { + fprintf(stderr, "Devfreq not enabled\n"); + is_enabled = false; + return; + } + + while(readdir(dir) != NULL) + num++; + + if (num == 2) { + fprintf(stderr, "Devfreq not enabled\n"); + is_enabled = false; + closedir(dir); + dir = NULL; + return; + } + + callback fn = &devfreq_dev_callback; + process_directory(p.c_str(), fn); +} + +void initialize_devfreq(void) +{ + if (is_enabled) + create_tab("Device Freq stats", _("Device Freq stats")); +} + +void display_devfreq_devices(void) +{ + unsigned int i, j; + WINDOW *win; + char fline[1024]; + char buf[128]; + + win = get_ncurses_win("Device Freq stats"); + if (!win) + return; + + wclear(win); + wmove(win, 2,0); + + if (!is_enabled) { + wprintw(win, _(" Devfreq is not enabled")); + return; + } + + if (!all_devfreq.size()) { + wprintw(win, _(" No devfreq devices available")); + return; + } + + for (i=0; i<all_devfreq.size(); i++) { + + class devfreq *df = all_devfreq[i]; + wprintw(win, "\n%s\n", df->device_name()); + + for(j=0; j < df->dstates.size(); j++) { + memset(fline, 0, sizeof(fline)); + strcpy(fline, "\t"); + df->fill_freq_name(j, buf); + strcat(fline, buf); + df->fill_freq_utilization(j, buf); + strcat(fline, buf); + strcat(fline, "\n"); + wprintw(win, "%s", fline); + } + wprintw(win, "\n"); + } +} + +void report_devfreq_devices(void) +{ + if (!is_enabled) { + return; + } + +/* todo: adapt to new report format */ + +} + +void clear_all_devfreq() +{ + unsigned int i, j; + + for (i=0; i < all_devfreq.size(); i++) { + class devfreq *df = all_devfreq[i]; + + for(j=0; j < df->dstates.size(); j++) + delete df->dstates[j]; + + delete df; + } + all_devfreq.clear(); + /* close /sys/class/devfreq */ + if (dir != NULL) { + closedir(dir); + dir = NULL; + } +} diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h new file mode 100644 index 0000000..4a8983b --- /dev/null +++ b/src/devices/devfreq.h @@ -0,0 +1,76 @@ +/* + * Copyright 2012, Linaro + * + * 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: + * Rajagopal Venkat <rajagopal.venkat@linaro.org> + */ +#ifndef _INCLUDE_GUARD_DEVFREQ_H +#define _INCLUDE_GUARD_DEVFREQ_H + +#include "device.h" +#include "../parameters/parameters.h" +#include <sys/time.h> + +struct frequency; + +class devfreq: public device { + char dir_name[128]; + struct timeval stamp_before, stamp_after; + double sample_time; + + uint64_t parse_freq_time(char *ptr); + void add_devfreq_freq_state(uint64_t freq, uint64_t time); + void update_devfreq_freq_state(uint64_t freq, uint64_t time); + void parse_devfreq_trans_stat(char *dname); + void process_time_stamps(); + +public: + + vector<struct frequency *> dstates; + + devfreq(const char *c); + void fill_freq_utilization(unsigned int idx, char *buf); + void fill_freq_name(unsigned int idx, char *buf); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "devfreq";}; + + virtual const char * device_name(void) { return dir_name;}; + virtual const char * human_name(void) { return "devfreq";}; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual const char * util_units(void) { return " rpm"; }; + virtual int power_valid(void) { return 0; /*utilization_power_valid(r_index);*/}; + virtual int grouping_prio(void) { return 1; }; +}; + +extern void create_all_devfreq_devices(void); +extern void clear_all_devfreq(void); +extern void display_devfreq_devices(void); +extern void report_devfreq_devices(void); +extern void initialize_devfreq(void); +extern void start_devfreq_measurement(void); +extern void end_devfreq_measurement(void); + +#endif diff --git a/src/devices/device.cpp b/src/devices/device.cpp new file mode 100644 index 0000000..f191072 --- /dev/null +++ b/src/devices/device.cpp @@ -0,0 +1,345 @@ +/* + * 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 "device.h" +#include <vector> +#include <algorithm> +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> + +using namespace std; + +#include "backlight.h" +#include "usb.h" +#include "ahci.h" +#include "alsa.h" +#include "rfkill.h" +#include "i915-gpu.h" +#include "thinkpad-fan.h" +#include "thinkpad-light.h" +#include "network.h" +#include "runtime_pm.h" + +#include "../parameters/parameters.h" +#include "../display.h" +#include "../lib.h" +#include "../report/report.h" +#include "../report/report-maker.h" +#include "../report/report-data-html.h" +#include "../measurement/measurement.h" +#include "../devlist.h" +#include <unistd.h> + +device::device(void) +{ + cached_valid = 0; + hide = 0; + + memset(guilty, 0, sizeof(guilty)); + memset(real_path, 0, sizeof(real_path)); +} + + +void device::register_sysfs_path(const char *path) +{ + char current_path[PATH_MAX + 1]; + int iter = 0; + pt_strcpy(current_path, path); + + while (iter++ < 10) { + char test_path[PATH_MAX + 1]; + snprintf(test_path, sizeof(test_path), "%s/device", current_path); + if (access(test_path, R_OK) == 0) + strcpy(current_path, test_path); + else + break; + } + + if (!realpath(current_path, real_path)) + real_path[0] = 0; +} + +void device::start_measurement(void) +{ + hide = false; +} + +void device::end_measurement(void) +{ +} + +double device::utilization(void) +{ + return 0.0; +} + + + +vector<class device *> all_devices; + + +void devices_start_measurement(void) +{ + unsigned int i; + for (i = 0; i < all_devices.size(); i++) + all_devices[i]->start_measurement(); +} + +void devices_end_measurement(void) +{ + unsigned int i; + for (i = 0; i < all_devices.size(); i++) + all_devices[i]->end_measurement(); + + clear_devpower(); + + for (i = 0; i < all_devices.size(); i++) { + all_devices[i]->hide = false; + all_devices[i]->register_power_with_devlist(&all_results, &all_parameters); + } +} + +static bool power_device_sort(class device * i, class device * j) +{ + double pI, pJ; + pI = i->power_usage(&all_results, &all_parameters); + pJ = j->power_usage(&all_results, &all_parameters); + + if (equals(pI, pJ)) { + int vI, vJ; + vI = i->power_valid(); + vJ = j->power_valid(); + + if (vI != vJ) + return vI > vJ; + + return i->utilization() > j->utilization(); + } + return pI > pJ; +} + + +void report_devices(void) +{ + WINDOW *win; + unsigned int i; + int show_power; + double pw; + + char util[128]; + char power[128]; + + win = get_ncurses_win("Device stats"); + if (!win) + return; + + show_power = global_power_valid(); + + wclear(win); + wmove(win, 2,0); + + sort(all_devices.begin(), all_devices.end(), power_device_sort); + + + + pw = global_power(); + if (pw > 0.0001) { + char buf[32]; + wprintw(win, _("The battery reports a discharge rate of %sW\n"), + fmt_prefix(pw, buf)); + wprintw(win, _("The energy consumed was %sJ\n"), + fmt_prefix(global_joules(), buf)); + } + + if (show_power) { + char buf[32]; + wprintw(win, _("System baseline power is estimated at %sW\n"), + fmt_prefix(get_parameter_value("base power"), buf)); + } + + if (pw > 0.0001 || show_power) + wprintw(win, "\n"); + if (show_power) + wprintw(win, _("Power est. Usage Device name\n")); + else + wprintw(win, _(" Usage Device name\n")); + + for (i = 0; i < all_devices.size(); i++) { + double P; + + util[0] = 0; + + if (all_devices[i]->util_units()) { + if (all_devices[i]->utilization() < 1000) + sprintf(util, "%5.1f%s", all_devices[i]->utilization(), all_devices[i]->util_units()); + else + sprintf(util, "%5i%s", (int)all_devices[i]->utilization(), all_devices[i]->util_units()); + } + while (strlen(util) < 13) strcat(util, " "); + + P = all_devices[i]->power_usage(&all_results, &all_parameters); + + format_watts(P, power, 11); + + if (!show_power || !all_devices[i]->power_valid()) + strcpy(power, " "); + + + wprintw(win, "%s %s %s\n", + power, + util, + all_devices[i]->human_name() + ); + } +} + +void show_report_devices(void) +{ + unsigned int i; + int show_power, cols, rows, idx; + double pw; + + show_power = global_power_valid(); + sort(all_devices.begin(), all_devices.end(), power_device_sort); + + /* div attr css_class and css_id */ + tag_attr div_attr; + init_div(&div_attr, "clear_block", "devinfo"); + + /* Set Table attributes, rows, and cols */ + table_attributes std_table_css; + cols=2; + if (show_power) + cols=3; + + idx = cols; + rows= all_devices.size() + 1; + init_std_side_table_attr(&std_table_css, rows, cols); + + /* Set Title attributes */ + tag_attr title_attr; + init_title_attr(&title_attr); + + /* Add section */ + report.add_div(&div_attr); + + /* Device Summary */ + int summary_size=2; + string *summary = new string[summary_size]; + pw = global_power(); + char buf[32]; + if (pw > 0.0001) { + summary[0]= __("The battery reports a discharge rate of: "); + summary[1]=string(fmt_prefix(pw, buf)); + summary[1].append(" W"); + report.add_summary_list(summary, summary_size); + + summary[0]= __("The energy consumed was : "); + summary[1]=string(fmt_prefix(global_joules(), buf)); + summary[1].append(" J"); + report.add_summary_list(summary, summary_size); + } + + if (show_power) { + summary[0]=__("The system baseline power is estimated at: "); + summary[1]=string(fmt_prefix(get_parameter_value("base power"), buf)); + summary[1].append(" W"); + report.add_summary_list(summary, summary_size); + } + delete [] summary; + + /* Set array of data in row Major order */ + string *device_data = new string[cols * rows]; + device_data[0]= __("Usage"); + device_data[1]= __("Device Name"); + if (show_power) + device_data[2]= __("PW Estimate"); + + for (i = 0; i < all_devices.size(); i++) { + double P; + char util[128]; + char power[128]; + + util[0] = 0; + if (all_devices[i]->util_units()) { + if (all_devices[i]->utilization() < 1000) + sprintf(util, "%5.1f%s", + all_devices[i]->utilization(), + all_devices[i]->util_units()); + else + sprintf(util, "%5i%s", + (int)all_devices[i]->utilization(), + all_devices[i]->util_units()); + } + + P = all_devices[i]->power_usage(&all_results, &all_parameters); + format_watts(P, power, 11); + + if (!show_power || !all_devices[i]->power_valid()) + strcpy(power, " "); + + device_data[idx]= string(util); + idx+=1; + + device_data[idx]= string(all_devices[i]->human_name()); + idx+=1; + + if (show_power) { + device_data[idx]= string(power); + idx+=1; + } + } + /* Report Output */ + report.add_title(&title_attr, __("Device Power Report")); + report.add_table(device_data, &std_table_css); + delete [] device_data; +} + + +void create_all_devices(void) +{ + create_all_backlights(); + create_all_usb_devices(); + create_all_ahcis(); + create_all_alsa(); + create_all_rfkills(); + create_i915_gpu(); + create_thinkpad_fan(); + create_thinkpad_light(); + create_all_nics(); + create_all_runtime_pm_devices(); +} + + +void clear_all_devices(void) +{ + unsigned int i; + for (i = 0; i < all_devices.size(); i++) { + delete all_devices[i]; + } + all_devices.clear(); +} diff --git a/src/devices/device.h b/src/devices/device.h new file mode 100644 index 0000000..a373875 --- /dev/null +++ b/src/devices/device.h @@ -0,0 +1,85 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_DEVICE_H +#define _INCLUDE_GUARD_DEVICE_H + + +#include <vector> +#include <limits.h> + +struct parameter_bundle; +struct result_bundle; + +class device { +public: + int cached_valid; + bool hide; + + char guilty[4096]; + char real_path[PATH_MAX+1]; + + virtual void start_measurement(void); + virtual void end_measurement(void); + + device(void); + + virtual ~device() {}; + + void register_sysfs_path(const char *path); + + virtual double utilization(void); /* percentage */ + + virtual const char * util_units(void) { return "%"; }; + + virtual const char * class_name(void) { return "abstract device";}; + virtual const char * device_name(void) { return "abstract device";}; + + virtual const char * human_name(void) { return device_name(); }; + + virtual double power_usage(struct result_bundle *results, struct parameter_bundle *bundle) { return 0.0; }; + + virtual bool show_in_list(void) {return !hide;}; + + virtual int power_valid(void) { return 1;}; + + virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle) { ; }; + + virtual int grouping_prio(void) { return 0; }; /* priority of this device class if multiple classes match to the same underlying device. 0 is lowest */ +}; + +using namespace std; + +extern vector<class device *> all_devices; + +extern void devices_start_measurement(void); +extern void devices_end_measurement(void); +extern void show_report_devices(void); +extern void report_devices(void); + + +extern void create_all_devices(void); +extern void clear_all_devices(void); + +#endif diff --git a/src/devices/gpu_rapl_device.cpp b/src/devices/gpu_rapl_device.cpp new file mode 100644 index 0000000..71d71a0 --- /dev/null +++ b/src/devices/gpu_rapl_device.cpp @@ -0,0 +1,70 @@ +/* + * 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: + * Srinivas Pandruvada<Srinivas.Pandruvada@linux.intel.com> + */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "../parameters/parameters.h" +#include "gpu_rapl_device.h" + +gpu_rapl_device::gpu_rapl_device(i915gpu *parent) + : i915gpu(), + device_valid(false) +{ + last_time = time(NULL); + if (rapl.pp1_domain_present()) { + device_valid = true; + parent->add_child(this); + rapl.get_pp1_energy_status(&last_energy); + } +} + +void gpu_rapl_device::start_measurement(void) +{ + last_time = time(NULL); + + rapl.get_pp1_energy_status(&last_energy); +} + +void gpu_rapl_device::end_measurement(void) +{ + time_t curr_time = time(NULL); + double energy; + + consumed_power = 0.0; + if ((curr_time - last_time) > 0) { + rapl.get_pp1_energy_status(&energy); + consumed_power = (energy-last_energy)/(curr_time-last_time); + last_energy = energy; + last_time = curr_time; + } +} + +double gpu_rapl_device::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + if (rapl.pp1_domain_present()) + return consumed_power; + else + return 0.0; +} diff --git a/src/devices/gpu_rapl_device.h b/src/devices/gpu_rapl_device.h new file mode 100644 index 0000000..fbde246 --- /dev/null +++ b/src/devices/gpu_rapl_device.h @@ -0,0 +1,57 @@ +/* + * 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: + * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com> + */ +#ifndef _INCLUDE_GUARD_GPU_RAPL_DEVICE_H +#define _INCLUDE_GUARD_GPU_RAPL_DEVICE_H + +#include <vector> +#include <string> + +using namespace std; + +#include <sys/time.h> +#include "i915-gpu.h" +#include "cpu/rapl/rapl_interface.h" + +class gpu_rapl_device: public i915gpu { + + c_rapl_interface rapl; + time_t last_time; + double last_energy; + double consumed_power; + bool device_valid; + +public: + gpu_rapl_device(i915gpu *parent); + virtual const char * class_name(void) { return "GPU core";}; + virtual const char * device_name(void) { return "GPU core";}; + bool device_present() { return device_valid;} + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual void start_measurement(void); + virtual void end_measurement(void); + +}; + + +#endif diff --git a/src/devices/i915-gpu.cpp b/src/devices/i915-gpu.cpp new file mode 100644 index 0000000..d0f1d69 --- /dev/null +++ b/src/devices/i915-gpu.cpp @@ -0,0 +1,121 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <limits.h> +#include "../lib.h" + +using namespace std; + +#include "device.h" +#include "i915-gpu.h" +#include "../parameters/parameters.h" +#include "../process/powerconsumer.h" +#include "gpu_rapl_device.h" + +#include <string.h> +#include <unistd.h> + +i915gpu::i915gpu(): device() +{ + index = get_param_index("gpu-operations"); + rindex = get_result_index("gpu-operations"); +} + +const char * i915gpu::device_name(void) +{ + if (child_devices.size()) + return "GPU misc"; + else + return "GPU"; +} + +void i915gpu::start_measurement(void) +{ +} + +void i915gpu::end_measurement(void) +{ +} + + +double i915gpu::utilization(void) +{ + return get_result_value(rindex); + +} + +void create_i915_gpu(void) +{ + char filename[PATH_MAX]; + class i915gpu *gpu; + gpu_rapl_device *rapl_dev; + + pt_strcpy(filename, "/sys/kernel/debug/tracing/events/i915/i915_gem_ring_dispatch/format"); + + if (access(filename, R_OK) !=0) { + /* try an older tracepoint */ + pt_strcpy(filename, "/sys/kernel/debug/tracing/events/i915/i915_gem_request_submit/format"); + if (access(filename, R_OK) != 0) + return; + } + + register_parameter("gpu-operations"); + + gpu = new class i915gpu(); + all_devices.push_back(gpu); + + rapl_dev = new class gpu_rapl_device(gpu); + if (rapl_dev->device_present()) + all_devices.push_back(rapl_dev); +} + + + +double i915gpu::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + double child_power; + + power = 0; + factor = get_parameter_value(index, bundle); + util = get_result_value(rindex, result); + + power += util * factor / 100.0; + for (unsigned int i = 0; i < child_devices.size(); ++i) { + child_power = child_devices[i]->power_usage(result, bundle); + if ((power - child_power) > 0.0) + power -= child_power; + } + + return power; +} diff --git a/src/devices/i915-gpu.h b/src/devices/i915-gpu.h new file mode 100644 index 0000000..7653b94 --- /dev/null +++ b/src/devices/i915-gpu.h @@ -0,0 +1,58 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_i915_GPU_H +#define _INCLUDE_GUARD_i915_GPU_H + + +#include "device.h" + +class i915gpu: public device { + int index; + int rindex; + vector<device *>child_devices; + +public: + + i915gpu(); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "GPU";}; + + virtual const char * device_name(void); + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual bool show_in_list(void) {return false;}; + virtual const char * util_units(void) { return " ops/s"; }; + + virtual void add_child(device *dev_ptr) { child_devices.push_back(dev_ptr);} +}; + +extern void create_i915_gpu(void); + + +#endif
\ No newline at end of file diff --git a/src/devices/network.cpp b/src/devices/network.cpp new file mode 100644 index 0000000..8087b7f --- /dev/null +++ b/src/devices/network.cpp @@ -0,0 +1,441 @@ +/* + * 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 <vector> +#include <string> +#include <map> + +#include <stdio.h> +#include <sys/types.h> +#include <libgen.h> +#include <stdlib.h> +#include <unistd.h> + +#include <linux/ethtool.h> + +using namespace std; + +#include "device.h" +#include "network.h" +#include "../lib.h" +#include "../parameters/parameters.h" +#include "../process/process.h" +extern "C" { +#include "../tuning/iw.h" +} + +#include <string.h> +#include <net/if.h> +#include <linux/sockios.h> +#include <sys/ioctl.h> +#include <unistd.h> + +static map<string, class network *> nics; + +#ifdef DISABLE_TRYCATCH + +static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, + __u32 speed) +{ + + ep->speed = (__u16)speed; + ep->speed_hi = (__u16)(speed >> 16); +} + +static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep) +{ + return (ep->speed_hi << 16) | ep->speed; +} + +#endif + +static void do_proc_net_dev(void) +{ + static time_t last_time; + class network *dev; + ifstream file; + char line[4096]; + char *c, *c2; + + if (time(NULL) == last_time) + return; + + last_time = time(NULL); + + file.open("/proc/net/dev", ios::in); + if (!file) + return; + + file.getline(line, 4096); + file.getline(line, 4096); + + while (file) { + int i = 0; + unsigned long val = 0; + uint64_t pkt = 0; + file.getline(line, 4096); + c = strchr(line, ':'); + if (!c) + continue; + *c = 0; + c2 = c +1; + c = line; while (c && *c == ' ') c++; + /* c now points to the name of the nic */ + + dev = nics[c]; + if (!dev) + continue; + + c = c2++; + while (c != c2 && strlen(c) > 0) { + c2 = c; + val = strtoull(c, &c, 10); + i++; + if (i == 2 || i == 10) + pkt += val; + + } + dev->pkts = pkt; + } + file.close(); +} + + +network::network(const char *_name, const char *path): device() +{ + char line[4096]; + std::string filename(path); + char devname[128]; + start_up = 0; + end_up = 0; + start_speed = 0; + end_speed = 0; + start_pkts = 0; + end_pkts = 0; + pkts = 0; + valid_100 = -1; + valid_1000 = -1; + valid_high = -1; + valid_powerunsave = -1; + + pt_strcpy(sysfs_path, path); + register_sysfs_path(sysfs_path); + pt_strcpy(devname, _name); + sprintf(humanname, "nic:%s", _name); + pt_strcpy(name, devname); + + snprintf(devname, sizeof(devname), "%s-up", _name); + index_up = get_param_index(devname); + rindex_up = get_result_index(devname); + + snprintf(devname, sizeof(devname), "%s-powerunsave", _name); + index_powerunsave = get_param_index(devname); + rindex_powerunsave = get_result_index(devname); + + snprintf(devname, sizeof(devname), "%s-link-100", _name); + index_link_100 = get_param_index(devname); + rindex_link_100 = get_result_index(devname); + + snprintf(devname, sizeof(devname), "%s-link-1000", _name); + index_link_1000 = get_param_index(devname); + rindex_link_1000 = get_result_index(devname); + + snprintf(devname, sizeof(devname), "%s-link-high", _name); + index_link_high = get_param_index(devname); + rindex_link_high = get_result_index(devname); + + snprintf(devname, sizeof(devname), "%s-packets", _name); + index_pkts = get_param_index(devname); + rindex_pkts = get_result_index(devname); + + memset(line, 0, 4096); + filename.append("/device/driver"); + if (readlink(filename.c_str(), line, 4096) > 0) { + snprintf(humanname, sizeof(humanname), _("Network interface: %s (%s)"), _name, basename(line)); + }; +} + +static int net_iface_up(const char *iface) +{ + int sock; + struct ifreq ifr; + int ret; + + memset(&ifr, 0, sizeof(struct ifreq)); + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock<0) + return 0; + + pt_strcpy(ifr.ifr_name, iface); + + /* Check if the interface is up */ + ret = ioctl(sock, SIOCGIFFLAGS, &ifr); + if (ret<0) { + close(sock); + return 0; + } + + if (ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) { + close(sock); + return 1; + } + + close(sock); + + return 0; +} + +static int iface_link(const char *name) +{ + int sock; + struct ifreq ifr; + struct ethtool_value cmd; + int link; + + memset(&ifr, 0, sizeof(struct ifreq)); + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock<0) + return 0; + + pt_strcpy(ifr.ifr_name, name); + + memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (caddr_t)&cmd; + ioctl(sock, SIOCETHTOOL, &ifr); + close(sock); + + link = cmd.data; + + return link; +} + + +static int iface_speed(const char *name) +{ + int sock; + struct ifreq ifr; + struct ethtool_cmd cmd; + int speed; + + memset(&ifr, 0, sizeof(struct ifreq)); + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock<0) + return 0; + + pt_strcpy(ifr.ifr_name, name); + + memset(&cmd, 0, sizeof(cmd)); + + cmd.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t)&cmd; + ioctl(sock, SIOCETHTOOL, &ifr); + close(sock); + + speed = ethtool_cmd_speed(&cmd); + + + if (speed > 0 && speed <= 100) + speed = 100; + if (speed > 100 && speed <= 1000) + speed = 1000; + if (speed == 65535 || !iface_link(name)) + speed = 0; /* no link */ + + return speed; +} + +void network::start_measurement(void) +{ + start_up = 1; + start_speed = 0; + end_up = 1; + end_speed = 0; + + start_speed = iface_speed(name); + + start_up = net_iface_up(name); + + do_proc_net_dev(); + start_pkts = pkts; + + gettimeofday(&before, NULL); +} + + +void network::end_measurement(void) +{ + int u_100, u_1000, u_high, u_powerunsave; + + gettimeofday(&after, NULL); + + end_speed = iface_speed(name); + end_up = net_iface_up(name); + do_proc_net_dev(); + end_pkts = pkts; + + duration = (after.tv_sec - before.tv_sec) + (after.tv_usec - before.tv_usec) / 1000000.0; + + u_100 = 0; + u_1000 = 0; + u_high = 0; + + if (start_speed == 100) + u_100 += 50; + if (start_speed == 1000) + u_1000 += 50; + if (start_speed > 1000) + u_high += 50; + if (end_speed == 100) + u_100 += 50; + if (end_speed == 1000) + u_1000 += 50; + if (end_speed > 1000) + u_high += 50; + + if (start_pkts > end_pkts) + end_pkts = start_pkts; + + u_powerunsave = 100 - 100 * get_wifi_power_saving(name); + + report_utilization(rindex_link_100, u_100); + report_utilization(rindex_link_1000, u_1000); + report_utilization(rindex_link_high, u_high); + report_utilization(rindex_up, (start_up+end_up) / 2.0); + report_utilization(rindex_pkts, (end_pkts - start_pkts)/(duration + 0.001)); + report_utilization(rindex_powerunsave, u_powerunsave); +} + + +double network::utilization(void) +{ + return (end_pkts - start_pkts) / (duration + 0.001); +} + +const char * network::device_name(void) +{ + return name; +} + +static void netdev_callback(const char *d_name) +{ + char devname[128]; + + std::string f_name("/sys/class/net/"); + if (strcmp(d_name, "lo") == 0) + return; + + f_name.append(d_name); + + snprintf(devname, sizeof(devname), "%s-up", d_name); + register_parameter(devname); + + snprintf(devname, sizeof(devname), "%s-powerunsave", d_name); + register_parameter(devname); + + snprintf(devname, sizeof(devname), "%s-link-100", d_name); + register_parameter(devname); + + snprintf(devname, sizeof(devname), "%s-link-1000", d_name); + register_parameter(devname); + + snprintf(devname, sizeof(devname), "%s-link-high", d_name); + register_parameter(devname); + + snprintf(devname, sizeof(devname), "%s-packets", d_name); + register_parameter(devname); + + network *bl = new(std::nothrow) class network(d_name, f_name.c_str()); + if (bl) { + all_devices.push_back(bl); + nics[d_name] = bl; + } +} + +void create_all_nics(callback fn) +{ + if (!fn) + fn = &netdev_callback; + process_directory("/sys/class/net/", fn); +} + +double network::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + power = 0; + factor = get_parameter_value(index_up, bundle); + util = get_result_value(rindex_up, result); + + power += util * factor; + + if (valid_100 == -1) { + valid_100 = utilization_power_valid(rindex_link_100); + valid_1000 = utilization_power_valid(rindex_link_1000); + valid_high = utilization_power_valid(rindex_link_high); + valid_powerunsave = utilization_power_valid(rindex_powerunsave); + } + + if (valid_100 > 0) { + factor = get_parameter_value(index_link_100, bundle); + util = get_result_value(rindex_link_100, result); + power += util * factor / 100; + } + + + if (valid_1000 > 0) { + factor = get_parameter_value(index_link_1000, bundle); + util = get_result_value(rindex_link_1000, result); + power += util * factor / 100; + } + + if (valid_high > 0) { + factor = get_parameter_value(index_link_high, bundle); + util = get_result_value(rindex_link_high, result); + power += util * factor / 100; + } + + if (valid_powerunsave > 0) { + factor = get_parameter_value(index_powerunsave, bundle); + util = get_result_value(rindex_powerunsave, result); + power += util * factor / 100; + } + + factor = get_parameter_value(index_pkts, bundle); + util = get_result_value(rindex_pkts, result); + if (util > 5000) + util = 5000; + + power += util * factor / 100; + + return power; +} diff --git a/src/devices/network.h b/src/devices/network.h new file mode 100644 index 0000000..7fb4cc6 --- /dev/null +++ b/src/devices/network.h @@ -0,0 +1,85 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_NETWORK_H +#define _INCLUDE_GUARD_NETWORK_H + +#include <sys/time.h> +#include <limits.h> + +#include "device.h" +#include "../parameters/parameters.h" + +class network: public device { + int start_up, end_up; + uint64_t start_pkts, end_pkts; + struct timeval before, after; + + int start_speed; /* 0 is "no link" */ + int end_speed; /* 0 is "no link" */ + + char sysfs_path[PATH_MAX]; + char name[4096]; + char humanname[4096]; + int index_up; + int rindex_up; + int index_link_100; + int rindex_link_100; + int index_link_1000; + int rindex_link_1000; + int index_link_high; + int rindex_link_high; + int index_pkts; + int rindex_pkts; + int index_powerunsave; + int rindex_powerunsave; + + int valid_100; + int valid_1000; + int valid_high; + int valid_powerunsave; +public: + uint64_t pkts; + double duration; + + network(const char *_name, const char *path); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); + virtual const char * util_units(void) { return " pkts/s"; }; + + virtual const char * class_name(void) { return "ethernet";}; + + virtual const char * device_name(void); + virtual const char * human_name(void) { return humanname; }; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int power_valid(void) { return utilization_power_valid(rindex_up) + utilization_power_valid(rindex_link_100) + utilization_power_valid(rindex_link_1000) + utilization_power_valid(rindex_link_high);}; + virtual int grouping_prio(void) { return 10; }; +}; + +extern void create_all_nics(callback fn = NULL); + +#endif diff --git a/src/devices/rfkill.cpp b/src/devices/rfkill.cpp new file mode 100644 index 0000000..99a652f --- /dev/null +++ b/src/devices/rfkill.cpp @@ -0,0 +1,177 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <libgen.h> +#include <unistd.h> +#include <limits.h> + + +using namespace std; + +#include "device.h" +#include "rfkill.h" +#include "../parameters/parameters.h" + +#include <string.h> +#include <unistd.h> + +rfkill::rfkill(char *_name, char *path): device() +{ + char line[4096]; + char filename[PATH_MAX]; + char devname[128]; + start_soft = 0; + start_hard = 0; + end_soft = 0; + end_hard = 0; + pt_strcpy(sysfs_path, path); + register_sysfs_path(sysfs_path); + snprintf(devname, sizeof(devname), "radio:%s", _name); + snprintf(humanname, sizeof(humanname), "radio:%s", _name); + pt_strcpy(name, devname); + register_parameter(devname); + index = get_param_index(devname); + rindex = get_result_index(name); + + memset(line, 0, 4096); + snprintf(filename, sizeof(filename), "%s/device/driver", path); + if (readlink(filename, line, sizeof(line)) > 0) { + snprintf(humanname, sizeof(humanname), _("Radio device: %s"), basename(line)); + } + snprintf(filename, sizeof(filename), "%s/device/device/driver", path); + if (readlink(filename, line, sizeof(line)) > 0) { + snprintf(humanname, sizeof(humanname), _("Radio device: %s"), basename(line)); + } +} + +void rfkill::start_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + start_hard = 1; + start_soft = 1; + end_hard = 1; + end_soft = 1; + + snprintf(filename, sizeof(filename), "%s/hard", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> start_hard; + } + file.close(); + + snprintf(filename, sizeof(filename), "%s/soft", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> start_soft; + } + file.close(); +} + +void rfkill::end_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + snprintf(filename, sizeof(filename), "%s/hard", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_hard; + } + file.close(); + snprintf(filename, sizeof(filename), "%s/soft", sysfs_path); + file.open(filename, ios::in); + if (file) { + file >> end_soft; + } + file.close(); + + report_utilization(name, utilization()); +} + + +double rfkill::utilization(void) +{ + double p; + int rfk; + + rfk = start_soft+end_soft; + if (rfk < start_hard+end_hard) + rfk = start_hard+end_hard; + + p = 100 - 50.0 * rfk; + + return p; +} + +const char * rfkill::device_name(void) +{ + return name; +} + +static void create_all_rfkills_callback(const char *d_name) +{ + char filename[PATH_MAX]; + char name[4096] = {0}; + class rfkill *bl; + ifstream file; + + snprintf(filename, sizeof(filename), "/sys/class/rfkill/%s/name", d_name); + strncpy(name, d_name, sizeof(name) - 1); + file.open(filename, ios::in); + if (file) { + file.getline(name, 100); + file.close(); + } + + snprintf(filename, sizeof(filename), "/sys/class/rfkill/%s", d_name); + bl = new class rfkill(name, filename); + all_devices.push_back(bl); +} + +void create_all_rfkills(void) +{ + process_directory("/sys/class/rfkill/", create_all_rfkills_callback); +} + +double rfkill::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + power = 0; + factor = get_parameter_value(index, bundle); + util = get_result_value(rindex, result); + + power += util * factor / 100.0; + + return power; +} diff --git a/src/devices/rfkill.h b/src/devices/rfkill.h new file mode 100644 index 0000000..429ba18 --- /dev/null +++ b/src/devices/rfkill.h @@ -0,0 +1,62 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_RFKILL_H +#define _INCLUDE_GUARD_RFKILL_H + +#include <limits.h> + +#include "device.h" +#include "../parameters/parameters.h" + +class rfkill: public device { + int start_soft, end_soft; + int start_hard, end_hard; + char sysfs_path[PATH_MAX]; + char name[4096]; + char humanname[4096]; + int index; + int rindex; +public: + + rfkill(char *_name, char *path); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "radio";}; + + virtual const char * device_name(void); + virtual const char * human_name(void) { return humanname; }; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int power_valid(void) { return utilization_power_valid(rindex);}; + virtual int grouping_prio(void) { return 5; }; +}; + +extern void create_all_rfkills(void); + + +#endif
\ No newline at end of file diff --git a/src/devices/runtime_pm.cpp b/src/devices/runtime_pm.cpp new file mode 100644 index 0000000..26f9d32 --- /dev/null +++ b/src/devices/runtime_pm.cpp @@ -0,0 +1,257 @@ +/* + * 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 "runtime_pm.h" + +#include <string.h> + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <limits.h> + +#include "../parameters/parameters.h" +#include "../lib.h" + +#include <iostream> +#include <fstream> + +runtime_pmdevice::runtime_pmdevice(const char *_name, const char *path) : device() +{ + pt_strcpy(sysfs_path, path); + register_sysfs_path(sysfs_path); + pt_strcpy(name, _name); + snprintf(humanname, sizeof(humanname), "runtime-%s", _name); + + index = get_param_index(humanname); + r_index = get_result_index(humanname); + + before_suspended_time = 0; + before_active_time = 0; + after_suspended_time = 0; + after_active_time = 0; + + register_parameter(humanname); +} + +void runtime_pmdevice::start_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + before_suspended_time = 0; + before_active_time = 0; + after_suspended_time = 0; + after_active_time = 0; + + snprintf(filename, sizeof(filename), "%s/power/runtime_suspended_time", sysfs_path); + file.open(filename, ios::in); + if (!file) + return; + file >> before_suspended_time; + file.close(); + + snprintf(filename, sizeof(filename), "%s/power/runtime_active_time", sysfs_path); + file.open(filename, ios::in); + if (!file) + return; + file >> before_active_time; + file.close(); +} + +void runtime_pmdevice::end_measurement(void) +{ + char filename[PATH_MAX]; + ifstream file; + + snprintf(filename, sizeof(filename), "%s/power/runtime_suspended_time", sysfs_path); + file.open(filename, ios::in); + if (!file) + return; + file >> after_suspended_time; + file.close(); + + snprintf(filename, sizeof(filename), "%s/power/runtime_active_time", sysfs_path); + file.open(filename, ios::in); + if (!file) + return; + file >> after_active_time; + file.close(); +} + +double runtime_pmdevice::utilization(void) /* percentage */ +{ + double d; + d = 100 * (after_active_time - before_active_time) / (0.0001 + after_active_time - before_active_time + after_suspended_time - before_suspended_time); + + if (d < 0.00) + d = 0.0; + if (d > 99.9) + d = 100.0; + return d; +} + +const char * runtime_pmdevice::device_name(void) +{ + return name; +} + +const char * runtime_pmdevice::human_name(void) +{ + return humanname; +} + + +double runtime_pmdevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + power = 0; + + factor = get_parameter_value(index, bundle); + util = get_result_value(r_index, result); + power += util * factor / 100.0; + + return power; +} + +void runtime_pmdevice::set_human_name(char *_name) +{ + pt_strcpy(humanname, _name); +} + + +int device_has_runtime_pm(const char *sysfs_path) +{ + char filename[PATH_MAX]; + ifstream file; + unsigned long value; + + snprintf(filename, sizeof(filename), "%s/power/runtime_suspended_time", sysfs_path); + file.open(filename, ios::in); + if (!file) + return 0; + file >> value; + file.close(); + if (value) + return 1; + + snprintf(filename, sizeof(filename), "%s/power/runtime_active_time", sysfs_path); + file.open(filename, ios::in); + if (!file) + return 0; + file >> value; + file.close(); + if (value) + return 1; + + return 0; +} + +static void do_bus(const char *bus) +{ + /* /sys/bus/pci/devices/0000\:00\:1f.0/power/runtime_suspended_time */ + + struct dirent *entry; + DIR *dir; + char filename[PATH_MAX]; + + snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/", bus); + dir = opendir(filename); + if (!dir) + return; + while (1) { + ifstream file; + class runtime_pmdevice *dev; + entry = readdir(dir); + + if (!entry) + break; + if (entry->d_name[0] == '.') + continue; + + snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s", bus, entry->d_name); + dev = new class runtime_pmdevice(entry->d_name, filename); + + if (strcmp(bus, "i2c") == 0) { + string devname; + char dev_name[4096]; + bool is_adapter = false; + + snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/new_device", bus, entry->d_name); + if (access(filename, W_OK) == 0) + is_adapter = true; + + snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/name", bus, entry->d_name); + file.open(filename, ios::in); + if (file) { + getline(file, devname); + file.close(); + } + + snprintf(dev_name, sizeof(dev_name), _("I2C %s (%s): %s"), (is_adapter ? _("Adapter") : _("Device")), entry->d_name, devname.c_str()); + dev->set_human_name(dev_name); + } + + if (strcmp(bus, "pci") == 0) { + uint16_t vendor = 0, device = 0; + + snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/vendor", bus, entry->d_name); + + file.open(filename, ios::in); + if (file) { + file >> hex >> vendor; + file.close(); + } + + + snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/device", bus, entry->d_name); + file.open(filename, ios::in); + if (file) { + file >> hex >> device; + file.close(); + } + + if (vendor && device) { + char devname[4096]; + snprintf(devname, sizeof(devname), _("PCI Device: %s"), + pci_id_to_name(vendor, device, filename, 4095)); + dev->set_human_name(devname); + } + } + all_devices.push_back(dev); + } + closedir(dir); +} + +void create_all_runtime_pm_devices(void) +{ + do_bus("pci"); + do_bus("spi"); + do_bus("platform"); + do_bus("i2c"); +} diff --git a/src/devices/runtime_pm.h b/src/devices/runtime_pm.h new file mode 100644 index 0000000..77bf398 --- /dev/null +++ b/src/devices/runtime_pm.h @@ -0,0 +1,66 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_RUNTIMEPM_H +#define _INCLUDE_GUARD_RUNTIMEPM_H + +#include <limits.h> + +#include "device.h" +#include "../parameters/parameters.h" + +class runtime_pmdevice: public device { + uint64_t before_suspended_time, before_active_time; + uint64_t after_suspended_time, after_active_time; + char sysfs_path[PATH_MAX]; + char name[4096]; + char humanname[4096]; + int index; + int r_index; +public: + + runtime_pmdevice(const char *_name, const char *path); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "runtime_pm";}; + + virtual const char * device_name(void); + virtual const char * human_name(void); + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int power_valid(void) { return utilization_power_valid(r_index);}; + + void set_human_name(char *name); + virtual int grouping_prio(void) { return 1; }; +}; + +extern void create_all_runtime_pm_devices(void); + +extern int device_has_runtime_pm(const char *sysfs_path); + + +#endif
\ No newline at end of file diff --git a/src/devices/thinkpad-fan.cpp b/src/devices/thinkpad-fan.cpp new file mode 100644 index 0000000..8e2ce53 --- /dev/null +++ b/src/devices/thinkpad-fan.cpp @@ -0,0 +1,124 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <math.h> +#include <unistd.h> +#include <limits.h> + +#include "../lib.h" + + +#include "device.h" +#include "thinkpad-fan.h" +#include "../parameters/parameters.h" +#include "../process/powerconsumer.h" + +#include <string.h> +#include <unistd.h> + +thinkpad_fan::thinkpad_fan(): device() +{ + start_rate = 0; + end_rate = 0; + fan_index = get_param_index("thinkpad-fan"); + fansqr_index = get_param_index("thinkpad-fan-sqr"); + fancub_index = get_param_index("thinkpad-fan-cub"); + r_index = get_result_index("thinkpad-fan"); + register_sysfs_path("/sys/devices/platform/thinkpad_hwmon"); +} + +void thinkpad_fan::start_measurement(void) +{ + /* read the rpms of the fan */ + start_rate = read_sysfs("/sys/devices/platform/thinkpad_hwmon/fan1_input"); +} + +void thinkpad_fan::end_measurement(void) +{ + end_rate = read_sysfs("/sys/devices/platform/thinkpad_hwmon/fan1_input"); + + report_utilization("thinkpad-fan", utilization()); +} + + +double thinkpad_fan::utilization(void) +{ + return (start_rate+end_rate) / 2; +} + +void create_thinkpad_fan(void) +{ + char filename[PATH_MAX]; + class thinkpad_fan *fan; + + pt_strcpy(filename, "/sys/devices/platform/thinkpad_hwmon/fan1_input"); + + if (access(filename, R_OK) !=0) + return; + + register_parameter("thinkpad-fan", 10); + register_parameter("thinkpad-fan-sqr", 5); + register_parameter("thinkpad-fan-cub", 10); + + fan = new class thinkpad_fan(); + all_devices.push_back(fan); +} + + + +double thinkpad_fan::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + + power = 0; + util = get_result_value(r_index, result); + + if (util < 0) + util = 0; + + + /* physics dictact that fan power goes cubic with the rpms, but there's also a linear component for friction*/ + factor = get_parameter_value(fancub_index, bundle); + power += factor * pow(util / 3600.0, 3); + + factor = get_parameter_value(fansqr_index, bundle) - 5.0; + power += factor * pow(util / 3600.0, 2); + + factor = get_parameter_value(fan_index, bundle) - 10.0; + power += util / 5000.0 * factor; + + if (power <= 0.0) + power = 0.0; + + return power; +} diff --git a/src/devices/thinkpad-fan.h b/src/devices/thinkpad-fan.h new file mode 100644 index 0000000..34c4c43 --- /dev/null +++ b/src/devices/thinkpad-fan.h @@ -0,0 +1,58 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_THINKPAD_FAN_H +#define _INCLUDE_GUARD_THINKPAD_FAN_H + + +#include "device.h" +#include "../parameters/parameters.h" + +class thinkpad_fan: public device { + double start_rate, end_rate; + int fan_index, fansqr_index, fancub_index; + int r_index; +public: + + thinkpad_fan(); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "fan";}; + + virtual const char * device_name(void) { return "Fan-1";}; + virtual const char * human_name(void) { return "Laptop fan";}; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual const char * util_units(void) { return " rpm"; }; + virtual int power_valid(void) { return utilization_power_valid(r_index);}; + virtual int grouping_prio(void) { return 1; }; +}; + +extern void create_thinkpad_fan(void); + + +#endif
\ No newline at end of file diff --git a/src/devices/thinkpad-light.cpp b/src/devices/thinkpad-light.cpp new file mode 100644 index 0000000..d047ab3 --- /dev/null +++ b/src/devices/thinkpad-light.cpp @@ -0,0 +1,113 @@ +/* + * 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 <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <math.h> +#include <unistd.h> +#include <limits.h> + +#include "../lib.h" + + +#include "device.h" +#include "thinkpad-light.h" +#include "../parameters/parameters.h" +#include "../process/powerconsumer.h" + +#include <string.h> +#include <unistd.h> + +thinkpad_light::thinkpad_light(): device() +{ + start_rate = 0; + end_rate = 0; + light_index = get_param_index("thinkpad-light"); + r_index = get_result_index("thinkpad-light"); + register_sysfs_path("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight"); +} + +void thinkpad_light::start_measurement(void) +{ + /* read the rpms of the light */ + start_rate = read_sysfs("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness"); +} + +void thinkpad_light::end_measurement(void) +{ + end_rate = read_sysfs("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness"); + + report_utilization("thinkpad-light", utilization()); +} + + +double thinkpad_light::utilization(void) +{ + return (start_rate+end_rate) / 2.55 / 2.0; +} + +void create_thinkpad_light(void) +{ + char filename[PATH_MAX]; + class thinkpad_light *light; + + pt_strcpy(filename, "/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness"); + + if (access(filename, R_OK) !=0) + return; + + register_parameter("thinkpad-light", 10); + + light = new class thinkpad_light(); + all_devices.push_back(light); +} + + + +double thinkpad_light::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + + power = 0; + util = get_result_value(r_index, result); + + if (util < 0) + util = 0; + + + factor = get_parameter_value(light_index, bundle) - 10.0; + power += util / 100.0 * factor; + + if (power <= 0.0) + power = 0.0; + + return power; +} diff --git a/src/devices/thinkpad-light.h b/src/devices/thinkpad-light.h new file mode 100644 index 0000000..64a1789 --- /dev/null +++ b/src/devices/thinkpad-light.h @@ -0,0 +1,58 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_THINKPAD_LIGHT_H +#define _INCLUDE_GUARD_THINKPAD_LIGHT_H + + +#include "device.h" +#include "../parameters/parameters.h" + +class thinkpad_light: public device { + double start_rate, end_rate; + int light_index; + int r_index; +public: + + thinkpad_light(); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "light";}; + + virtual const char * device_name(void) { return "Light-1";}; + virtual const char * human_name(void) { return "Thinkpad light";}; + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual const char * util_units(void) { return "%"; }; + virtual int power_valid(void) { return utilization_power_valid(r_index);}; + virtual int grouping_prio(void) { return 1; }; +}; + +extern void create_thinkpad_light(void); + + +#endif
\ No newline at end of file diff --git a/src/devices/usb.cpp b/src/devices/usb.cpp new file mode 100644 index 0000000..5042699 --- /dev/null +++ b/src/devices/usb.cpp @@ -0,0 +1,254 @@ +/* + * 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 "usb.h" + +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <limits.h> + +#include "../lib.h" +#include "../devlist.h" +#include "../parameters/parameters.h" + +#include <iostream> +#include <fstream> + +usbdevice::usbdevice(const char *_name, const char *path, const char *devid): device() +{ + ifstream file; + char filename[PATH_MAX]; + char vendor[4096]; + char product[4096]; + + pt_strcpy(sysfs_path, path); + register_sysfs_path(sysfs_path); + pt_strcpy(name, _name); + pt_strcpy(devname, devid); + snprintf(humanname, sizeof(humanname), _("USB device: %s"), pretty_print(devid, vendor, 4096)); + active_before = 0; + active_after = 0; + connected_before = 0; + connected_after = 0; + busnum = 0; + devnum = 0; + + index = get_param_index(devname); + r_index = get_result_index(name); + rootport = 0; + cached_valid = 0; + + + /* root ports and hubs should count as 0 power ... their activity is derived */ + snprintf(filename, sizeof(filename), "%s/bDeviceClass", path); + file.open(filename, ios::in); + if (file) { + int dclass = 0; + + file >> dclass; + file.close(); + if (dclass == 9) + rootport = 1; + }; + + vendor[0] = 0; + product[0] = 0; + snprintf(filename, sizeof(filename), "%s/manufacturer", path); + file.open(filename, ios::in); + if (file) { + file.getline(vendor, 2047); + if (strstr(vendor, "Linux ")) + vendor[0] = 0; + file.close(); + }; + snprintf(filename, sizeof(filename), "%s/product", path); + file.open(filename, ios::in); + if (file) { + file.getline(product, 2040); + file.close(); + }; + if (strlen(vendor) && strlen(product)) + snprintf(humanname, sizeof(humanname), _("USB device: %s (%s)"), product, vendor); + else if (strlen(product)) + snprintf(humanname, sizeof(humanname), _("USB device: %s"), product); + else if (strlen(vendor)) + snprintf(humanname, sizeof(humanname), _("USB device: %s"), vendor); + + /* For usbdevfs we need bus number and device number */ + snprintf(filename, sizeof(filename), "%s/busnum", path); + file.open(filename, ios::in); + if (file) { + + file >> busnum; + file.close(); + }; + snprintf(filename, sizeof(filename), "%s/devnum", path); + file.open(filename, ios::in); + if (file) { + + file >> devnum; + file.close(); + }; +} + + + +void usbdevice::start_measurement(void) +{ + ifstream file; + char fullpath[PATH_MAX]; + + active_before = 0; + active_after = 0; + connected_before = 0; + connected_after = 0; + + snprintf(fullpath, sizeof(fullpath), "%s/power/active_duration", sysfs_path); + file.open(fullpath, ios::in); + if (file) { + file >> active_before; + } + file.close(); + + snprintf(fullpath, sizeof(fullpath), "%s/power/connected_duration", sysfs_path); + file.open(fullpath, ios::in); + if (file) { + file >> connected_before; + } + file.close(); +} + +void usbdevice::end_measurement(void) +{ + ifstream file; + char fullpath[PATH_MAX]; + + snprintf(fullpath, sizeof(fullpath), "%s/power/active_duration", sysfs_path); + file.open(fullpath, ios::in); + if (file) { + file >> active_after; + } + file.close(); + + snprintf(fullpath, sizeof(fullpath), "%s/power/connected_duration", sysfs_path); + file.open(fullpath, ios::in); + if (file) { + file >> connected_after; + } + file.close(); + report_utilization(name, utilization()); + +} + +double usbdevice::utilization(void) /* percentage */ +{ + double d; + d = 100.0 * (active_after - active_before) / (0.01 + connected_after - connected_before); + if (d < 0.0) + d = 0.0; + if (d > 99.8) + d = 100.0; + return d; +} + +const char * usbdevice::device_name(void) +{ + return name; +} + +const char * usbdevice::human_name(void) +{ + return humanname; +} + +void usbdevice::register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle) +{ + char devfs_name[1024]; + + snprintf(devfs_name, sizeof(devfs_name), "usb/%03d/%03d", busnum, + devnum); + + register_devpower(devfs_name, power_usage(results, bundle), this); +} + +double usbdevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle) +{ + double power; + double factor; + double util; + + if (rootport || !cached_valid) + return 0.0; + + + power = 0; + factor = get_parameter_value(index, bundle); + util = get_result_value(r_index, result); + + power += util * factor / 100.0; + + return power; +} + +static void create_all_usb_devices_callback(const char *d_name) +{ + char filename[PATH_MAX]; + ifstream file; + class usbdevice *usb; + char device_name[PATH_MAX]; + char vendorid[64], devid[64]; + char devid_name[4096]; + + snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s", d_name); + snprintf(device_name, sizeof(device_name), "%s/power/active_duration", filename); + if (access(device_name, R_OK) != 0) + return; + + snprintf(device_name, sizeof(device_name), "%s/idVendor", filename); + file.open(device_name, ios::in); + if (file) + file.getline(vendorid, 64); + file.close(); + snprintf(device_name, sizeof(device_name), "%s/idProduct", filename); + file.open(device_name, ios::in); + if (file) + file.getline(devid, 64); + file.close(); + + snprintf(devid_name, sizeof(devid_name), "usb-device-%s-%s", vendorid, devid); + snprintf(device_name, sizeof(device_name), "usb-device-%s-%s-%s", d_name, vendorid, devid); + if (result_device_exists(device_name)) + return; + + usb = new class usbdevice(device_name, filename, devid_name); + all_devices.push_back(usb); + register_parameter(devid_name, 0.1); +} + +void create_all_usb_devices(void) +{ + process_directory("/sys/bus/usb/devices/", create_all_usb_devices_callback); +} diff --git a/src/devices/usb.h b/src/devices/usb.h new file mode 100644 index 0000000..7e76a55 --- /dev/null +++ b/src/devices/usb.h @@ -0,0 +1,67 @@ +/* + * 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> + */ +#ifndef _INCLUDE_GUARD_USB_H +#define _INCLUDE_GUARD_USB_H + +#include <limits.h> + +#include "device.h" +#include "../parameters/parameters.h" + +class usbdevice: public device { + int active_before, active_after; + int connected_before, connected_after; + char sysfs_path[PATH_MAX]; + char name[4096]; + char devname[4096]; + char humanname[4096]; + int index; + int r_index; + int rootport; + int busnum; + int devnum; +public: + + usbdevice(const char *_name, const char *path, const char *devid); + + virtual void start_measurement(void); + virtual void end_measurement(void); + + virtual double utilization(void); /* percentage */ + + virtual const char * class_name(void) { return "usb";}; + + virtual const char * device_name(void); + virtual const char * human_name(void); + virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle); + virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle); + virtual int power_valid(void) { return utilization_power_valid(r_index);}; + virtual int grouping_prio(void) { return 4; }; +}; + +extern void create_all_usb_devices(void); + + +#endif
\ No newline at end of file |