4a763b5872e5e928c5aead50d3a2cc24e919e5b6
[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 struct range_info *new_cur(__u64 time)
23 {
24         struct range_info *cur = malloc(sizeof(struct range_info));
25
26         INIT_LIST_HEAD(&cur->head);
27         cur->start = time;
28         return cur;
29 }
30
31 static inline void update_range(struct list_head *head_p,
32                                 struct range_info **cur_p, __u64 time)
33 {
34         if (*cur_p == NULL)
35                 *cur_p = new_cur(time);
36         else {
37                 __u64 my_delta = (time > (*cur_p)->end) ? time - (*cur_p)->end : 1;
38                 if (BIT_TIME(my_delta) >= range_delta) {
39                         list_add_tail(&(*cur_p)->head, head_p);
40                         *cur_p = new_cur(time);
41                 }
42         }
43
44         (*cur_p)->end = time;
45 }
46
47 static inline void init_region(struct region_info *reg)
48 {
49         INIT_LIST_HEAD(&reg->qranges);
50         INIT_LIST_HEAD(&reg->cranges);
51         reg->qr_cur = reg->cr_cur = NULL;
52 }
53
54 static inline void update_qregion(struct region_info *reg, __u64 time)
55 {
56         update_range(&reg->qranges, &reg->qr_cur, time);
57 }
58
59 static inline void update_cregion(struct region_info *reg, __u64 time)
60 {
61         update_range(&reg->cranges, &reg->cr_cur, time);
62 }
63
64 static inline void avg_update(struct avg_info *ap, __u64 t)
65 {
66         if (ap->n++ == 0)
67                 ap->min = ap->total = ap->max = t;
68         else {
69                 if (t < ap->min)
70                         ap->min = t;
71                 else if (t > ap->max)
72                         ap->max = t;
73                 ap->total += t;
74         }
75 }
76
77 static inline void avg_unupdate(struct avg_info *ap, __u64 t)
78 {
79         ap->n--;
80         ap->total -= t;
81 }
82
83 static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
84 {
85         if (*last_q != ((__u64)-1))
86                 avg_update(avg, (time > *last_q) ? time - *last_q : 1);
87         *last_q = time;
88 }
89
90 static inline void dip_update_q(struct d_info *dip, struct io *iop)
91 {
92         update_lq(&dip->last_q, &dip->avgs.q2q, iop->t.time);
93         update_qregion(&dip->regions, iop->t.time);
94 }
95
96 static inline struct io *io_alloc(void)
97 {
98         struct io *iop;
99
100         if (!list_empty(&free_ios)) {
101                 iop = list_entry(free_ios.next, struct io, f_head);
102                 LIST_DEL(&iop->f_head);
103         }
104         else
105                 iop = malloc(sizeof(struct io));
106
107         memset(iop, 0, sizeof(struct io));
108
109         return iop;
110 }
111
112 static inline void io_free(struct io *iop)
113 {
114 #       if defined(DEBUG)
115                 memset(iop, 0, sizeof(*iop));
116 #       endif
117         list_add_tail(&iop->f_head, &free_ios);
118 }
119
120 static inline int io_setup(struct io *iop, enum iop_type type)
121 {
122         iop->type = type;
123         iop->dip = dip_add(iop->t.device, iop);
124         if (iop->linked) {
125                 iop->pip = find_process(iop->t.pid, NULL);
126                 INIT_LIST_HEAD(&iop->down_list);
127                 INIT_LIST_HEAD(&iop->up_list);
128                 iop->bytes_left = iop->t.bytes;
129         }
130
131         return iop->linked;
132 }
133
134 static inline void io_release(struct io *iop)
135 {
136         if (iop->linked)
137                 dip_rem(iop);
138         if (iop->pdu) 
139                 free(iop->pdu);
140         io_free(iop);
141 }
142
143 #define UPDATE_AVGS(_avg, _iop, _pip, _time) do {                       \
144                 avg_update(&all_avgs. _avg , _time);                    \
145                 avg_update(&_iop->dip->avgs. _avg , _time);             \
146                 if (_pip) avg_update(&_pip->avgs. _avg , _time);        \
147         } while (0)
148
149 #define UNUPDATE_AVGS(_avg, _iop, _pip, _time) do {                     \
150                 avg_unupdate(&all_avgs. _avg , _time);                  \
151                 avg_unupdate(&_iop->dip->avgs. _avg , _time);           \
152                 if (_pip) avg_unupdate(&_pip->avgs. _avg , _time);      \
153         } while (0)
154
155 static inline void update_q2c(struct io *iop, __u64 c_time)
156 {
157         UPDATE_AVGS(q2c, iop, iop->pip, c_time);
158 }
159
160 static inline void update_q2a(struct io *iop, __u64 a_time)
161 {
162         UPDATE_AVGS(q2a, iop, iop->pip, a_time);
163 }
164
165 static inline void update_q2i(struct io *iop, __u64 i_time)
166 {
167         UPDATE_AVGS(q2i, iop, iop->pip, i_time);
168 }
169
170 static inline void update_i2d(struct io *iop, __u64 d_time)
171 {
172         UPDATE_AVGS(i2d, iop, iop->pip, d_time);
173 }
174
175 static inline void unupdate_i2d(struct io *iop, __u64 d_time)
176 {
177         UNUPDATE_AVGS(i2d, iop, iop->pip, d_time);
178 }
179
180 static inline void update_d2c(struct io *iop, __u64 c_time)
181 {
182         UPDATE_AVGS(d2c, iop, iop->pip, c_time);
183 }
184
185 static inline void update_blks(struct io *iop)
186 {
187         __u64 nblks = iop->t.bytes >> 9;
188         avg_update(&all_avgs.blks, nblks);
189         ASSERT(iop->dip != NULL);
190         avg_update(&iop->dip->avgs.blks, nblks);
191         if (iop->pip)
192                 avg_update(&iop->pip->avgs.blks, nblks);
193 }
194
195 static inline struct rb_root *__get_root(struct d_info *dip, enum iop_type type)
196 {
197         struct rb_root *roots = dip->heads;
198         return &roots[type];
199 }
200
201 static inline void *dip_rb_mkhds(void)
202 {
203         size_t len = N_IOP_TYPES * sizeof(struct rb_root);
204         return memset(malloc(len), 0, len);
205 }
206
207 static inline int dip_rb_ins(struct d_info *dip, struct io *iop)
208 {
209         return rb_insert(__get_root(dip, iop->type), iop);
210 }
211
212 static inline void dip_rb_rem(struct io *iop)
213 {
214         rb_erase(&iop->rb_node, __get_root(iop->dip, iop->type));
215 }
216
217 static inline void dip_rb_fe(struct d_info *dip, enum iop_type type, 
218                              struct io *iop, 
219                              void (*fnc)(struct io *iop, struct io *this), 
220                              struct list_head *head)
221 {
222         rb_foreach(__get_root(dip, type)->rb_node, iop, fnc, head);
223 }
224
225 static inline struct io *dip_rb_find_sec(struct d_info *dip, 
226                                          enum iop_type type, __u64 sec)
227 {
228         return rb_find_sec(__get_root(dip, type), sec);
229 }
230
231 static inline struct io *list_first_down(struct io *iop)
232 {
233         struct list_head *p = list_first(&iop->down_list);
234         return p ? list_entry(p, struct io, up_head) : NULL;
235 }
236
237 static inline struct io *list_first_up(struct io *iop)
238 {
239         struct list_head *p = list_first(&iop->up_list);
240         return p ? list_entry(p, struct io, down_head) : NULL;
241 }
242
243 static inline int list_empty_up(struct io *iop)
244 {
245         return list_empty(&iop->up_list);
246 }
247
248 static inline void __link(struct io *down_iop, struct io *up_iop)
249 {
250         list_add_tail(&down_iop->up_head, &up_iop->down_list);
251         list_add_tail(&up_iop->down_head, &down_iop->up_list);
252 }
253
254 static inline void __unlink(struct io *down_iop, struct io *up_iop)
255 {
256         LIST_DEL(&down_iop->up_head);
257         LIST_DEL(&up_iop->down_head);
258 }
259
260 static inline void add_retry(struct io *iop)
261 {
262         list_add_tail(&iop->retry, &retries);
263 }
264
265 static inline void del_retry(struct io *iop)
266 {
267         LIST_DEL(&iop->retry);
268 }
269
270 static inline __u64 tdelta(struct io *iop1, struct io *iop2)
271 {
272         __u64 t1 = iop1->t.time;
273         __u64 t2 = iop2->t.time;
274         return (t1 < t2) ? (t2 - t1) : 1;
275 }