diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:00:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 20:00:20 +0000 |
commit | fcb4cb5c3d0fec0fede160d565134d553d783fb2 (patch) | |
tree | 7be42535554ca6badc1847d83ef123f4dc3c5506 /src/devlist.cpp | |
parent | Initial commit. (diff) | |
download | powertop-fcb4cb5c3d0fec0fede160d565134d553d783fb2.tar.xz powertop-fcb4cb5c3d0fec0fede160d565134d553d783fb2.zip |
Adding upstream version 2.15.upstream/2.15upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/devlist.cpp')
-rw-r--r-- | src/devlist.cpp | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/src/devlist.cpp b/src/devlist.cpp new file mode 100644 index 0000000..70ae70e --- /dev/null +++ b/src/devlist.cpp @@ -0,0 +1,351 @@ +/* + * 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> + */ + +/* + * Code to track centrally which process has what /dev files open + */ +#include <iostream> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <sys/stat.h> +#include <vector> +#include <algorithm> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> + +using namespace std; + +#include "devlist.h" +#include "lib.h" +#include "report/report.h" +#include "report/report-maker.h" +#include "report/report-data-html.h" + +#include "process/process.h" +#include "devices/device.h" +/* + +* collect list of processes that have devices open + (alternate between before and after lists) + +* charge a "surcharge" to a device (sub)string + - count how many openers + - add proprotion to each process that has it open + +* list of devices + power they use for processing + +*/ + +static vector<struct devuser *> one; +static vector<struct devuser *> two; +static vector<struct devpower *> devpower; + +static int phase; +/* + * 0 - one = before, two = after + * 1 - one = after, two = before + */ + +void clean_open_devices() +{ + unsigned int i=0; + + for (i = 0; i < one.size(); i++) { + free(one[i]); + } + + for (i = 0; i < two.size(); i++) { + free(two[i]); + } + + for (i = 0; i < devpower.size(); i++){ + free(devpower[i]); + } +} + +void collect_open_devices(void) +{ + struct dirent *entry; + DIR *dir; + char filename[PATH_MAX]; + char link[PATH_MAX]; + unsigned int i; + vector<struct devuser *> *target; + + if (phase == 1) + target = &one; + else + target = &two; + + for (i = 0; i < target->size(); i++) { + free((*target)[i]); + } + target->resize(0); + + + dir = opendir("/proc/"); + if (!dir) + return; + while (1) { + struct dirent *entry2; + DIR *dir2; + entry = readdir(dir); + + if (!entry) + break; + if (entry->d_name[0] == '.') + continue; + if (strcmp(entry->d_name, "self") == 0) + continue; + + snprintf(filename, sizeof(filename), "/proc/%s/fd/", entry->d_name); + + dir2 = opendir(filename); + if (!dir2) + continue; + while (1) { + int ret; + struct devuser * dev; + entry2 = readdir(dir2); + if (!entry2) + break; + if (!isdigit(entry2->d_name[0])) + continue; + snprintf(filename, sizeof(filename), "/proc/%s/fd/%s", entry->d_name, entry2->d_name); + memset(link, 0, sizeof(link)); + ret = readlink(filename, link, sizeof(link) - 1); + if (ret < 0) + continue; + + if (strcmp(link, "/dev/null") == 0) + continue; + if (strcmp(link, "/dev/.udev/queue.bin") == 0) + continue; + if (strcmp(link, "/dev/initctl") == 0) + continue; + if (strcmp(link, "/dev/ptmx") == 0) + continue; + if (strstr(link, "/dev/pts/")) + continue; + if (strstr(link, "/dev/shm/")) + continue; + if (strstr(link, "/dev/urandom")) + continue; + if (strstr(link, "/dev/tty")) + continue; + + if (strncmp(link, "/dev", 4)==0) { + dev = (struct devuser *)malloc(sizeof(struct devuser)); + if (!dev) + continue; + dev->pid = strtoull(entry->d_name, NULL, 10); + strncpy(dev->device, link, 251); + dev->device[251] = '\0'; + strncpy(dev->comm, read_sysfs_string("/proc/%s/comm", entry->d_name).c_str(), 31); + dev->comm[31] = '\0'; + target->push_back(dev); + + } + } + closedir(dir2); + } + closedir(dir); + + if (phase) + phase = 0; + else + phase = 1; +} + + +/* returns 0 if no process is identified as having the device open and a value > 0 otherwise */ +int charge_device_to_openers(const char *devstring, double power, class device *_dev) +{ + unsigned int i; + int openers = 0; + class process *proc; + /* 1. count the number of openers */ + + for (i = 0; i < one.size(); i++) { + if (strstr(one[i]->device, devstring)) + openers++; + } + for (i = 0; i < two.size(); i++) { + if (strstr(two[i]->device, devstring)) + openers++; + } + + + /* 2. divide power by this number */ + + if (!openers) + return 0; + power = power / openers; + + + /* 3. for each process that has it open, add the charge */ + + for (i = 0; i < one.size(); i++) + if (strstr(one[i]->device, devstring)) { + proc = find_create_process(one[i]->comm, one[i]->pid); + if (proc) { + proc->power_charge += power; + if (strlen(_dev->guilty) < 2000 && strstr(_dev->guilty, one[i]->comm) == NULL) { + strcat(_dev->guilty, one[i]->comm); + strcat(_dev->guilty, " "); + } + } + } + + for (i = 0; i < two.size(); i++) + if (strstr(two[i]->device, devstring)) { + proc = find_create_process(two[i]->comm, two[i]->pid); + if (proc) { + proc->power_charge += power; + if (strlen(_dev->guilty) < 2000 && strstr(_dev->guilty, two[i]->comm) == NULL) { + strcat(_dev->guilty, two[i]->comm); + strcat(_dev->guilty, " "); + } + } + } + + + + return openers; +} + +void clear_devpower(void) +{ + unsigned int i; + + for (i = 0; i < devpower.size(); i++) { + devpower[i]->power = 0.0; + devpower[i]->dev->guilty[0] = 0; + } +} + +void register_devpower(const char *devstring, double power, class device *_dev) +{ + unsigned int i; + struct devpower *dev = NULL; + + for (i = 0; i < devpower.size(); i++) + if (strcmp(devstring, devpower[i]->device) == 0) { + dev = devpower[i]; + } + + if (!dev) { + dev = (struct devpower *)malloc(sizeof (struct devpower)); + pt_strcpy(dev->device, devstring); + dev->power = 0.0; + devpower.push_back(dev); + } + dev->dev = _dev; + dev->power = power; +} + +void run_devpower_list(void) +{ + unsigned int i; + + for (i = 0; i < devpower.size(); i++) { + int ret; + ret = charge_device_to_openers(devpower[i]->device, devpower[i]->power, devpower[i]->dev); + if (ret) + devpower[i]->dev->hide = true; + else + devpower[i]->dev->hide = false; + + } + +} + +static bool devlist_sort(struct devuser * i, struct devuser * j) +{ + if (i->pid != j->pid) + return i->pid < j->pid; + + return (strcmp(i->device, j->device)< 0); +} + +void report_show_open_devices(void) +{ + vector<struct devuser *> *target; + unsigned int i; + char prev[128], proc[128]; + int idx, cols, rows; + + prev[0] = 0; + if (phase == 1) + target = &one; + else + target = &two; + + if (target->size() == 0) + return; + + + /* Set Table attributes, rows, and cols */ + table_attributes std_table_css; + cols = 2; + idx = cols; + rows= target->size() + 1; + init_std_table_attr(&std_table_css, rows, cols); + + /* Set Title attributes */ + tag_attr title_attr; + init_title_attr(&title_attr); + + /* Set array of data in row Major order */ + string *process_data = new string[cols * rows]; + + sort(target->begin(), target->end(), devlist_sort); + process_data[0]=__("Process"); + process_data[1]=__("Device"); + + for (i = 0; i < target->size(); i++) { + proc[0] = 0; + if (strcmp(prev, (*target)[i]->comm) != 0) + snprintf(proc, sizeof(proc), "%s", (*target)[i]->comm); + + process_data[idx]=string(proc); + idx+=1; + process_data[idx]=string((*target)[i]->device); + idx+=1; + snprintf(prev, sizeof(prev), "%s", (*target)[i]->comm); + } + + /* Report Output */ + /* No div attribute here inherits from device power report */ + report.add_title(&title_attr, __("Process Device Activity")); + report.add_table(process_data, &std_table_css); + delete [] process_data; + report.end_div(); +} |