Merge branch 'master' of ssh://git.kernel.dk/data/git/blktrace
[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 struct p_info * __find_process_pid(__u32 pid)
37 {
38         struct pn_info *this;
39         struct rb_node *n = root_pid.rb_node;
40
41         while (n) {
42                 this = rb_entry(n, struct pn_info, rb_node);
43                 if (pid < this->u.pid)
44                         n = n->rb_left;
45                 else if (pid > this->u.pid)
46                         n = n->rb_right;
47                 else
48                         return this->pip;
49         }
50
51         return NULL;
52 }
53
54 struct p_info *__find_process_name(char *name)
55 {
56         int cmp;
57         struct pn_info *this;
58         struct rb_node *n = root_name.rb_node;
59
60         while (n) {
61                 this = rb_entry(n, struct pn_info, rb_node);
62                 cmp = strcmp(name, this->u.name);
63                 if (cmp < 0)
64                         n = n->rb_left;
65                 else if (cmp > 0)
66                         n = n->rb_right;
67                 else
68                         return this->pip;
69         }
70
71         return NULL;
72 }
73
74 struct p_info *find_process(__u32 pid, char *name)
75 {
76         struct p_info *pip;
77
78         if (pid != ((__u32)-1) && ((pip = __find_process_pid(pid)) != NULL))
79                 return pip;
80
81         if (name)
82                 return __find_process_name(name);
83
84         return NULL;
85 }
86
87 static void insert_pid(struct p_info *that)
88 {
89         struct pn_info *this;
90         struct rb_node *parent = NULL;
91         struct rb_node **p = &root_pid.rb_node;
92
93         while (*p) {
94                 parent = *p;
95                 this = rb_entry(parent, struct pn_info, rb_node);
96
97                 if (that->pid < this->u.pid)
98                         p = &(*p)->rb_left;
99                 else if (that->pid > this->u.pid)
100                         p = &(*p)->rb_right;
101                 else {
102                         ASSERT(strcmp(that->name, this->pip->name) == 0);
103                         return; // Already there
104                 }
105         }
106
107         this = malloc(sizeof(struct pn_info));
108         this->u.pid = that->pid;
109         this->pip = that;
110
111         rb_link_node(&this->rb_node, parent, p);
112         rb_insert_color(&this->rb_node, &root_pid);
113 }
114
115 static void insert_name(struct p_info *that)
116 {
117         int cmp;
118         struct pn_info *this;
119         struct rb_node *parent = NULL;
120         struct rb_node **p = &root_name.rb_node;
121
122         while (*p) {
123                 parent = *p;
124                 this = rb_entry(parent, struct pn_info, rb_node);
125                 cmp = strcmp(that->name, this->u.name);
126
127                 if (cmp < 0)
128                         p = &(*p)->rb_left;
129                 else if (cmp > 0)
130                         p = &(*p)->rb_right;
131                 else
132                         return; // Already there...
133         }
134
135         this = malloc(sizeof(struct pn_info));
136         this->u.name = strdup(that->name);
137         this->pip = that;
138
139         rb_link_node(&this->rb_node, parent, p);
140         rb_insert_color(&this->rb_node, &root_name);
141 }
142
143 static void insert(struct p_info *pip)
144 {
145         insert_pid(pip);
146         insert_name(pip);
147 }
148
149 void add_process(__u32 pid, char *name)
150 {
151         struct p_info *pip = find_process(pid, name);
152
153         if (pip == NULL) {
154                 size_t len = sizeof(struct p_info) + strlen(name) + 1;
155
156                 pip = memset(malloc(len), 0, len);
157                 pip->pid = pid;
158                 init_region(&pip->regions);
159                 pip->last_q = (__u64)-1;
160                 strcpy(pip->name, name);
161
162                 insert(pip);
163         }
164 }
165
166 void pip_update_q(struct io *iop)
167 {
168         if (iop->pip) {
169                 update_lq(&iop->pip->last_q, &iop->pip->avgs.q2q, iop->t.time);
170                 update_qregion(&iop->pip->regions, iop->t.time);
171         }
172 }
173
174 void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *), void *arg)
175 {
176         if (n) {
177                 __foreach(n->rb_left, f, arg);
178                 f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
179                 __foreach(n->rb_right, f, arg);
180         }
181 }
182
183 void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
184 {
185         if (exes == NULL)
186                 __foreach(root_name.rb_node, f, arg);
187         else {
188                 struct p_info *pip;
189                 char *exe, *p, *next, *exes_save = strdup(exes);
190
191                 p = exes_save;
192                 while (exes_save != NULL) {
193                         exe = exes_save;
194                         if ((next = strchr(exes_save, ',')) != NULL) {
195                                 *next = '\0';
196                                 exes_save = next+1;
197                         }
198                         else
199                                 exes_save = NULL;
200
201                         pip = __find_process_name(exe);
202                         if (pip)
203                                 f(pip, arg);
204                 }
205         }
206 }