Added -X option - generate easily parseable file
[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 static void insert_pid(struct p_info *that, __u32 pid)
93 {
94         struct pn_info *this;
95         struct rb_node *parent = NULL;
96         struct rb_node **p = &root_pid.rb_node;
97
98         while (*p) {
99                 parent = *p;
100                 this = rb_entry(parent, struct pn_info, rb_node);
101
102                 if (pid < this->u.pid)
103                         p = &(*p)->rb_left;
104                 else if (pid > this->u.pid)
105                         p = &(*p)->rb_right;
106                 else
107                         return; // Already there
108         }
109
110         this = malloc(sizeof(struct pn_info));
111         this->u.pid = pid;
112         this->pip = that;
113
114         rb_link_node(&this->rb_node, parent, p);
115         rb_insert_color(&this->rb_node, &root_pid);
116 }
117
118 static void insert_name(struct p_info *that)
119 {
120         int cmp;
121         struct pn_info *this;
122         struct rb_node *parent = NULL;
123         struct rb_node **p = &root_name.rb_node;
124
125         while (*p) {
126                 parent = *p;
127                 this = rb_entry(parent, struct pn_info, rb_node);
128                 cmp = strcmp(that->name, this->u.name);
129
130                 if (cmp < 0)
131                         p = &(*p)->rb_left;
132                 else if (cmp > 0)
133                         p = &(*p)->rb_right;
134                 else
135                         return; // Already there...
136         }
137
138         this = malloc(sizeof(struct pn_info));
139         this->u.name = strdup(that->name);
140         this->pip = that;
141
142         rb_link_node(&this->rb_node, parent, p);
143         rb_insert_color(&this->rb_node, &root_name);
144 }
145
146 static void insert(struct p_info *pip)
147 {
148         insert_pid(pip, pip->pid);
149         insert_name(pip);
150 }
151
152 static inline struct p_info *pip_alloc(void)
153 {
154         return memset(malloc(sizeof(struct p_info)), 0, sizeof(struct p_info));
155 }
156
157 struct p_info *find_process(__u32 pid, char *name)
158 {
159         struct p_info *pip;
160
161         if (pid != ((__u32)-1)) {
162                 if ((pip = __find_process_pid(pid)) != NULL)
163                         return pip;
164                 else if (name) {
165                         pip = __find_process_name(name);
166
167                         if (pip && pid != pip->pid) {
168                                 /*
169                                  * This is a process with the same name
170                                  * as another, but a different PID.
171                                  *
172                                  * We'll store a reference in the PID
173                                  * tree...
174                                  */
175                                 insert_pid(pip, pid);
176                         }
177                         return pip;
178                 }
179
180                 /*
181                  * We're here because we have a pid, and no name, but
182                  * we didn't find a process ...
183                  *
184                  * We'll craft one using the pid...
185                  */
186
187                 name = alloca(256);
188                 sprintf(name, "pid%09u", pid);
189                 add_process(pid, name);
190                 return __find_process_pid(pid);
191         }
192
193         return __find_process_name(name);
194 }
195
196 void add_process(__u32 pid, char *name)
197 {
198         struct p_info *pip = find_process(pid, name);
199
200         if (pip == NULL) {
201                 pip = pip_alloc();
202                 pip->pid = pid;
203                 region_init(&pip->regions);
204                 pip->last_q = (__u64)-1;
205                 pip->name = strdup(name);
206
207                 insert(pip);
208         }
209 }
210
211 void pip_update_q(struct io *iop)
212 {
213         if (iop->pip) {
214                 if (remapper_dev(iop->dip->device))
215                         update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q_dm,
216                                                                 iop->t.time);
217                 else
218                         update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q,
219                                                                 iop->t.time);
220                 update_qregion(&iop->pip->regions, iop->t.time);
221         }
222 }
223
224 void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *), void *arg)
225 {
226         if (n) {
227                 __foreach(n->rb_left, f, arg);
228                 f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
229                 __foreach(n->rb_right, f, arg);
230         }
231 }
232
233 void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
234 {
235         if (exes == NULL)
236                 __foreach(root_name.rb_node, f, arg);
237         else {
238                 struct p_info *pip;
239                 char *exe, *p, *next, *exes_save = strdup(exes);
240
241                 p = exes_save;
242                 while (exes_save != NULL) {
243                         exe = exes_save;
244                         if ((next = strchr(exes_save, ',')) != NULL) {
245                                 *next = '\0';
246                                 exes_save = next+1;
247                         }
248                         else
249                                 exes_save = NULL;
250
251                         pip = __find_process_name(exe);
252                         if (pip)
253                                 f(pip, arg);
254                 }
255         }
256 }
257
258 void pip_exit(void)
259 {
260         __destroy(root_pid.rb_node, 0, 0);
261         __destroy(root_name.rb_node, 1, 1);
262 }