/* * 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 */ #include #include #include #include #include #include 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 vector 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; }