blob: 34dc68ddb7ce5517e814be0bd51a75e9a768d5d5 [file] [log] [blame]
/*
* 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[4097];
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);
line[4096] = '\0';
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);
}
}