diff options
Diffstat (limited to 'src/devices/runtime_pm.cpp')
-rw-r--r-- | src/devices/runtime_pm.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
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"); +} |