Combine all outstanding patches into one /big patch/
[blktrace.git] / btt / proc.c
1 /*
2  * blktrace output analysis: generate a timeline & gather statistics
3  *
4  * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@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 __destroy(struct rb_node *n, int free_name, int free_pip)
37 {
38         if (n) {
39                 struct pn_info *pnp = rb_entry(n, struct pn_info, rb_node);
40
41                 __destroy(n->rb_left, free_name, free_pip);
42                 __destroy(n->rb_right, free_name, free_pip);
43
44                 if (free_name) free(pnp->u.name);
45                 if (free_pip) {
46                         free(pnp->pip->name);
47                         region_exit(&pnp->pip->regions);
48                         free(pnp->pip);
49                 }
50                 free(pnp);
51         }
52 }
53
54 struct p_info * __find_process_pid(__u32 pid)
55 {
56         struct pn_info *this;
57         struct rb_node *n = root_pid.rb_node;
58
59         while (n) {
60                 this = rb_entry(n, struct pn_info, rb_node);
61                 if (pid < this->u.pid)
62                         n = n->rb_left;
63                 else if (pid > this->u.pid)
64                         n = n->rb_right;
65                 else
66                         return this->pip;
67         }
68
69         return NULL;
70 }
71
72 struct p_info *__find_process_name(char *name)
73 {
74         int cmp;
75         struct pn_info *this;
76         struct rb_node *n = root_name.rb_node;
77
78         while (n) {
79                 this = rb_entry(n, struct pn_info, rb_node);
80                 cmp = strcmp(name, this->u.name);
81                 if (cmp < 0)
82                         n = n->rb_left;
83                 else if (cmp > 0)
84                         n = n->rb_right;
85                 else
86                         return this->pip;
87         }
88
89         return NULL;
90 }
91
92 struct p_info *find_process(__u32 pid, char *name)
93 {
94         struct p_info *pip;
95
96         if (pid != ((__u32)-1) && ((pip = __find_process_pid(pid)) != NULL))
97                 return pip;
98
99         if (name)
100                 return __find_process_name(name);
101
102         return NULL;
103 }
104
105 static void insert_pid(struct p_info *that)
106 {
107         struct pn_info *this;
108         struct rb_node *parent = NULL;
109         struct rb_node **p = &root_pid.rb_node;
110
111         while (*p) {
112                 parent = *p;
113                 this = rb_entry(parent, struct pn_info, rb_node);
114
115                 if (that->pid < this->u.pid)
116                         p = &(*p)->rb_left;
117                 else if (that->pid > this->u.pid)
118                         p = &(*p)->rb_right;
119                 else {
120                         ASSERT(strcmp(that->name, this->pip->name) == 0);
121                         return; // Already there
122                 }
123         }
124
125         this = malloc(sizeof(struct pn_info));
126         this->u.pid = that->pid;
127         this->pip = that;
128
129         rb_link_node(&this->rb_node, parent, p);
130         rb_insert_color(&this->rb_node, &root_pid);
131 }
132
133 static void insert_name(struct p_info *that)
134 {
135         int cmp;
136         struct pn_info *this;
137         struct rb_node *parent = NULL;
138         struct rb_node **p = &root_name.rb_node;
139
140         while (*p) {
141                 parent = *p;
142                 this = rb_entry(parent, struct pn_info, rb_node);
143                 cmp = strcmp(that->name, this->u.name);
144
145                 if (cmp < 0)
146                         p = &(*p)->rb_left;
147                 else if (cmp > 0)
148                         p = &(*p)->rb_right;
149                 else
150                         return; // Already there...
151         }
152
153         this = malloc(sizeof(struct pn_info));
154         this->u.name = strdup(that->name);
155         this->pip = that;
156
157         rb_link_node(&this->rb_node, parent, p);
158         rb_insert_color(&this->rb_node, &root_name);
159 }
160
161 static void insert(struct p_info *pip)
162 {
163         insert_pid(pip);
164         insert_name(pip);
165 }
166
167 void add_process(__u32 pid, char *name)
168 {
169         struct p_info *pip = find_process(pid, name);
170
171         if (pip == NULL) {
172                 pip = memset(malloc(sizeof(*pip)), 0, sizeof(*pip));
173                 pip->pid = pid;
174                 region_init(&pip->regions);
175                 pip->last_q = (__u64)-1;
176                 pip->name = strdup(name);
177
178                 insert(pip);
179         }
180 }
181
182 void pip_update_q(struct io *iop)
183 {
184         if (iop->pip) {
185                 update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q, iop->t.time);
186                 update_qregion(&iop->pip->regions, iop->t.time);
187         }
188 }
189
190 void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *), void *arg)
191 {
192         if (n) {
193                 __foreach(n->rb_left, f, arg);
194                 f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
195                 __foreach(n->rb_right, f, arg);
196         }
197 }
198
199 void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
200 {
201         if (exes == NULL)
202                 __foreach(root_name.rb_node, f, arg);
203         else {
204                 struct p_info *pip;
205                 char *exe, *p, *next, *exes_save = strdup(exes);
206
207                 p = exes_save;
208                 while (exes_save != NULL) {
209                         exe = exes_save;
210                         if ((next = strchr(exes_save, ',')) != NULL) {
211                                 *next = '\0';
212                                 exes_save = next+1;
213                         }
214                         else
215                                 exes_save = NULL;
216
217                         pip = __find_process_name(exe);
218                         if (pip)
219                                 f(pip, arg);
220                 }
221         }
222 }
223
224 void pip_exit(void)
225 {
226         __destroy(root_pid.rb_node, 0, 0);
227         __destroy(root_name.rb_node, 1, 1);
228 }