diff options
Diffstat (limited to 'src/devices/ahci.cpp')
-rw-r--r-- | src/devices/ahci.cpp | 428 |
1 files changed, 428 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; +} |