Merge branch 'fix-m' into add-P
[blktrace.git] / btt / proc.c
CommitLineData
63eba147
JA
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
6eb42155
ADB
25struct 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
34struct rb_root root_pid, root_name;
63eba147 35
69040794
AB
36static 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
6eb42155 54struct p_info * __find_process_pid(__u32 pid)
63eba147 55{
6eb42155
ADB
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 }
63eba147 68
6eb42155 69 return NULL;
63eba147
JA
70}
71
6eb42155 72struct p_info *__find_process_name(char *name)
63eba147 73{
6eb42155
ADB
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;
63eba147
JA
87 }
88
89 return NULL;
90}
91
4c48f14e 92static void insert_pid(struct p_info *that, __u32 pid)
63eba147 93{
6eb42155
ADB
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
4c48f14e 102 if (pid < this->u.pid)
6eb42155 103 p = &(*p)->rb_left;
4c48f14e 104 else if (pid > this->u.pid)
6eb42155 105 p = &(*p)->rb_right;
8b10aae0 106 else
6eb42155 107 return; // Already there
6eb42155
ADB
108 }
109
110 this = malloc(sizeof(struct pn_info));
4c48f14e 111 this->u.pid = pid;
6eb42155
ADB
112 this->pip = that;
113
114 rb_link_node(&this->rb_node, parent, p);
115 rb_insert_color(&this->rb_node, &root_pid);
63eba147
JA
116}
117
6eb42155 118static void insert_name(struct p_info *that)
63eba147 119{
6eb42155
ADB
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 }
63eba147 137
6eb42155
ADB
138 this = malloc(sizeof(struct pn_info));
139 this->u.name = strdup(that->name);
140 this->pip = that;
63eba147 141
6eb42155
ADB
142 rb_link_node(&this->rb_node, parent, p);
143 rb_insert_color(&this->rb_node, &root_name);
144}
63eba147 145
6eb42155
ADB
146static void insert(struct p_info *pip)
147{
4c48f14e 148 insert_pid(pip, pip->pid);
6eb42155 149 insert_name(pip);
63eba147
JA
150}
151
4c48f14e
AB
152static inline struct p_info *pip_alloc(void)
153{
154 return memset(malloc(sizeof(struct p_info)), 0, sizeof(struct p_info));
155}
156
157struct 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
8b10aae0 182 * we didn't find a process ...
4c48f14e
AB
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
4c48f14e
AB
193 return __find_process_name(name);
194}
195
63eba147
JA
196void add_process(__u32 pid, char *name)
197{
198 struct p_info *pip = find_process(pid, name);
199
200 if (pip == NULL) {
4c48f14e 201 pip = pip_alloc();
6eb42155 202 pip->pid = pid;
69040794 203 region_init(&pip->regions);
6eb42155 204 pip->last_q = (__u64)-1;
69040794 205 pip->name = strdup(name);
6eb42155 206
4c48f14e 207 insert(pip);
63eba147
JA
208 }
209}
210
211void pip_update_q(struct io *iop)
212{
213 if (iop->pip) {
ae6d30f4 214 if (remapper_dev(iop->dip->device))
8b10aae0 215 update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q_dm,
ae6d30f4
AB
216 iop->t.time);
217 else
8b10aae0 218 update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q,
ae6d30f4 219 iop->t.time);
63eba147
JA
220 update_qregion(&iop->pip->regions, iop->t.time);
221 }
222}
6eb42155
ADB
223
224void __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
233void 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}
69040794
AB
257
258void pip_exit(void)
259{
260 __destroy(root_pid.rb_node, 0, 0);
261 __destroy(root_name.rb_node, 1, 1);
262}