Major revamping (ver 2.0)
[blktrace.git] / btt / inlines.h
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
22 static inline void region_init(struct region_info *reg)
23 {
24         INIT_LIST_HEAD(&reg->qranges);
25         INIT_LIST_HEAD(&reg->cranges);
26 }
27
28 static inline void __region_exit(struct list_head *range_head)
29 {
30         struct list_head *p, *q;
31         struct range_info *rip;
32
33         list_for_each_safe(p, q, range_head) {
34                 rip = list_entry(p, struct range_info, head);
35                 free(rip);
36         }
37 }
38
39 static inline void region_exit(struct region_info *reg)
40 {
41         __region_exit(&reg->qranges);
42         __region_exit(&reg->cranges);
43 }
44
45 static inline void update_range(struct list_head *head_p, __u64 time)
46 {
47         struct range_info *rip;
48
49         if (!list_empty(head_p)) {
50                 rip = list_entry(head_p->prev, struct range_info, head);
51
52                 if (time < rip->end)
53                         return;
54
55                 if (BIT_TIME(time - rip->end) < range_delta) {
56                         rip->end = time;
57                         return;
58                 }
59         }
60
61         rip = malloc(sizeof(*rip));
62         rip->start = rip->end = time;
63         list_add_tail(&rip->head, head_p);
64 }
65
66 static inline void update_qregion(struct region_info *reg, __u64 time)
67 {
68         update_range(&reg->qranges, time);
69 }
70
71 static inline void update_cregion(struct region_info *reg, __u64 time)
72 {
73         update_range(&reg->cranges, time);
74 }
75
76 static inline void avg_update(struct avg_info *ap, __u64 t)
77 {
78         if (ap->n++ == 0)
79                 ap->min = ap->total = ap->max = t;
80         else {
81                 if (t < ap->min)
82                         ap->min = t;
83                 else if (t > ap->max)
84                         ap->max = t;
85                 ap->total += t;
86         }
87 }
88
89 static inline void avg_update_n(struct avg_info *ap, __u64 t, int n)
90 {
91         if (ap->n == 0) {
92                 ap->min = ap->max = t;
93                 ap->total = (n * t);
94         }
95         else {
96                 if (t < ap->min)
97                         ap->min = t;
98                 else if (t > ap->max)
99                         ap->max = t;
100                 ap->total += (n * t);
101         }
102
103         ap->n += n;
104 }
105
106 static inline void avg_unupdate(struct avg_info *ap, __u64 t)
107 {
108         ap->n--;
109         ap->total -= t;
110 }
111
112 static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
113 {
114         if (*last_q != ((__u64)-1))
115                 avg_update(avg, (time > *last_q) ? time - *last_q : 1);
116         *last_q = time;
117 }
118
119 static inline void dip_update_q(struct d_info *dip, struct io *iop)
120 {
121         update_lq(&dip->last_q, &dip->avgs.q2q, iop->t.time);
122         update_qregion(&dip->regions, iop->t.time);
123 }
124
125 static inline struct io *io_alloc(void)
126 {
127         struct io *iop;
128
129         if (!list_empty(&free_ios)) {
130                 iop = list_entry(free_ios.prev, struct io, f_head);
131                 LIST_DEL(&iop->f_head);
132
133 #               if defined(COUNT_IOS)
134                         nios_reused++;
135 #               endif
136         }
137         else {
138                 iop = malloc(sizeof(struct io));
139
140 #               if defined(COUNT_IOS)
141                         nios_alloced++;
142 #               endif
143         }
144
145         memset(iop, 0, sizeof(struct io));
146
147 #       if defined(DEBUG)
148                 iop->f_head.next = LIST_POISON1;
149 #       endif
150
151 #       if defined(COUNT_IOS)
152                 list_add_tail(&iop->cio_head, &cios);
153 #       endif
154
155         return iop;
156 }
157
158 static inline void io_free(struct io *iop)
159 {
160 #       if defined(COUNT_IOS)
161                 nios_freed++;
162                 LIST_DEL(&iop->cio_head);
163 #       endif
164
165 #       if defined(DEBUG)
166                 memset(iop, 0, sizeof(*iop));
167 #       endif
168
169         list_add_tail(&iop->f_head, &free_ios);
170 }
171
172 static inline void io_free_all(void)
173 {
174         struct io *iop;
175         struct list_head *p, *q;
176
177         list_for_each_safe(p, q, &free_ios) {
178                 iop = list_entry(p, struct io, f_head);
179                 free(iop);
180         }
181 }
182
183 static inline int io_setup(struct io *iop, enum iop_type type)
184 {
185         iop->type = type;
186         iop->dip = dip_add(iop->t.device, iop);
187         if (iop->linked) {
188                 iop->pip = find_process(iop->t.pid, NULL);
189                 iop->bytes_left = iop->t.bytes;
190         }
191
192         return iop->linked;
193 }
194
195 static inline void io_release(struct io *iop)
196 {
197         ASSERT(iop->f_head.next == LIST_POISON1);
198
199         if (iop->linked)
200                 dip_rem(iop);
201         if (iop->pdu) 
202                 free(iop->pdu);
203
204         io_free(iop);
205 }
206
207 #define UPDATE_AVGS(_avg, _iop, _pip, _time) do {                       \
208                 avg_update(&all_avgs. _avg , _time);                    \
209                 avg_update(&_iop->dip->avgs. _avg , _time);             \
210                 if (_pip) avg_update(&_pip->avgs. _avg , _time);        \
211         } while (0)
212
213 #define UPDATE_AVGS_N(_avg, _iop, _pip, _time, _n) do {                 \
214                 avg_update_n(&all_avgs. _avg , _time, _n);              \
215                 avg_update_n(&_iop->dip->avgs. _avg , _time, _n);       \
216                 if (_pip) avg_update_n(&_pip->avgs. _avg , _time,_n);   \
217         } while (0)
218
219 #define UNUPDATE_AVGS(_avg, _iop, _pip, _time) do {                     \
220                 avg_unupdate(&all_avgs. _avg , _time);                  \
221                 avg_unupdate(&_iop->dip->avgs. _avg , _time);           \
222                 if (_pip) avg_unupdate(&_pip->avgs. _avg , _time);      \
223         } while (0)
224
225 static inline void update_q2c(struct io *iop, __u64 c_time)
226 {
227 #       if defined(DEBUG)
228                 if (per_io_ofp) 
229                         fprintf(per_io_ofp, "q2c %13.9f\n", BIT_TIME(c_time));
230 #       endif
231         UPDATE_AVGS(q2c, iop, iop->pip, c_time);
232 }
233
234 static inline void update_q2a(struct io *iop, __u64 a_time)
235 {
236 #       if defined(DEBUG)
237                 if (per_io_ofp) 
238                         fprintf(per_io_ofp, "q2a %13.9f\n", BIT_TIME(a_time));
239 #       endif
240         UPDATE_AVGS(q2a, iop, iop->pip, a_time);
241 }
242
243 static inline void update_q2i(struct io *iop, __u64 i_time)
244 {
245 #       if defined(DEBUG)
246                 if (per_io_ofp) 
247                         fprintf(per_io_ofp, "q2i %13.9f\n", BIT_TIME(i_time));
248 #       endif
249
250         UPDATE_AVGS(q2i, iop, iop->pip, i_time);
251 }
252
253 static inline void unupdate_q2i(struct io *iop, __u64 i_time)
254 {
255         UNUPDATE_AVGS(q2i, iop, iop->pip, i_time);
256 }
257
258 static inline void update_i2d(struct io *iop, __u64 d_time)
259 {
260 #       if defined(DEBUG)
261                 if (per_io_ofp) 
262                         fprintf(per_io_ofp, "i2d %13.9f\n", BIT_TIME(d_time));
263 #       endif
264
265         UPDATE_AVGS(i2d, iop, iop->pip, d_time);
266 }
267
268 static inline void unupdate_i2d(struct io *iop, __u64 d_time)
269 {
270         UNUPDATE_AVGS(i2d, iop, iop->pip, d_time);
271 }
272
273 static inline void update_d2c(struct io *iop, __u64 c_time)
274 {
275 #       if defined(DEBUG)
276                 if (per_io_ofp) 
277                         fprintf(per_io_ofp, "d2c %13.9f\n", BIT_TIME(c_time));
278 #       endif
279
280         UPDATE_AVGS(d2c, iop, iop->pip, c_time);
281 }
282
283 static inline void update_blks(struct io *iop)
284 {
285         __u64 nblks = iop->t.bytes >> 9;
286         avg_update(&all_avgs.blks, nblks);
287         ASSERT(iop->dip != NULL);
288         avg_update(&iop->dip->avgs.blks, nblks);
289         if (iop->pip)
290                 avg_update(&iop->pip->avgs.blks, nblks);
291 }
292
293 static inline struct rb_root *__get_root(struct d_info *dip, enum iop_type type)
294 {
295         struct rb_root *roots = dip->heads;
296         return &roots[type];
297 }
298
299 static inline int dip_rb_ins(struct d_info *dip, struct io *iop)
300 {
301         return rb_insert(__get_root(dip, iop->type), iop);
302 }
303
304 static inline void dip_rb_rem(struct io *iop)
305 {
306         rb_erase(&iop->rb_node, __get_root(iop->dip, iop->type));
307
308 #       if defined(DEBUG)
309                 rb_tree_size--;
310 #       endif
311 }
312
313 static inline void dip_rb_fe(struct d_info *dip, enum iop_type type, 
314                              struct io *iop, 
315                              void (*fnc)(struct io *iop, struct io *this), 
316                              struct list_head *head)
317 {
318         rb_foreach(__get_root(dip, type)->rb_node, iop, fnc, head);
319 }
320
321 static inline struct io *dip_rb_find_sec(struct d_info *dip, 
322                                          enum iop_type type, __u64 sec)
323 {
324         return rb_find_sec(__get_root(dip, type), sec);
325 }
326
327 static inline __u64 tdelta(__u64 from, __u64 to)
328 {
329         return (from < to) ? (to - from) : 1;
330 }
331
332 static inline int remapper_dev(__u32 dev)
333 {
334         int mjr = MAJOR(dev);
335         return mjr == 9 || mjr == 253 || mjr == 254;
336 }
337
338 static inline int type2c(enum iop_type type)
339 {
340         int c;
341
342         switch (type) {
343         case IOP_Q: c = 'Q'; break;
344         case IOP_X: c = 'X'; break;
345         case IOP_A: c = 'A'; break;
346         case IOP_I: c = 'I'; break;
347         case IOP_M: c = 'M'; break;
348         case IOP_D: c = 'D'; break;
349         case IOP_C: c = 'C'; break;
350         case IOP_R: c = 'R'; break;
351         case IOP_G: c = 'G'; break;
352         default   : c = '?'; break;
353         }
354
355         return c;
356 }
357
358 static inline int histo_idx(__u64 nbytes)
359 {
360         int idx = (nbytes >> 9) - 1;
361         return min(idx, N_HIST_BKTS-1);
362 }
363
364 static inline void update_q_histo(__u64 nbytes)
365 {
366         q_histo[histo_idx(nbytes)]++;
367 }
368
369 static inline void update_d_histo(__u64 nbytes)
370 {
371         d_histo[histo_idx(nbytes)]++;
372 }
373
374 static inline struct io *io_first_list(struct list_head *head)
375 {
376         if (list_empty(head))
377                 return NULL;
378
379         return list_entry(head->next, struct io, f_head);
380 }
381
382 static inline void __dump_iop(FILE *ofp, struct io *iop, int extra_nl)
383 {
384         fprintf(ofp, "%5d.%09lu %3d,%-3d %c %10llu+%-4u\n",
385                 (int)SECONDS(iop->t.time),
386                 (unsigned long)NANO_SECONDS(iop->t.time),
387                 MAJOR(iop->t.device), MINOR(iop->t.device), type2c(iop->type),
388                 (unsigned long long)iop->t.sector, t_sec(&iop->t));
389         if (extra_nl) fprintf(ofp, "\n");
390 }
391
392 static inline void __dump_iop2(FILE *ofp, struct io *a_iop, struct io *l_iop)
393 {
394         fprintf(ofp, "%5d.%09lu %3d,%-3d %c %10llu+%-4u <- (%3d,%-3d) %10llu\n",
395                 (int)SECONDS(a_iop->t.time),
396                 (unsigned long)NANO_SECONDS(a_iop->t.time),
397                 MAJOR(a_iop->t.device), MINOR(a_iop->t.device), 
398                 type2c(a_iop->type), (unsigned long long)a_iop->t.sector, 
399                 t_sec(&a_iop->t), MAJOR(l_iop->t.device), 
400                 MINOR(l_iop->t.device), (unsigned long long)l_iop->t.sector);
401 }