Blame btt/proc.c

Packit c4abd9
/*
Packit c4abd9
 * blktrace output analysis: generate a timeline & gather statistics
Packit c4abd9
 *
Packit c4abd9
 * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
Packit c4abd9
 *
Packit c4abd9
 *  This program is free software; you can redistribute it and/or modify
Packit c4abd9
 *  it under the terms of the GNU General Public License as published by
Packit c4abd9
 *  the Free Software Foundation; either version 2 of the License, or
Packit c4abd9
 *  (at your option) any later version.
Packit c4abd9
 *
Packit c4abd9
 *  This program is distributed in the hope that it will be useful,
Packit c4abd9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit c4abd9
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit c4abd9
 *  GNU General Public License for more details.
Packit c4abd9
 *
Packit c4abd9
 *  You should have received a copy of the GNU General Public License
Packit c4abd9
 *  along with this program; if not, write to the Free Software
Packit c4abd9
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit c4abd9
 *
Packit c4abd9
 */
Packit c4abd9
#include <string.h>
Packit c4abd9
Packit c4abd9
#include "globals.h"
Packit c4abd9
Packit c4abd9
struct pn_info {
Packit c4abd9
	struct rb_node rb_node;
Packit c4abd9
	struct p_info *pip;
Packit c4abd9
	union {
Packit c4abd9
		char *name;
Packit c4abd9
		__u32 pid;
Packit c4abd9
	}  u;
Packit c4abd9
};
Packit c4abd9
Packit c4abd9
struct rb_root root_pid, root_name;
Packit c4abd9
Packit c4abd9
static void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *),
Packit c4abd9
			void *arg)
