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
__foreach(struct rb_node * n,void (* f)(struct p_info *,void *),void * arg)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
__destroy(struct rb_node * n,int free_name,int free_pip)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
__find_process_pid(__u32 pid)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
__find_process_name(char * name)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
insert_pid(struct p_info * that,__u32 pid)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
insert_name(struct p_info * that)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
insert(struct p_info * pip)157 static void insert(struct p_info *pip)
158 {
159 insert_pid(pip, pip->pid);
160 insert_name(pip);
161 }
162
pip_alloc(void)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
find_process(__u32 pid,char * name)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
process_alloc(__u32 pid,char * name)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
pip_update_q(struct io * iop)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
pip_foreach_out(void (* f)(struct p_info *,void *),void * arg)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
pip_exit(void)259 void pip_exit(void)
260 {
261 __destroy(root_pid.rb_node, 0, 0);
262 __destroy(root_name.rb_node, 1, 1);
263 }
264