Add in the notion of pre-culling IOs per device until a Q is hit.
[blktrace.git] / btt / devs.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 <stdio.h>
22 #include "globals.h"
23
24 #define N_DEV_HASH      128
25 #define DEV_HASH(dev)   ((MAJOR(dev) ^ MINOR(dev)) & (N_DEV_HASH - 1))
26 struct list_head        dev_heads[N_DEV_HASH];
27
28 #if defined(DEBUG)
29 void __dump_rb_node(struct rb_node *n)
30 {
31         struct io *iop = rb_entry(n, struct io, rb_node);
32
33         dbg_ping();
34         if (iop->type == IOP_A)
35                 __dump_iop2(stdout, iop, bilink_first_down(iop, NULL));
36         else
37                 __dump_iop(stdout, iop, 0);
38         if (n->rb_left)
39                 __dump_rb_node(n->rb_left);
40         if (n->rb_right)
41                 __dump_rb_node(n->rb_right);
42 }
43
44 void __dump_rb_tree(struct d_info *dip, enum iop_type type)
45 {
46         struct rb_root *roots = dip->heads;
47         struct rb_root *root = &roots[type];
48         struct rb_node *n = root->rb_node;
49
50         if (n) {
51                 printf("\tIOP_%c\n", type2c(type));
52                 __dump_rb_node(n);
53         }
54 }
55
56 void dump_rb_trees(void)
57 {
58         int i;
59         enum iop_type type;
60         struct d_info *dip;
61         struct list_head *p;
62
63         for (i = 0; i < N_DEV_HASH; i++) {
64                 __list_for_each(p, &dev_heads[i]) {
65                         dip = list_entry(p, struct d_info, hash_head);
66                         printf("Trees for %3d,%-3d\n", MAJOR(dip->device),
67                                MINOR(dip->device));
68                         for (type = IOP_Q; type < N_IOP_TYPES; type++) {
69                                 if (type != IOP_L)
70                                         __dump_rb_tree(dip, type);
71                         }
72                 }
73         }
74 }
75 #endif
76
77 void init_dev_heads(void)
78 {
79         int i;
80         for (i = 0; i < N_DEV_HASH; i++)
81                 INIT_LIST_HEAD(&dev_heads[i]);
82 }
83
84 struct d_info *__dip_find(__u32 device)
85 {
86         struct d_info *dip;
87         struct list_head *p;
88
89         __list_for_each(p, &dev_heads[DEV_HASH(device)]) {
90                 dip = list_entry(p, struct d_info, hash_head);
91                 if (device == dip->device)
92                         return dip;
93         }
94
95         return NULL;
96 }
97
98 struct d_info *dip_add(__u32 device, struct io *iop)
99 {
100         struct d_info *dip = __dip_find(device);
101
102         if (dip == NULL) {
103                 dip = malloc(sizeof(struct d_info));
104                 memset(dip, 0, sizeof(*dip));
105                 dip->heads = dip_rb_mkhds();
106                 init_region(&dip->regions);
107                 dip->device = device;
108                 dip->last_q = (__u64)-1;
109                 dip->map = dev_map_find(device);
110                 dip->seek_handle = seeki_init(device);
111                 latency_init(dip);
112                 list_add_tail(&dip->hash_head, &dev_heads[DEV_HASH(device)]);
113                 list_add_tail(&dip->all_head, &all_devs);
114                 dip->start_time = BIT_TIME(iop->t.time);
115                 dip->pre_culling = 1;
116                 n_devs++;
117         }
118
119         if (dip->pre_culling) {
120                 if (iop->type == IOP_Q || iop->type == IOP_A)
121                         dip->pre_culling = 0;
122                 else
123                         return NULL;
124         }
125
126         iop->linked = dip_rb_ins(dip, iop);
127 #if defined(DEBUG)
128         if (iop->linked) 
129                 rb_tree_size++;
130 #endif
131
132         dip->end_time = BIT_TIME(iop->t.time);
133         return dip;
134 }
135
136 void dip_rem(struct io *iop)
137 {
138         if (iop->linked) {
139                 dip_rb_rem(iop);
140                 iop->linked = 0;
141         }
142 }
143
144 void dip_foreach(struct io *iop, enum iop_type type, 
145                  void (*fnc)(struct io *iop, struct io *this), int rm_after)
146 {
147         if (rm_after) {
148                 LIST_HEAD(head);
149                 struct io *this;
150                 struct list_head *p, *q;
151
152                 dip_rb_fe(iop->dip, type, iop, fnc, &head);
153                 list_for_each_safe(p, q, &head) {
154                         this = list_entry(p, struct io, f_head);
155                         LIST_DEL(&this->f_head);
156                         io_release(this);
157                 }
158         }
159         else
160                 dip_rb_fe(iop->dip, type, iop, fnc, NULL);
161 }
162
163 void dip_foreach_list(struct io *iop, enum iop_type type, struct list_head *hd)
164 {
165         dip_rb_fe(iop->dip, type, iop, NULL, hd);
166 }
167
168 struct io *dip_find_sec(struct d_info *dip, enum iop_type type, __u64 sec)
169 {
170         return dip_rb_find_sec(dip, type, sec);
171 }
172
173 void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg)
174 {
175         if (devices == NULL) {
176                 struct list_head *p;
177                 __list_for_each(p, &all_devs)
178                         func(list_entry(p, struct d_info, all_head), arg);
179         }
180         else {
181                 int i;
182                 struct d_info *dip;
183                 unsigned int mjr, mnr;
184                 char *p = devices;
185
186                 while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
187                         dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
188                         ASSERT(dip);
189
190                         func(dip, arg);
191
192                         p = strchr(p, ';');
193                         if (p) p++;
194                 }
195         }
196 }
197
198 void dip_plug(__u32 dev, double cur_time)
199 {
200         struct d_info *dip = __dip_find(dev);
201
202         if (!dip || dip->is_plugged) return;
203
204         dip->is_plugged = 1;
205         dip->last_plug = cur_time;
206 }
207
208 void dip_unplug(__u32 dev, double cur_time, int is_timer)
209 {
210         struct d_info *dip = __dip_find(dev);
211
212         if (!dip || !dip->is_plugged) return;
213
214         dip->nplugs++;
215         if (is_timer) dip->n_timer_unplugs++;
216
217         dip->plugged_time += (cur_time - dip->last_plug);
218         dip->is_plugged = 0;
219 }