Packit c4abd9
{
Packit c4abd9
	if (n) {
Packit c4abd9
		__foreach(n->rb_left, f, arg);
Packit c4abd9
		f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
Packit c4abd9
		__foreach(n->rb_right, f, arg);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void __destroy(struct rb_node *n, int free_name, int free_pip)
Packit c4abd9
{
Packit c4abd9
	if (n) {
Packit c4abd9
		struct pn_info *pnp = rb_entry(n, struct pn_info, rb_node);
Packit c4abd9
Packit c4abd9
		__destroy(n->rb_left, free_name, free_pip);
Packit c4abd9
		__destroy(n->rb_right, free_name, free_pip);
Packit c4abd9
Packit c4abd9
		if (free_name)
Packit c4abd9
			free(pnp->u.name);
Packit c4abd9
		if (free_pip) {
Packit c4abd9
			free(pnp->pip->name);
Packit c4abd9
			region_exit(&pnp->pip->regions);
Packit c4abd9
			free(pnp->pip);
Packit c4abd9
		}
Packit c4abd9
		free(pnp);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
struct p_info * __find_process_pid(__u32 pid)
Packit c4abd9
{
Packit c4abd9
	struct pn_info *this;
Packit c4abd9
	struct rb_node *n = root_pid.rb_node;
Packit c4abd9
Packit c4abd9
	while (n) {
Packit c4abd9
		this = rb_entry(n, struct pn_info, rb_node);
Packit c4abd9
		if (pid < this->u.pid)
Packit c4abd9
			n = n->rb_left;
Packit c4abd9
		else if (pid > this->u.pid)
Packit c4abd9
			n = n->rb_right;
Packit c4abd9
		else
Packit c4abd9
			return this->pip;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return NULL;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
struct p_info *__find_process_name(char *name)
Packit c4abd9
{
Packit c4abd9
	int cmp;
Packit c4abd9
	struct pn_info *this;
Packit c4abd9
	struct rb_node *n = root_name.rb_node;
Packit c4abd9
Packit c4abd9
	while (n) {
Packit c4abd9
		this = rb_entry(n, struct pn_info, rb_node);
Packit c4abd9
		cmp = strcmp(name, this->u.name);
Packit c4abd9
		if (cmp < 0)
Packit c4abd9
			n = n->rb_left;
Packit c4abd9
		else if (cmp > 0)
Packit c4abd9
			n = n->rb_right;
Packit c4abd9
		else
Packit c4abd9
			return this->pip;
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return NULL;
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void insert_pid(struct p_info *that, __u32 pid)
Packit c4abd9
{
Packit c4abd9
	struct pn_info *this;
Packit c4abd9
	struct rb_node *parent = NULL;
Packit c4abd9
	struct rb_node **p = &root_pid.rb_node;
Packit c4abd9
Packit c4abd9
	while (*p) {
Packit c4abd9
		parent = *p;
Packit c4abd9
		this = rb_entry(parent, struct pn_info, rb_node);
Packit c4abd9
Packit c4abd9
		if (pid < this->u.pid)
Packit c4abd9
			p = &(*p)->rb_left;
Packit c4abd9
		else if (pid > this->u.pid)
Packit c4abd9
			p = &(*p)->rb_right;
Packit c4abd9
		else
Packit c4abd9
			return;	// Already there
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	this = malloc(sizeof(struct pn_info));
Packit c4abd9
	this->u.pid = pid;
Packit c4abd9
	this->pip = that;
Packit c4abd9
Packit c4abd9
	rb_link_node(&this->rb_node, parent, p);
Packit c4abd9
	rb_insert_color(&this->rb_node, &root_pid);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void insert_name(struct p_info *that)
Packit c4abd9
{
Packit c4abd9
	int cmp;
Packit c4abd9
	struct pn_info *this;
Packit c4abd9
	struct rb_node *parent = NULL;
Packit c4abd9
	struct rb_node **p = &root_name.rb_node;
Packit c4abd9
Packit c4abd9
	while (*p) {
Packit c4abd9
		parent = *p;
Packit c4abd9
		this = rb_entry(parent, struct pn_info, rb_node);
Packit c4abd9
		cmp = strcmp(that->name, this->u.name);
Packit c4abd9
Packit c4abd9
		if (cmp < 0)
Packit c4abd9
			p = &(*p)->rb_left;
Packit c4abd9
		else if (cmp > 0)
Packit c4abd9
			p = &(*p)->rb_right;
Packit c4abd9
		else
Packit c4abd9
			return;	// Already there...
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	this = malloc(sizeof(struct pn_info));
Packit c4abd9
	this->u.name = strdup(that->name);
Packit c4abd9
	this->pip = that;
Packit c4abd9
Packit c4abd9
	rb_link_node(&this->rb_node, parent, p);
Packit c4abd9
	rb_insert_color(&this->rb_node, &root_name);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static void insert(struct p_info *pip)
Packit c4abd9
{
Packit c4abd9
	insert_pid(pip, pip->pid);
Packit c4abd9
	insert_name(pip);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
static inline struct p_info *pip_alloc(void)
Packit c4abd9
{
Packit c4abd9
	return memset(malloc(sizeof(struct p_info)), 0, sizeof(struct p_info));
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
struct p_info *find_process(__u32 pid, char *name)
Packit c4abd9
{
Packit c4abd9
	struct p_info *pip;
Packit c4abd9
Packit c4abd9
	if (pid != ((__u32)-1)) {
Packit c4abd9
		if ((pip = __find_process_pid(pid)) != NULL)
Packit c4abd9
			return pip;
Packit c4abd9
		else if (name) {
Packit c4abd9
			pip = __find_process_name(name);
Packit c4abd9
Packit c4abd9
			if (pip && pid != pip->pid) {
Packit c4abd9
				/*
Packit c4abd9
				 * This is a process with the same name
Packit c4abd9
				 * as another, but a different PID.
Packit c4abd9
				 *
Packit c4abd9
				 * We'll store a reference in the PID
Packit c4abd9
				 * tree...
Packit c4abd9
				 */
Packit c4abd9
				insert_pid(pip, pid);
Packit c4abd9
			}
Packit c4abd9
			return pip;
Packit c4abd9
		}
Packit c4abd9
Packit c4abd9
		/*
Packit c4abd9
		 * We're here because we have a pid, and no name, but
Packit c4abd9
		 * we didn't find a process ...
Packit c4abd9
		 *
Packit c4abd9
		 * We'll craft one using the pid...
Packit c4abd9
		 */
Packit c4abd9
Packit c4abd9
		name = alloca(256);
Packit c4abd9
		sprintf(name, "pid%09u", pid);
Packit c4abd9
		process_alloc(pid, name);
Packit c4abd9
		return __find_process_pid(pid);
Packit c4abd9
	}
Packit c4abd9
Packit c4abd9
	return __find_process_name(name);
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
void process_alloc(__u32 pid, char *name)
Packit c4abd9
{
Packit c4abd9
	struct p_info *pip = find_process(pid, name);
Packit c4abd9
Packit c4abd9
	if (pip == NULL) {
Packit c4abd9
		pip = pip_alloc();
Packit c4abd9
		pip->pid = pid;
Packit c4abd9
		region_init(&pip->regions);
Packit c4abd9
		pip->last_q = (__u64)-1;
Packit c4abd9
		pip->name = strdup(name);
Packit c4abd9
Packit c4abd9
		insert(pip);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
void pip_update_q(struct io *iop)
Packit c4abd9
{
Packit c4abd9
	if (iop->pip) {
Packit c4abd9
		if (remapper_dev(iop->dip->device))
Packit c4abd9
			update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q_dm,
Packit c4abd9
								iop->t.time);
Packit c4abd9
		else
Packit c4abd9
			update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q,
Packit c4abd9
								iop->t.time);
Packit c4abd9
		update_qregion(&iop->pip->regions, iop->t.time);
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
Packit c4abd9
{
Packit c4abd9
	if (exes == NULL)
Packit c4abd9
		__foreach(root_name.rb_node, f, arg);
Packit c4abd9
	else {
Packit c4abd9
		struct p_info *pip;
Packit c4abd9
		char *exe, *next, *exes_save = strdup(exes);
Packit c4abd9
Packit c4abd9
		while (exes_save != NULL) {
Packit c4abd9
			exe = exes_save;
Packit c4abd9
			if ((next = strchr(exes_save, ',')) != NULL) {
Packit c4abd9
				*next = '\0';
Packit c4abd9
				exes_save = next+1;
Packit c4abd9
			} else
Packit c4abd9
				exes_save = NULL;
Packit c4abd9
Packit c4abd9
			pip = __find_process_name(exe);
Packit c4abd9
			if (pip)
Packit c4abd9
				f(pip, arg);
Packit c4abd9
		}
Packit c4abd9
	}
Packit c4abd9
}
Packit c4abd9
Packit c4abd9
void pip_exit(void)
Packit c4abd9
{
Packit c4abd9
	__destroy(root_pid.rb_node, 0, 0);
Packit c4abd9
	__destroy(root_name.rb_node, 1, 1);
Packit c4abd9
}