Home | History | Annotate | Download | only in btt
      1 /*
      2  * blktrace output analysis: generate a timeline & gather statistics
      3  *
      4  * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle (at) hp.com>
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19  *
     20  */
     21 #include <string.h>
     22 
     23 #include "globals.h"
     24 
     25 struct pn_info {
     26 	struct rb_node rb_node;
     27 	struct p_info *pip;
     28 	union {
     29 		char *name;
     30 		__u32 pid;
     31 	}  u;
     32 };
     33 
     34 struct rb_root root_pid, root_name;
     35 
     36 static void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *),
     37 			void *arg)
     38 {
     39 	if (n) {
     40 		__foreach(n->rb_left, f, arg);
     41 		f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
     42 		__foreach(n->rb_right, f, arg);
     43 	}
     44 }
     45 
     46 static void __destroy(struct rb_node *n, int free_name, int free_pip)
     47 {
     48 	if (n) {
     49 		struct pn_info *pnp = rb_entry(n, struct pn_info, rb_node);
     50 
     51 		__destroy(n->rb_left, free_name, free_pip);
     52 		__destroy(n->rb_right, free_name, free_pip);
     53 
     54 		if (free_name)
     55 			free(pnp->u.name);
     56 		if (free_pip) {
     57 			free(pnp->pip->name);
     58 			region_exit(&pnp->pip->regions);
     59 			free(pnp->pip);
     60 		}
     61 		free(pnp);
     62 	}
     63 }
     64 
     65 struct p_info * __find_process_pid(__u32 pid)
     66 {
     67 	struct pn_info *this;
     68 	struct rb_node *n = root_pid.rb_node;
     69 
     70 	while (n) {
     71 		this = rb_entry(n, struct pn_info, rb_node);
     72 		if (pid < this->u.pid)
     73 			n = n->rb_left;
     74 		else if (pid > this->u.pid)
     75 			n = n->rb_right;
     76 		else
     77 			return this->pip;
     78 	}
     79 
     80 	return NULL;
     81 }
     82 
     83 struct p_info *__find_process_name(char *name)
     84 {
     85 	int cmp;
     86 	struct pn_info *this;
     87 	struct rb_node *n = root_name.rb_node;
     88 
     89 	while (n) {
     90 		this = rb_entry(n, struct pn_info, rb_node);
     91 		cmp = strcmp(name, this->u.name);
     92 		if (cmp < 0)
     93 			n = n->rb_left;
     94 		else if (cmp > 0)
     95 			n = n->rb_right;
     96 		else
     97 			return this->pip;
     98 	}
     99 
    100 	return NULL;
    101 }
    102 
    103 static void insert_pid(struct p_info *that, __u32 pid)
    104 {
    105 	struct pn_info *this;
    106 	struct rb_node *parent = NULL;
    107 	struct rb_node **p = &root_pid.rb_node;
    108 
    109 	while (*p) {
    110 		parent = *p;
    111 		this = rb_entry(parent, struct pn_info, rb_node);
    112 
    113 		if (pid < this->u.pid)
    114 			p = &(*p)->rb_left;
    115 		else if (pid > this->u.pid)
    116 			p = &(*p)->rb_right;
    117 		else
    118 			return;	// Already there
    119 	}
    120 
    121 	this = malloc(sizeof(struct pn_info));
    122 	this->u.pid = pid;
    123 	this->pip = that;
    124 
    125 	rb_link_node(&this->rb_node, parent, p);
    126 	rb_insert_color(&this->rb_node, &root_pid);
    127 }
    128 
    129 static void insert_name(struct p_info *that)
    130 {
    131 	int cmp;
    132 	struct pn_info *this;
    133 	struct rb_node *parent = NULL;
    134 	struct rb_node **p = &root_name.rb_node;
    135 
    136 	while (*p) {
    137 		parent = *p;
    138 		this = rb_entry(parent, struct pn_info, rb_node);
    139 		cmp = strcmp(that->name, this->u.name);
    140 
    141 		if (cmp < 0)
    142 			p = &(*p)->rb_left;
    143 		else if (cmp > 0)
    144 			p = &(*p)->rb_right;
    145 		else
    146 			return;	// Already there...
    147 	}
    148 
    149 	this = malloc(sizeof(struct pn_info));
    150 	this->u.name = strdup(that->name);
    151 	this->pip = that;
    152 
    153 	rb_link_node(&this->rb_node, parent, p);
    154 	rb_insert_color(&this->rb_node, &root_name);
    155 }
    156 
    157 static void insert(struct p_info *pip)
    158 {
    159 	insert_pid(pip, pip->pid);
    160 	insert_name(pip);
    161 }
    162 
    163 static inline struct p_info *pip_alloc(void)
    164 {
    165 	return memset(malloc(sizeof(struct p_info)), 0, sizeof(struct p_info));
    166 }
    167 
    168 struct p_info *find_process(__u32 pid, char *name)
    169 {
    170 	struct p_info *pip;
    171 
    172 	if (pid != ((__u32)-1)) {
    173 		if ((pip = __find_process_pid(pid)) != NULL)
    174 			return pip;
    175 		else if (name) {
    176 			pip = __find_process_name(name);
    177 
    178 			if (pip && pid != pip->pid) {
    179 				/*
    180 				 * This is a process with the same name
    181 				 * as another, but a different PID.
    182 				 *
    183 				 * We'll store a reference in the PID
    184 				 * tree...
    185 				 */
    186 				insert_pid(pip, pid);
    187 			}
    188 			return pip;
    189 		}
    190 
    191 		/*
    192 		 * We're here because we have a pid, and no name, but
    193 		 * we didn't find a process ...
    194 		 *
    195 		 * We'll craft one using the pid...
    196 		 */
    197 
    198 		name = alloca(256);
    199 		sprintf(name, "pid%09u", pid);
    200 		process_alloc(pid, name);
    201 		return __find_process_pid(pid);
    202 	}
    203 
    204 	return __find_process_name(name);
    205 }
    206 
    207 void process_alloc(__u32 pid, char *name)
    208 {
    209 	struct p_info *pip = find_process(pid, name);
    210 
    211 	if (pip == NULL) {
    212 		pip = pip_alloc();
    213 		pip->pid = pid;
    214 		region_init(&pip->regions);
    215 		pip->last_q = (__u64)-1;
    216 		pip->name = strdup(name);
    217 
    218 		insert(pip);
    219 	}
    220 }
    221 
    222 void pip_update_q(struct io *iop)
    223 {
    224 	if (iop->pip) {
    225 		if (remapper_dev(iop->dip->device))
    226 			update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q_dm,
    227 								iop->t.time);
    228 		else
    229 			update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q,
    230 								iop->t.time);
    231 		update_qregion(&iop->pip->regions, iop->t.time);
    232 	}
    233 }
    234 
    235 void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
    236 {
    237 	if (exes == NULL)
    238 		__foreach(root_name.rb_node, f, arg);
    239 	else {
    240 		struct p_info *pip;
    241 		char *exe, *p, *next, *exes_save = strdup(exes);
    242 
    243 		p = exes_save;
    244 		while (exes_save != NULL) {
    245 			exe = exes_save;
    246 			if ((next = strchr(exes_save, ',')) != NULL) {
    247 				*next = '\0';
    248 				exes_save = next+1;
    249 			} else
    250 				exes_save = NULL;
    251 
    252 			pip = __find_process_name(exe);
    253 			if (pip)
    254 				f(pip, arg);
    255 		}
    256 	}
    257 }
    258 
    259 void pip_exit(void)
    260 {
    261 	__destroy(root_pid.rb_node, 0, 0);
    262 	__destroy(root_name.rb_node, 1, 1);
    263 }
    264