You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
5.5 KiB
263 lines
5.5 KiB
/*
|
|
* blktrace output analysis: generate a timeline & gather statistics
|
|
*
|
|
* Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
|
|
*
|
|
* This program 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
#include <string.h>
|
|
|
|
#include "globals.h"
|
|
|
|
struct pn_info {
|
|
struct rb_node rb_node;
|
|
struct p_info *pip;
|
|
union {
|
|
char *name;
|
|
__u32 pid;
|
|
} u;
|
|
};
|
|
|
|
struct rb_root root_pid, root_name;
|
|
|
|
static void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *),
|
|
void *arg)
|
|
{
|
|
if (n) {
|
|
__foreach(n->rb_left, f, arg);
|
|
f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
|
|
__foreach(n->rb_right, f, arg);
|
|
}
|
|
}
|
|
|
|
static void __destroy(struct rb_node *n, int free_name, int free_pip)
|
|
{
|
|
if (n) {
|
|
struct pn_info *pnp = rb_entry(n, struct pn_info, rb_node);
|
|
|
|
__destroy(n->rb_left, free_name, free_pip);
|
|
__destroy(n->rb_right, free_name, free_pip);
|
|
|
|
if (free_name)
|
|
free(pnp->u.name);
|
|
if (free_pip) {
|
|
free(pnp->pip->name);
|
|
region_exit(&pnp->pip->regions);
|
|
free(pnp->pip);
|
|
}
|
|
free(pnp);
|
|
}
|
|
}
|
|
|
|
struct p_info * __find_process_pid(__u32 pid)
|
|
{
|
|
struct pn_info *this;
|
|
struct rb_node *n = root_pid.rb_node;
|
|
|
|
while (n) {
|
|
this = rb_entry(n, struct pn_info, rb_node);
|
|
if (pid < this->u.pid)
|
|
n = n->rb_left;
|
|
else if (pid > this->u.pid)
|
|
n = n->rb_right;
|
|
else
|
|
return this->pip;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct p_info *__find_process_name(char *name)
|
|
{
|
|
int cmp;
|
|
struct pn_info *this;
|
|
struct rb_node *n = root_name.rb_node;
|
|
|
|
while (n) {
|
|
this = rb_entry(n, struct pn_info, rb_node);
|
|
cmp = strcmp(name, this->u.name);
|
|
if (cmp < 0)
|
|
n = n->rb_left;
|
|
else if (cmp > 0)
|
|
n = n->rb_right;
|
|
else
|
|
return this->pip;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void insert_pid(struct p_info *that, __u32 pid)
|
|
{
|
|
struct pn_info *this;
|
|
struct rb_node *parent = NULL;
|
|
struct rb_node **p = &root_pid.rb_node;
|
|
|
|
while (*p) {
|
|
parent = *p;
|
|
this = rb_entry(parent, struct pn_info, rb_node);
|
|
|
|
if (pid < this->u.pid)
|
|
p = &(*p)->rb_left;
|
|
else if (pid > this->u.pid)
|
|
p = &(*p)->rb_right;
|
|
else
|
|
return; // Already there
|
|
}
|
|
|
|
this = malloc(sizeof(struct pn_info));
|
|
this->u.pid = pid;
|
|
this->pip = that;
|
|
|
|
rb_link_node(&this->rb_node, parent, p);
|
|
rb_insert_color(&this->rb_node, &root_pid);
|
|
}
|
|
|
|
static void insert_name(struct p_info *that)
|
|
{
|
|
int cmp;
|
|
struct pn_info *this;
|
|
struct rb_node *parent = NULL;
|
|
struct rb_node **p = &root_name.rb_node;
|
|
|
|
while (*p) {
|
|
parent = *p;
|
|
this = rb_entry(parent, struct pn_info, rb_node);
|
|
cmp = strcmp(that->name, this->u.name);
|
|
|
|
if (cmp < 0)
|
|
p = &(*p)->rb_left;
|
|
else if (cmp > 0)
|
|
p = &(*p)->rb_right;
|
|
else
|
|
return; // Already there...
|
|
}
|
|
|
|
this = malloc(sizeof(struct pn_info));
|
|
this->u.name = strdup(that->name);
|
|
this->pip = that;
|
|
|
|
rb_link_node(&this->rb_node, parent, p);
|
|
rb_insert_color(&this->rb_node, &root_name);
|
|
}
|
|
|
|
static void insert(struct p_info *pip)
|
|
{
|
|
insert_pid(pip, pip->pid);
|
|
insert_name(pip);
|
|
}
|
|
|
|
static inline struct p_info *pip_alloc(void)
|
|
{
|
|
return memset(malloc(sizeof(struct p_info)), 0, sizeof(struct p_info));
|
|
}
|
|
|
|
struct p_info *find_process(__u32 pid, char *name)
|
|
{
|
|
struct p_info *pip;
|
|
|
|
if (pid != ((__u32)-1)) {
|
|
if ((pip = __find_process_pid(pid)) != NULL)
|
|
return pip;
|
|
else if (name) {
|
|
pip = __find_process_name(name);
|
|
|
|
if (pip && pid != pip->pid) {
|
|
/*
|
|
* This is a process with the same name
|
|
* as another, but a different PID.
|
|
*
|
|
* We'll store a reference in the PID
|
|
* tree...
|
|
*/
|
|
insert_pid(pip, pid);
|
|
}
|
|
return pip;
|
|
}
|
|
|
|
/*
|
|
* We're here because we have a pid, and no name, but
|
|
* we didn't find a process ...
|
|
*
|
|
* We'll craft one using the pid...
|
|
*/
|
|
|
|
name = alloca(256);
|
|
sprintf(name, "pid%09u", pid);
|
|
process_alloc(pid, name);
|
|
return __find_process_pid(pid);
|
|
}
|
|
|
|
return __find_process_name(name);
|
|
}
|
|
|
|
void process_alloc(__u32 pid, char *name)
|
|
{
|
|
struct p_info *pip = find_process(pid, name);
|
|
|
|
if (pip == NULL) {
|
|
pip = pip_alloc();
|
|
pip->pid = pid;
|
|
region_init(&pip->regions);
|
|
pip->last_q = (__u64)-1;
|
|
pip->name = strdup(name);
|
|
|
|
insert(pip);
|
|
}
|
|
}
|
|
|
|
void pip_update_q(struct io *iop)
|
|
{
|
|
if (iop->pip) {
|
|
if (remapper_dev(iop->dip->device))
|
|
update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q_dm,
|
|
iop->t.time);
|
|
else
|
|
update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q,
|
|
iop->t.time);
|
|
update_qregion(&iop->pip->regions, iop->t.time);
|
|
}
|
|
}
|
|
|
|
void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
|
|
{
|
|
if (exes == NULL)
|
|
__foreach(root_name.rb_node, f, arg);
|
|
else {
|
|
struct p_info *pip;
|
|
char *exe, *next, *exes_save = strdup(exes);
|
|
|
|
while (exes_save != NULL) {
|
|
exe = exes_save;
|
|
if ((next = strchr(exes_save, ',')) != NULL) {
|
|
*next = '\0';
|
|
exes_save = next+1;
|
|
} else
|
|
exes_save = NULL;
|
|
|
|
pip = __find_process_name(exe);
|
|
if (pip)
|
|
f(pip, arg);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pip_exit(void)
|
|
{
|
|
__destroy(root_pid.rb_node, 0, 0);
|
|
__destroy(root_name.rb_node, 1, 1);
|
|
}
|