| /* |
| * 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 "process.h" |
| #include <string.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| |
| #include <iostream> |
| #include <fstream> |
| |
| |
| vector <class process *> all_processes; |
| |
| void process::account_disk_dirty(void) |
| { |
| disk_hits++; |
| } |
| |
| void process::schedule_thread(uint64_t time, int thread_id) |
| { |
| running_since = time; |
| running = 1; |
| } |
| |
| |
| uint64_t process::deschedule_thread(uint64_t time, int thread_id) |
| { |
| uint64_t delta; |
| |
| if (!running_since) |
| return 0; |
| |
| delta = time - running_since; |
| |
| if (time < running_since) |
| printf("%llu time %llu since \n", (unsigned long long)time, |
| (unsigned long long)running_since); |
| |
| if (thread_id == 0) /* idle thread */ |
| delta = 0; |
| accumulated_runtime += delta; |
| running = 0; |
| |
| return delta; |
| } |
| |
| static void cmdline_to_string(char *str) |
| { |
| char *c = str; |
| char prev = 0; |
| |
| while (prev != 0 || *c != 0) { |
| prev = *c; |
| if (*c == 0) |
| *c = ' '; |
| c++; |
| } |
| } |
| |
| |
| process::process(const char *_comm, int _pid, int _tid) : power_consumer() |
| { |
| char line[4096]; |
| ifstream file; |
| |
| strcpy(comm, _comm); |
| pid = _pid; |
| is_idle = 0; |
| running = 0; |
| last_waker = NULL; |
| waker = NULL; |
| is_kernel = 0; |
| tgid = _tid; |
| |
| if (_tid == 0) { |
| sprintf(line, "/proc/%i/status", _pid); |
| file.open(line); |
| while (file) { |
| file.getline(line, 4096); |
| if (strstr(line, "Tgid")) { |
| char *c; |
| c = strchr(line, ':'); |
| if (!c) |
| continue; |
| c++; |
| tgid = strtoull(c, NULL, 10); |
| break; |
| } |
| } |
| file.close(); |
| } |
| |
| if (strncmp(_comm, "kondemand/", 10) == 0) |
| is_idle = 1; |
| |
| strcpy(desc, comm); |
| |
| sprintf(line, "/proc/%i/cmdline", _pid); |
| file.open(line, ios::binary); |
| if (file) { |
| memset(line, 0, sizeof(line)); |
| file.read(line, 4096); |
| file.close(); |
| if (strlen(line) < 1) { |
| is_kernel = 1; |
| sprintf(desc, "[%s]", comm); |
| } else { |
| int sz = sizeof(desc) - 1; |
| cmdline_to_string(line); |
| strncpy(desc, line, sz); |
| desc[sz] = 0x00; |
| } |
| } |
| } |
| |
| const char * process::description(void) |
| { |
| |
| if (child_runtime > accumulated_runtime) |
| child_runtime = 0; |
| |
| return desc; |
| } |
| |
| double process::usage_summary(void) |
| { |
| double t; |
| t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10; |
| return t; |
| } |
| |
| const char * process::usage_units_summary(void) |
| { |
| return "%"; |
| } |
| |
| class process * find_create_process(const char *comm, int pid) |
| { |
| unsigned int i; |
| class process *new_proc; |
| |
| for (i = 0; i < all_processes.size(); i++) { |
| if (all_processes[i]->pid == pid && strcmp(comm, all_processes[i]->comm) == 0) |
| return all_processes[i]; |
| } |
| |
| new_proc = new class process(comm, pid); |
| all_processes.push_back(new_proc); |
| return new_proc; |
| } |
| |
| class process * find_create_process(char *comm, int pid) |
| { |
| return find_create_process((const char*)comm, pid); |
| } |
| |
| static void merge_process(class process *one, class process *two) |
| { |
| one->accumulated_runtime += two->accumulated_runtime; |
| one->child_runtime += two->child_runtime; |
| one->wake_ups += two->wake_ups; |
| one->disk_hits += two->disk_hits; |
| one->hard_disk_hits += two->hard_disk_hits; |
| one->xwakes += two->xwakes; |
| one->gpu_ops += two->gpu_ops; |
| one->power_charge += two->power_charge; |
| } |
| |
| |
| void merge_processes(void) |
| { |
| std::vector<class process*>::iterator it1, it2; |
| class process *one, *two; |
| |
| it1 = all_processes.begin(); |
| while (it1 != all_processes.end()) { |
| it2 = it1 + 1; |
| one = *it1; |
| while (it2 != all_processes.end()) { |
| two = *it2; |
| /* fold threads */ |
| if (one->pid == two->tgid && two->tgid != 0) { |
| merge_process(one, two); |
| delete *it2; |
| it2 = all_processes.erase(it2); |
| continue; |
| } |
| /* find dupes and add up */ |
| if (!strcmp(one->desc, two->desc)) { |
| merge_process(one, two); |
| delete *it2; |
| it2 = all_processes.erase(it2); |
| continue; |
| } |
| ++it2; |
| } |
| ++it1; |
| } |
| } |
| |
| void all_processes_to_all_power(void) |
| { |
| unsigned int i; |
| for (i = 0; i < all_processes.size() ; i++) |
| if (all_processes[i]->accumulated_runtime) |
| all_power.push_back(all_processes[i]); |
| } |
| |
| void clear_processes(void) |
| { |
| std::vector <class process *>::iterator it = all_processes.begin(); |
| while (it != all_processes.end()) { |
| delete *it; |
| it = all_processes.erase(it); |
| } |
| } |