[PATCH] Convert to using on-the-fly RB trees, no post-traversal.
authorAlan David Brunelle <Alan.Brunelle@hp.com>
Tue, 3 Oct 2006 12:44:18 +0000 (14:44 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 3 Oct 2006 12:44:18 +0000 (14:44 +0200)
From: Alan D. Brunelle <Alan.Brunelle@hp.com>

- Converted to using RB trees as much as possible - significant speed
  up in general.

- Changed from constructing IO bushes to just doing things inline as we
  get the traces. Significant speed up and reduction in complexity.
  Lost ability to absolutely handle REQUEUE traces (may put out the wrong
  min/max information for certain stats).

- Added btt/dip_rb.c
- Removed btt/traverse.c btt/iofree.c btt/cylist.c
- Fixed message concerning stats & range data to include '.dat'
- Added in timing statistics (K traces per second handled)
- Changed verbose to just update once per second
- Added notions of "foreach" iterators for devices, processes, IO traces, ...
- Removed a lot of redundant code in output (using iterators instead)
- If not interested in seek information, don't calculate a lot of stuff -
  again, significant speed up.

Signed-off-by: Alan D. Brunelle <Alan.Brunelle@hp.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
17 files changed:
btt/Makefile
btt/args.c
btt/bt_timeline.c
btt/cylist.c [deleted file]
btt/devmap.c
btt/devs.c
btt/dip_rb.c [new file with mode: 0644]
btt/globals.h
btt/inlines.h
btt/iofree.c [deleted file]
btt/iostat.c
btt/misc.c
btt/output.c
btt/proc.c
btt/seek.c
btt/trace.c
btt/traverse.c [deleted file]

index df5096b743668f7e35c26256579d9580ef0f8021..830ceda9b60da9eb2ac16da883f41d8f003e00ba 100644 (file)
@@ -8,10 +8,13 @@ PROGS = btt
 #PLIBS = -lpthread
 LIBS   = $(PLIBS) $(ELIBS)
 OBJS   = bt_timeline.o args.o output.o proc.o trace.o misc.o devs.o \
-         traverse.o iofree.o devmap.o cylist.o seek.o iostat.o latency.o
+         devmap.o seek.o iostat.o latency.o dip_rb.o rbtree.o
 
 all: depend $(PROGS)
 
+rbtree.o: ../rbtree.c
+       $(CC) -o $*.o -c $(ALL_CFLAGS) $<
+
 depend:
        @$(CC) -MM $(ALL_CFLAGS) -I.. *.c 1> .depend
 
index 9dcb694cd7f248310a467e6a3668a1ceff0dcc62..c8a79b297d6a31d926f00ece0ce704f8c47a3d3d 100644 (file)
@@ -25,7 +25,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-
 #include "globals.h"
 
 #define S_OPTS "d:D:e:hi:I:l:M:o:q:s:S:Vv"
@@ -144,7 +143,6 @@ static void usage(char *prog)
 void handle_args(int argc, char *argv[])
 {
        int c;
-       char *dev_map_fname = NULL;
 
        while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
                switch (c) {
@@ -152,39 +150,40 @@ void handle_args(int argc, char *argv[])
                        sscanf(optarg, "%lf", &range_delta);
                        break;
                case 'D':
-                       devices = optarg;
+                       devices = strdup(optarg);
                        break;
                case 'e':
-                       exes = optarg;
+                       exes = strdup(optarg);
                        break;
                case 'h':
                        usage(argv[0]);
                        exit(0);
                case 'i':
-                       input_name = optarg;
+                       input_name = strdup(optarg);
                        break;
                case 'l':
-                       d2c_name = optarg;
+                       d2c_name = strdup(optarg);
                        break;
                case 'I':
-                       iostat_name = optarg;
+                       iostat_name = strdup(optarg);
                        break;
                case 'M':
-                       dev_map_fname = optarg;
+                       if (dev_map_read(optarg))
+                               exit(1);
                        break;
                case 'o':
-                       output_name = optarg;
+                       output_name = strdup(optarg);
                        break;
                case 'q':
-                       q2c_name = optarg;
+                       q2c_name = strdup(optarg);
                        break;
                case 's':
-                       seek_name = optarg;
+                       seek_name = strdup(optarg);
                        break;
                case 'S': {
                        unsigned int interval;
                        sscanf(optarg, "%u", &interval);
-                       iostat_interval = (__u64)interval * (1000 * 1000 * 1000);
+                       iostat_interval = (__u64)interval * 1000000000LL;
                        break;
                }
                case 'v':
@@ -210,13 +209,10 @@ void handle_args(int argc, char *argv[])
                exit(1);
        }
 
-       if (dev_map_fname && dev_map_read(dev_map_fname))
-               exit(1);
-
        if (output_name == NULL)
                ranges_ofp = avgs_ofp = stdout;
        else {
-               char *fname = malloc(sizeof(output_name) + 20);
+               char *fname = malloc(strlen(output_name) + 32);
 
                sprintf(fname, "%s.dat", output_name);
                ranges_ofp = fopen(fname, "w");
@@ -225,7 +221,7 @@ void handle_args(int argc, char *argv[])
                        exit(1);
                }
                if (verbose)
-                       printf("Sending range data to %s\n", output_name);
+                       printf("Sending range data to %s.dat\n", output_name);
 
                sprintf(fname, "%s.avg", output_name);
                avgs_ofp = fopen(fname, "w");
@@ -234,7 +230,7 @@ void handle_args(int argc, char *argv[])
                        exit(1);
                }
                if (verbose)
-                       printf("Sending stats data to %s\n", output_name);
+                       printf("Sending stats data to %s.avg\n", output_name);
 
                free(fname);
        }
index 9d07382f17f78ffbdb10a48f878cf4b84f43d6a6..46d8ad170f76fb8b26c12814d6891bb10556f9d6 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
-
 #include "globals.h"
 
 char bt_timeline_version[] = "0.99";
 
-char *devices = NULL;
-char *exes = NULL;
-char *input_name = NULL;
-char *output_name = NULL;
-char *seek_name = NULL;
-char *d2c_name = NULL;
-char *q2c_name = NULL;
+char *devices, *exes, *input_name, *output_name, *seek_name;
+char *d2c_name, *q2c_name;
 double range_delta = 0.1;
 FILE *ranges_ofp, *avgs_ofp;
-int verbose = 0;
-int ifd;
-unsigned long n_traces, n_io_allocs, n_io_frees;
+int ifd, verbose = 0;
+unsigned long n_traces;
 struct avgs_info all_avgs;
 __u64 last_q = (__u64)-1;
-unsigned int pending_xs;
-
 unsigned int n_devs;
+time_t genesis, last_vtrace;
 LIST_HEAD(all_devs);
-LIST_HEAD(all_ios);
 LIST_HEAD(all_procs);
-struct my_mem *free_ios = NULL;
-struct my_mem *free_bits = NULL;
+LIST_HEAD(free_ios);
 
 struct region_info all_regions = {
        .qranges = LIST_HEAD_INIT(all_regions.qranges),
@@ -56,16 +46,13 @@ struct region_info all_regions = {
        .cr_cur = NULL
 };
 
-char iop_map[] = { 'Q', 'X', 'A', 'M', 'I', 'D', 'C', 'Y' };
-
-struct blk_io_trace *convert_to_cpu(struct blk_io_trace *t);
 int process(void);
 
 int main(int argc, char *argv[])
 {
        handle_args(argc, argv);
 
-       cy_init();
+       init_dev_heads();
        iostat_init();
        if (process() || output_avgs(avgs_ofp) || output_ranges(ranges_ofp))
                return 1;
@@ -77,22 +64,22 @@ int process(void)
 {
        int ret = 0;
        struct blk_io_trace *t;
-       struct io *iop = IO_ZALLOC();
+       struct io *iop = io_alloc();
 
-       while (!do_read(ifd, &iop->t, sizeof(iop->t))) {
+       genesis = last_vtrace = time(NULL);
+       while (!do_read(ifd, &iop->t, sizeof(struct blk_io_trace))) {
                t = convert_to_cpu(&iop->t);
                if (t->pdu_len > 0) {
                        iop->pdu = malloc(t->pdu_len);
                        if (do_read(ifd, iop->pdu, t->pdu_len)) {
-                               free(iop->pdu);
                                ret = 1;
                                break;
                        }
                }
                add_trace(iop);
-               iop = IO_ZALLOC();
+               iop = io_alloc();
        }
-       IO_FREE(iop);
+       io_release(iop);
 
        if (iostat_ofp) {
                fprintf(iostat_ofp, "\n");
@@ -102,10 +89,10 @@ int process(void)
        seek_clean();
        latency_clean();
 
-       if (verbose)
-               printf("\n%10lu traces, %10lu mallocs %1lu frees\n",
-                                      n_traces, n_io_allocs, n_io_frees);
+       if (verbose) {
+               double tps = (double)n_traces / (double)(time(NULL) - genesis);
+               printf("%10lu traces @ %.1lf Ktps\n", n_traces, tps/1000.0);
+       }
 
-       cy_shutdown();
        return ret;
 }
diff --git a/btt/cylist.c b/btt/cylist.c
deleted file mode 100644 (file)
index 64fb7c9..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * blktrace output analysis: generate a timeline & gather statistics
- *
- * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-#include "globals.h"
-
-struct cy_list {
-       struct list_head head;
-       struct list_head list;
-};
-
-struct cy_list *pending_cys;
-
-static inline void __rem_cy(struct io_list *iolp)
-{
-       io_unlink(&iolp->iop);
-       if (--iolp->cy_users == 0) {
-               LIST_DEL(&iolp->head);
-               free(iolp);
-       }
-}
-
-void rem_c(struct io *iop)
-{
-       struct list_head *p, *q;
-       struct io_list *iolp;
-
-       ASSERT(iop->type == IOP_C);
-
-       list_for_each_safe(p, q, &pending_cys->list) {
-               iolp = list_entry(p, struct io_list, head);
-
-               if (iolp->iop == iop) {
-                       __rem_cy(iolp);
-                       break;
-               }
-       }
-}
-
-void run_cy_list(struct list_head *list)
-{
-       struct list_head *p, *q;
-       struct io_list *iolp;
-
-       list_for_each_safe(p, q, list) {
-               iolp = list_entry(p, struct io_list, head);
-               traverse(iolp->iop);
-               __rem_cy(iolp);
-       }
-}
-
-void add_cy(struct io *iop)
-{
-       struct io_list *iolp = malloc(sizeof(*iolp));
-
-       ASSERT(iop->type == IOP_C || iop->type == IOP_Y);
-
-       iolp->cy_users = 1;
-       io_link(&iolp->iop, iop);
-
-       list_add_tail(&iolp->head, &pending_cys->list);
-       if (pending_xs == 0)
-               run_cy_list(&pending_cys->list);
-}
-
-void cy_init(void)
-{
-       pending_cys = zmalloc(sizeof(*pending_cys));
-       INIT_LIST_HEAD(&pending_cys->list);
-}
-
-void cy_shutdown(void)
-{
-       ASSERT(list_empty(&pending_cys->list));
-       free(pending_cys);
-}
index 2227617b78dc9fbaf8f0118d75a27a6e2d7041bf..2b6366cf137eb4edc150eed2a49804a1bc13e6bb 100644 (file)
  *
  */
 #include <stdio.h>
-
 #include "globals.h"
+
 struct devmap *all_devmaps = NULL;
+
 void dev_map_add(struct devmap *dmp)
 {
-       struct devmap *this = zmalloc(sizeof(*this));
+       struct devmap *this = malloc(sizeof(struct devmap));
 
        *this = *dmp;
        this->next = all_devmaps;
index 1d41ee9594df0b49118e88e953fc1e60ca101637..bc75dae7e936cd29d3351385801c6c41882fc430 100644 (file)
  *
  */
 #include <stdio.h>
-
 #include "globals.h"
 
 #define N_DEV_HASH     128
 #define DEV_HASH(dev)  ((MAJOR(dev) ^ MINOR(dev)) & (N_DEV_HASH - 1))
-struct list_head       *dev_heads = NULL;
+struct list_head       dev_heads[N_DEV_HASH];
 
-static void init_dev_heads(void)
+void init_dev_heads(void)
 {
        int i;
-
-       dev_heads = zmalloc(N_DEV_HASH * sizeof(struct list_head));
        for (i = 0; i < N_DEV_HASH; i++)
                INIT_LIST_HEAD(&dev_heads[i]);
 }
@@ -40,11 +37,6 @@ struct d_info *__dip_find(__u32 device)
        struct list_head *p;
        struct d_info *dip;
 
-       if (dev_heads == NULL) {
-               init_dev_heads();
-               return NULL;
-       }
-
        __list_for_each(p, &dev_heads[DEV_HASH(device)]) {
                dip = list_entry(p, struct d_info, hash_head);
                if (device == dip->device)
@@ -54,33 +46,82 @@ struct d_info *__dip_find(__u32 device)
        return NULL;
 }
 
-struct d_info *dip_add(__u32 device, struct io *iop)
+struct d_info *dip_add(__u32 device, struct io *iop, int link)
 {
        struct d_info *dip = __dip_find(device);
 
        if (dip == NULL) {
-               int i;
-
-               dip = zmalloc(sizeof(*dip));
+               dip = malloc(sizeof(struct d_info));
+               dip->heads = dip_rb_mkhds();
+               init_region(&dip->regions);
                dip->device = device;
                dip->last_q = (__u64)-1;
-               for (i = 0; i < N_IOP_TYPES; i++)
-                       INIT_LIST_HEAD(&dip->iop_heads[i]);
-               init_region(&dip->regions);
                dip->map = dev_map_find(device);
                dip->seek_handle = seeki_init(device);
                latency_init(dip);
                memset(&dip->stats, 0, sizeof(dip->stats));
                memset(&dip->all_stats, 0, sizeof(dip->all_stats));
-
-               if (dev_heads == NULL) init_dev_heads();
                list_add_tail(&dip->hash_head, &dev_heads[DEV_HASH(device)]);
-
-               list_add_tail(&dip->head, &all_devs);
+               list_add_tail(&dip->all_head, &all_devs);
                n_devs++;
        }
 
-       list_add(&iop->dev_head, dip_get_head(dip, iop->type));
+       if (link)
+               dip_rb_ins(dip, iop);
 
        return dip;
 }
+
+void dip_rem(struct io *iop)
+{
+       dip_rb_rem(iop);
+}
+
+void dip_foreach(struct io *iop, enum iop_type type, 
+                void (*fnc)(struct io *iop, struct io *this), int rm_after)
+{
+       if (rm_after) {
+               LIST_HEAD(head);
+               struct io *this;
+               struct list_head *p, *q;
+
+               dip_rb_fe(iop->dip, type, iop, fnc, &head);
+               list_for_each_safe(p, q, &head) {
+                       this = list_entry(p, struct io, f_head);
+                       LIST_DEL(&this->f_head);
+                       io_release(this);
+               }
+       }
+       else
+               dip_rb_fe(iop->dip, type, iop, fnc, NULL);
+}
+
+struct io *dip_find_sec(struct d_info *dip, enum iop_type type, __u64 sec)
+{
+       return dip_rb_find_sec(dip, type, sec);
+}
+
+void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg)
+{
+       if (devices == NULL) {
+               struct list_head *p;
+               __list_for_each(p, &all_devs)
+                       func(list_entry(p, struct d_info, all_head), arg);
+       }
+       else {
+               int i;
+               struct d_info *dip;
+               unsigned int mjr, mnr;
+               char *p = devices;
+
+               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
+                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
+                       ASSERT(dip);
+
+                       func(dip, arg);
+
+                       p = strchr(p, ';');
+                       if (p) p++;
+               }
+       }
+}
diff --git a/btt/dip_rb.c b/btt/dip_rb.c
new file mode 100644 (file)
index 0000000..6ff09df
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * blktrace output analysis: generate a timeline & gather statistics
+ *
+ * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <stdio.h>
+#include "globals.h"
+
+void rb_insert(struct rb_root *root, struct io *iop)
+{
+       struct io *__iop;
+       struct rb_node *parent = NULL;
+       struct rb_node **p = &root->rb_node;
+       __u64 __s, s = BIT_START(iop);
+
+       ASSERT(root != NULL && iop != NULL);
+       while (*p) {
+               parent = *p;
+               __iop = rb_entry(parent, struct io, rb_node);
+               __s = BIT_START(__iop);
+
+               if (s < __s)
+                       p = &(*p)->rb_left;
+               else if (s > __s)
+                       p = &(*p)->rb_right;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       rb_link_node(&iop->rb_node, parent, p);
+       rb_insert_color(&iop->rb_node, root);
+}
+
+struct io *rb_find_sec(struct rb_root *root, __u64 sec)
+{
+       struct io *__iop;
+       struct rb_node *n = root->rb_node;
+
+       while (n) {
+               __iop = rb_entry(n, struct io, rb_node);
+               if (sec < BIT_START(__iop))
+                       n = n->rb_left;
+               else if (sec >= BIT_END(__iop))
+                       n = n->rb_right;
+               else
+                       return __iop;
+       }
+
+       return NULL;
+}
+
+void rb_foreach(struct rb_node *n, struct io *iop, 
+                     void (*fnc)(struct io *iop, struct io *this),
+                     struct list_head *head)
+{
+       if (n) {
+               struct io *this = rb_entry(n, struct io, rb_node);
+               __u64 iop_s = BIT_START(iop), iop_e = BIT_END(iop);
+               __u64 this_s = BIT_START(this), this_e = BIT_END(this);
+
+               if ((iop_s <= this_s) && (this_e <= iop_e)) {
+                       if (fnc) fnc(iop, this);
+                       if (head) list_add_tail(&this->f_head, head);
+               }
+               if (iop_s < this_s)
+                       rb_foreach(n->rb_left, iop, fnc, head);
+               if (this_e < iop_e)
+                       rb_foreach(n->rb_right, iop, fnc, head);
+       }
+}
index 4a5314050b27073b0a0f064f40b0b3a22dcb5c36..3bafc91433a322dfb837082fb29118806323abd9 100644 (file)
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#include <time.h>
 
 #include "blktrace.h"
+#include "rbtree.h"
 #include "list.h"
 
-#define pdu_start(t)   (((void *) (t) + sizeof(struct blk_io_trace)))
-
 #define BIT_TIME(t)    ((double)SECONDS(t) + ((double)NANO_SECONDS(t) / 1.0e9))
 
 #define BIT_START(iop) ((iop)->t.sector)
@@ -38,6 +38,7 @@
 #define TO_MSEC(nanosec) (1000.0 * TO_SEC(nanosec))
 
 #if defined(DEBUG)
+#define DBG_PING()     dbg_ping()
 #define ASSERT(truth)   do {                                           \
                                if (!(truth)) {                         \
                                        DBG_PING();                     \
                                }                                       \
                        } while (0)
 
-#define DBG_PING()             dbg_ping()
 
 #define LIST_DEL(hp)   list_del(hp)
-
 #else
 #define ASSERT(truth)
 #define DBG_PING()
-
 #define LIST_DEL(hp)   do {                                            \
                                if (((hp)->next != NULL) &&             \
                                    ((hp)->next != LIST_POISON1))       \
@@ -60,9 +58,6 @@
                        } while (0)
 #endif
 
-#define IO_ZALLOC()    my_zmalloc(&free_ios, sizeof(struct io))
-#define IO_FREE(iop)   my_free(&free_ios, iop)
-
 enum iop_type {
        IOP_Q = 0,
        IOP_X = 1,
@@ -71,18 +66,19 @@ enum iop_type {
        IOP_I = 4,
        IOP_D = 5,
        IOP_C = 6,
-       IOP_Y = 7,
+       IOP_R = 7,
 };
-#define N_IOP_TYPES    (IOP_Y + 1)
+#define N_IOP_TYPES    (IOP_R + 1)
 
 struct file_info {
        struct file_info *next;
        FILE *ofp;
-       char *oname;
+       char oname[1];
 };
 
-struct my_mem {
-       struct my_mem *next;
+struct mode {
+       int most_seeks, nmds;
+       long long *modes;
 };
 
 struct io;
@@ -120,156 +116,137 @@ struct region_info {
        struct range_info *qr_cur, *cr_cur;
 };
 
-struct p_info;
-struct p_pid {
-       struct list_head head;
-       struct p_info *pip;
-       __u32 pid;
-};
-
 struct p_info {
-       struct list_head head;
        struct region_info regions;
        struct avgs_info avgs;
-       char *name;
        __u64 last_q;
+       __u32 pid;
+       char name[1];
 };
 
 struct devmap {
        struct devmap *next;
-       char device[32];
+       unsigned int host, bus, target, lun, irq, cpu;
        char model[64];
-       unsigned int host, bus, target, lun;
-       char node[32], pci[32];
-       unsigned int irq, cpu;
-       char devno[32];
+       char device[32], node[32], pci[32], devno[32];
 };
 
 struct stats {
-       __u64 rqm[2];
-       __u64 ios[2];
-       __u64 sec[2];
-       __u64 wait;
-       __u64 svctm;
-
-       int cur_qusz, cur_dev;
+       __u64 rqm[2], ios[2], sec[2], wait, svctm;
        double last_qu_change, last_dev_change, tot_qusz, idle_time;
+       int cur_qusz, cur_dev;
 };
 
 struct d_info {
-       struct list_head head, hash_head;
-       struct list_head iop_heads[N_IOP_TYPES];
+       struct list_head all_head, hash_head;
+       void *heads;
        struct region_info regions;
-       struct avgs_info avgs;
-       __u64 last_q;
-       __u32 device;
-       __u64 n_ds;
        struct devmap *map;
        void *seek_handle;
        FILE *d2c_ofp, *q2c_ofp;
+       struct avgs_info avgs;
        struct stats stats, all_stats;
+       __u64 last_q, n_ds;
+       __u32 device;
 };
 
 struct io {
-       struct list_head all_head, dev_head;
+       struct rb_node rb_node;
+       struct list_head f_head;
        struct d_info *dip;
        struct p_info *pip;
-       void *pdu;
-
        struct blk_io_trace t;
-
-       int users, traversed;
+       void *pdu;
        enum iop_type type;
-
-       union {
-               struct {
-                       union {
-                               struct io *q_a;
-                               struct io *q_x;
-                       } qp;
-                       enum {
-                               Q_NONE = 10,
-                               Q_A = 20,
-                               Q_X = 30,
-                       } qp_type;
-               }                                         q;
-               struct {
-                       union {
-                               struct io *a_q;
-                               struct io *a_a;
-                       } ap;
-                       enum {
-                               A_NONE = 10,
-                               A_A = 20,
-                               A_Q = 30,
-                       } ap_type;
-               }                                         a;
-               struct { struct io *x_q;                } x;
-               struct { struct io *m_q;                } m;
-               struct { struct list_head i_qs_head;    } i;
-               struct { struct list_head d_im_head;    } d;
-               struct { struct io *c_d;                } c;
-               struct { struct io *y_c1, *y_c2;        } y;
-       } u;
+       int linked;
 };
 
+/* bt_timeline.c */
+
 extern char bt_timeline_version[], *devices, *exes, *input_name, *output_name;
 extern char *seek_name, *iostat_name, *d2c_name, *q2c_name;
 extern double range_delta;
 extern FILE *ranges_ofp, *avgs_ofp, *iostat_ofp;
 extern int verbose, ifd;
 extern unsigned int n_devs;
-extern unsigned long n_traces, n_io_allocs, n_io_frees;
-extern struct list_head all_devs, all_ios, all_procs;
+extern unsigned long n_traces;
+extern struct list_head all_devs, all_procs;
 extern struct avgs_info all_avgs;
 extern __u64 last_q;
 extern struct region_info all_regions;
-extern struct my_mem *free_ios, *free_bits;
-extern char iop_map[];
-extern unsigned int pending_xs;
+extern struct list_head free_ios;
 extern __u64 iostat_interval, iostat_last_stamp;
+extern time_t genesis, last_vtrace;
 
-void add_trace(struct io *iop);
-int in_devices(struct blk_io_trace *t);
-char *make_dev_hdr(char *pad, size_t len, struct d_info *dip);
-int output_avgs(FILE *ofp);
-int output_ranges(FILE *ofp);
-unsigned int do_read(int ifd, void *buf, int len);
-void add_process(__u32 pid, char *name);
-struct p_info *find_process(__u32 pid, char *name);
-void pip_update_q(struct io *iop);
+/* args.c */
 void handle_args(int argc, char *argv[]);
-struct devmap *dev_map_find(__u32 device);
+
+/* dev_map.c */
 int dev_map_read(char *fname);
-void add_cy(struct io *iop);
-void rem_c(struct io *iop);
-void cy_init(void);
-void cy_shutdown(void);
-struct d_info *__dip_find(__u32 device);
-struct d_info *dip_add(__u32 device, struct io *iop);
-void traverse(struct io *iop);
-void io_free_resources(struct io *iop);
-void *seeki_init(__u32 device);
-void seek_clean(void);
-void seeki_add(void *handle, struct io *iop);
-double seeki_mean(void *handle);
-long long seeki_nseeks(void *handle);
-long long seeki_median(void *handle);
-int seeki_mode(void *handle, long long **modes_p, int *nseeks_p);
-void add_file(struct file_info **fipp, FILE *fp, char *oname);
-void clean_files(struct file_info **fipp);
+struct devmap *dev_map_find(__u32 device);
 
+/* devs.c */
+void init_dev_heads(void);
+struct d_info *dip_add(__u32 device, struct io *iop, int link);
+void dip_rem(struct io *iop);
+struct d_info *__dip_find(__u32 device);
+void dip_foreach(struct io *iop, enum iop_type type, 
+                void (*fnc)(struct io *iop, struct io *this), int rm_after);
+struct io *dip_find_sec(struct d_info *dip, enum iop_type type, __u64 sec);
+void dip_foreach_out(void (*func)(struct d_info *, void *), void *arg);
+
+/* dip_rb.c */
+void rb_insert(struct rb_root *root, struct io *iop);
+struct io *rb_find_sec(struct rb_root *root, __u64 sec);
+void rb_foreach(struct rb_node *n, struct io *iop, 
+                     void (*fnc)(struct io *iop, struct io *this),
+                     struct list_head *head);
+
+/* iostat.c */
 void iostat_init(void);
 void iostat_insert(struct io *iop);
 void iostat_merge(struct io *iop);
 void iostat_issue(struct io *iop);
-void iostat_complete(struct io *iop);
+void iostat_unissue(struct io *iop);
+void iostat_complete(struct io *d_iop, struct io *c_iop);
 void iostat_check_time(__u64 stamp);
 void iostat_dump_stats(__u64 stamp, int all);
 
+/* latency.c */
 void latency_init(struct d_info *dip);
 void latency_clean(void);
 void latency_d2c(struct d_info *dip, __u64 tstamp, __u64 latency);
 void latency_q2c(struct d_info *dip, __u64 tstamp, __u64 latency);
 
+/* misc.c */
+struct blk_io_trace *convert_to_cpu(struct blk_io_trace *t);
+int in_devices(struct blk_io_trace *t);
+unsigned int do_read(int ifd, void *buf, int len);
+void add_file(struct file_info **fipp, FILE *fp, char *oname);
+void clean_files(struct file_info **fipp);
+void dbg_ping(void);
+
+/* output.c */
+int output_avgs(FILE *ofp);
+int output_ranges(FILE *ofp);
+char *make_dev_hdr(char *pad, size_t len, struct d_info *dip);
+
+/* proc.c */
+void add_process(__u32 pid, char *name);
+struct p_info *find_process(__u32 pid, char *name);
+void pip_update_q(struct io *iop);
+void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg);
+
+/* seek.c */
+void *seeki_init(__u32 device);
+void seek_clean(void);
+void seeki_add(void *handle, struct io *iop);
+double seeki_mean(void *handle);
+long long seeki_nseeks(void *handle);
+long long seeki_median(void *handle);
+int seeki_mode(void *handle, struct mode *mp);
+
+/* trace.c */
+void add_trace(struct io *iop);
+
 #include "inlines.h"
index 6c7c6406438693c4dd59a15e3c78941af056d913..c8945bfc6aab2e7d5bbee874f4c516c85589e894 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  */
-static inline void dbg_ping(void) { }
-
-static inline void *zmalloc(size_t len)
-{
-       return memset(malloc(len), 0, len);
-}
-
-static inline int is_dev(struct io *iop, unsigned int mjr, unsigned int mnr)
-{
-       return MAJOR(iop->t.device) == mjr && MINOR(iop->t.device) == mnr;
-}
-
-static inline int in_bit(struct io *in, struct io *out)
-{
-       return (BIT_START(out) <= BIT_START(in)) &&
-              (BIT_END(in) <= BIT_END(out));
-}
-
-static inline int is_bit(struct io *i1, struct io *i2)
-{
-       return (BIT_START(i1) == BIT_START(i2)) && (BIT_END(i1) == BIT_END(i2));
-}
 
 static inline struct range_info *new_cur(__u64 time)
 {
-       struct range_info *cur = zmalloc(sizeof(*cur));
+       struct range_info *cur = malloc(sizeof(struct range_info));
 
        INIT_LIST_HEAD(&cur->head);
        cur->start = time;
        return cur;
 }
 
-static inline  void update_range(struct list_head *head_p,
-                                struct range_info **cur_p, __u64 time)
+static inline void update_range(struct list_head *head_p,
+                               struct range_info **cur_p, __u64 time)
 {
        if (*cur_p == NULL)
                *cur_p = new_cur(time);
@@ -96,6 +74,12 @@ static inline void avg_update(struct avg_info *ap, __u64 t)
         }
 }
 
+static inline void avg_unupdate(struct avg_info *ap, __u64 t)
+{
+       ap->n--;
+       ap->total -= t;
+}
+
 static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
 {
        if (*last_q != ((__u64)-1))
@@ -103,111 +87,48 @@ static inline void update_lq(__u64 *last_q, struct avg_info *avg, __u64 time)
        *last_q = time;
 }
 
-static inline struct list_head *dip_get_head(struct d_info *dip,
-                                             enum iop_type type)
-{
-       return &dip->iop_heads[type];
-}
-
-static inline struct list_head *dip_get_head_dev(__u32 dev, enum iop_type type)
-{
-       struct d_info *dip = __dip_find(dev);
-
-       if (!dip) 
-               return NULL;
-       return dip_get_head(__dip_find(dev), type);
-}
-
 static inline void dip_update_q(struct d_info *dip, struct io *iop)
 {
        update_lq(&dip->last_q, &dip->avgs.q2q, iop->t.time);
        update_qregion(&dip->regions, iop->t.time);
 }
 
-static inline void dip_rem(struct io *iop)
-{
-       LIST_DEL(&iop->dev_head);
-}
-
-static inline void *my_malloc(struct my_mem **head_p, size_t len)
+static inline struct io *io_alloc(void)
 {
-       struct my_mem *this = *head_p;
+       struct io *iop;
 
-       if (this)
-               *head_p = this->next;
+       if (!list_empty(&free_ios)) {
+               iop = list_entry(free_ios.next, struct io, f_head);
+               LIST_DEL(&iop->f_head);
+       }
        else
-               this = malloc(len);
+               iop = malloc(sizeof(struct io));
 
-       return this;
+       return memset(iop, 0, sizeof(struct io));
 }
 
-static inline void *my_zmalloc(struct my_mem **head_p, size_t len)
-{
-       return memset(my_malloc(head_p, len), 0, len);
-}
-
-static inline void my_free(struct my_mem **head_p, void *p)
+static inline void io_free(struct io *iop)
 {
-       struct my_mem *this = p;
-
-       this->next = *head_p;
-       *head_p = this;
+       list_add_tail(&iop->f_head, &free_ios);
 }
 
-static inline void io_setup(struct io *iop, enum iop_type type)
+static inline void io_setup(struct io *iop, enum iop_type type, int link)
 {
        iop->type = type;
-       iop->dip = dip_add(iop->t.device, iop);
+       iop->dip = dip_add(iop->t.device, iop, link);
        iop->pip = find_process(iop->t.pid, NULL);
-
-       n_io_allocs++;
-       list_add_tail(&iop->all_head, &all_ios);
-}
-
-static inline void io_free(struct io *iop)
-{
-       ASSERT(iop->users == 0);
-
-       LIST_DEL(&iop->all_head);
-       dip_rem(iop);
-       IO_FREE(iop);
-       n_io_frees++;
+       iop->linked = link;
 }
 
-static inline void io_get(struct io *iop)
+static inline void io_release(struct io *iop)
 {
-       iop->users++;
-}
-
-
-static inline int __io_put(struct io *iop)
-{
-       return --iop->users;
-}
-
-static inline void io_put(struct io *iop)
-{
-       if (__io_put(iop) == 0) {
-               io_free_resources(iop);
-               io_free(iop);
+       if (iop->linked) {
+               dip_rem(iop);
+               iop->linked = 0;
        }
-}
-
-static inline void io_link(struct io **p_dst, struct io *iop)
-{
-       ASSERT(iop != NULL);
-       io_get(iop);
-       *p_dst = iop;
-}
-
-static inline void io_unlink(struct io **p_dst)
-{
-       ASSERT(*p_dst != NULL);
-       io_put(*p_dst);
-
-#if defined(DEBUG)
-       *p_dst = NULL;
-#endif
+       if (iop->pdu) 
+               free(iop->pdu);
+       io_free(iop);
 }
 
 #define UPDATE_AVGS(_avg, _iop, _pip, _time) do {                      \
@@ -216,6 +137,12 @@ static inline void io_unlink(struct io **p_dst)
                if (_pip) avg_update(&_pip->avgs. _avg , _time);        \
        } while (0)
 
+#define UNUPDATE_AVGS(_avg, _iop, _pip, _time) do {                    \
+               avg_unupdate(&all_avgs. _avg , _time);                  \
+               avg_unupdate(&_iop->dip->avgs. _avg , _time);           \
+               if (_pip) avg_unupdate(&_pip->avgs. _avg , _time);      \
+       } while (0)
+
 static inline void update_q2c(struct io *iop, __u64 c_time)
 {
        UPDATE_AVGS(q2c, iop, iop->pip, c_time);
@@ -236,6 +163,11 @@ static inline void update_i2d(struct io *iop, __u64 d_time)
        UPDATE_AVGS(i2d, iop, iop->pip, d_time);
 }
 
+static inline void unupdate_i2d(struct io *iop, __u64 d_time)
+{
+       UNUPDATE_AVGS(i2d, iop, iop->pip, d_time);
+}
+
 static inline void update_d2c(struct io *iop, __u64 c_time)
 {
        UPDATE_AVGS(d2c, iop, iop->pip, c_time);
@@ -245,7 +177,44 @@ static inline void update_blks(struct io *iop)
 {
        __u64 nblks = iop->t.bytes >> 9;
        avg_update(&all_avgs.blks, nblks);
+       ASSERT(iop->dip != NULL);
        avg_update(&iop->dip->avgs.blks, nblks);
        if (iop->pip)
                avg_update(&iop->pip->avgs.blks, nblks);
 }
+
+static inline struct rb_root *__get_root(struct d_info *dip, enum iop_type type)
+{
+       struct rb_root *roots = dip->heads;
+       return &roots[type];
+}
+
+static inline void *dip_rb_mkhds(void)
+{
+       size_t len = N_IOP_TYPES * sizeof(struct rb_root);
+       return memset(malloc(len), 0, len);
+}
+
+static inline void dip_rb_ins(struct d_info *dip, struct io *iop)
+{
+       rb_insert(__get_root(dip, iop->type), iop);
+}
+
+static inline void dip_rb_rem(struct io *iop)
+{
+       rb_erase(&iop->rb_node, __get_root(iop->dip, iop->type));
+}
+
+static inline void dip_rb_fe(struct d_info *dip, enum iop_type type, 
+                            struct io *iop, 
+                            void (*fnc)(struct io *iop, struct io *this), 
+                            struct list_head *head)
+{
+       rb_foreach(__get_root(dip, type)->rb_node, iop, fnc, head);
+}
+
+static inline struct io *dip_rb_find_sec(struct d_info *dip, 
+                                        enum iop_type type, __u64 sec)
+{
+       return rb_find_sec(__get_root(dip, type), sec);
+}
diff --git a/btt/iofree.c b/btt/iofree.c
deleted file mode 100644 (file)
index 989186d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * blktrace output analysis: generate a timeline & gather statistics
- *
- * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-#include <stdio.h>
-
-#include "globals.h"
-
-void io_free_resources(struct io *iop)
-{
-       switch (iop->type) {
-       case IOP_X: io_unlink(&iop->u.x.x_q); break;
-       case IOP_M: io_unlink(&iop->u.m.m_q); break;
-       case IOP_C: io_unlink(&iop->u.c.c_d); break;
-
-       case IOP_A:
-               switch (iop->u.a.ap_type) {
-               case A_NONE: break;
-               case A_Q: io_unlink(&iop->u.a.ap.a_q); break;
-               case A_A: io_unlink(&iop->u.a.ap.a_a); break;
-               default:
-                       ASSERT(0);
-                       /*NOTREACHED*/
-               }
-               break;
-
-       case IOP_Q:
-               switch (iop->u.q.qp_type) {
-               case Q_NONE: break;
-               case Q_A: io_unlink(&iop->u.q.qp.q_a); break;
-               case Q_X: io_unlink(&iop->u.q.qp.q_x); break;
-               default:
-                       ASSERT(0);
-                       /*NOTREACHED*/
-               }
-               break;
-
-       case IOP_D: {
-               struct io_list *iolp;
-               struct list_head *p, *q;
-
-               list_for_each_safe(p, q, &iop->u.d.d_im_head) {
-                       iolp = list_entry(p, struct io_list, head);
-                       io_unlink(&iolp->iop);
-
-                       LIST_DEL(&iolp->head);
-                       free(iolp);
-               }
-               break;
-       }
-
-       case IOP_I: {
-               struct io_list *iolp;
-               struct list_head *p, *q;
-
-               list_for_each_safe(p, q, &iop->u.i.i_qs_head) {
-                       iolp = list_entry(p, struct io_list, head);
-                       io_unlink(&iolp->iop);
-
-                       LIST_DEL(&iolp->head);
-                       free(iolp);
-               }
-               break;
-       }
-
-       case IOP_Y:
-               io_unlink(&iop->u.y.y_c1);
-               io_unlink(&iop->u.y.y_c2);
-               break;
-
-       default:
-               ASSERT(0);
-               /*NOTREACHED*/
-       }
-}
index 9c345883fb274508c6b42725fb1983810f7b6921..92b6eaed528c478d8568776ba3d0a71d65b2d7b2 100644 (file)
@@ -53,19 +53,6 @@ __u64 iostat_interval = 1;
 char *iostat_name = NULL;
 FILE *iostat_ofp = NULL;
 
-void calc_waits(struct io *d_iop, __u64 c_time)
-{
-       __u64 waits = 0;
-       struct list_head *p;
-       struct io_list *iolp;
-
-       __list_for_each(p, &d_iop->u.d.d_im_head) {
-               iolp = list_entry(p, struct io_list, head);
-               waits += (c_time - iolp->iop->t.time);
-       }
-       ADD_STAT(d_iop->dip, wait, waits);
-}
-
 void dump_hdr(void)
 {
        fprintf(iostat_ofp, "Device:       rrqm/s   wrqm/s     r/s     w/s    "
@@ -73,6 +60,11 @@ void dump_hdr(void)
                            "avgrq-sz avgqu-sz   await   svctm  %%util   Stamp\n");
 }
 
+void im2d2c_func(struct io *c_iop, struct io *im_iop)
+{
+       ADD_STAT(c_iop->dip, wait, c_iop->t.time - im_iop->t.time);
+}
+
 void iostat_init(void)
 {
        last_start = (__u64)-1;
@@ -174,7 +166,7 @@ void iostat_dump_stats(__u64 stamp, int all)
                struct list_head *p;
 
                __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
+                       dip = list_entry(p, struct d_info, all_head);
                        __dump_stats(stamp, all, dip);
                }
        }
@@ -193,7 +185,6 @@ void iostat_dump_stats(__u64 stamp, int all)
        }
        if (!all && iostat_ofp)
                fprintf(iostat_ofp, "\n");
-               
 }
 
 void iostat_check_time(__u64 stamp)
@@ -234,21 +225,29 @@ void iostat_issue(struct io *iop)
        INC_STAT(dip, cur_dev);
 }
 
-void iostat_complete(struct io *iop)
+void iostat_unissue(struct io *iop)
 {
-       struct io *d_iop;
+       int rw = IOP_RW(iop);
        struct d_info *dip = iop->dip;
 
-       if ((d_iop = iop->u.c.c_d) != NULL) {
-               double now = TO_SEC(iop->t.time);
-               calc_waits(d_iop, iop->t.time);
+       DEC_STAT(dip, ios[rw]);
+       SUB_STAT(dip, sec[rw], iop->t.bytes >> 9);
+       DEC_STAT(dip, cur_dev);
+}
 
-               update_tot_qusz(dip, now);
-               DEC_STAT(dip, cur_qusz);
+void iostat_complete(struct io *d_iop, struct io *c_iop)
+{
+       double now = TO_SEC(c_iop->t.time);
+       struct d_info *dip = d_iop->dip;
 
-               update_idle_time(dip, now, 0);
-               DEC_STAT(dip, cur_dev);
+       dip_foreach(d_iop, IOP_I, im2d2c_func, 0);
+       dip_foreach(d_iop, IOP_M, im2d2c_func, 0);
 
-               ADD_STAT(dip, svctm, iop->t.time - d_iop->t.time);
-       }
+       update_tot_qusz(dip, now);
+       DEC_STAT(dip, cur_qusz);
+
+       update_idle_time(dip, now, 0);
+       DEC_STAT(dip, cur_dev);
+
+       ADD_STAT(dip, svctm, c_iop->t.time - d_iop->t.time);
 }
index e0e396c12292a439479035857a2ac6bd92206c0f..1ec05cbd593e3d34c95c21af4dd10c168d62b3d7 100644 (file)
@@ -87,12 +87,15 @@ unsigned int do_read(int ifd, void *buf, int len)
 
 void add_file(struct file_info **fipp, FILE *fp, char *oname)
 {
-       struct file_info *fip = malloc(sizeof(struct file_info));
+       struct file_info *fip;
+       
+       fip = malloc(sizeof(struct file_info) + strlen(oname) + 1);
 
-       fip->ofp = fp;
-       fip->oname = oname;
        fip->next = *fipp;
        *fipp = fip;
+
+       fip->ofp = fp;
+       strcpy(fip->oname, oname);
 }
 
 void clean_files(struct file_info **fipp)
@@ -106,7 +109,8 @@ void clean_files(struct file_info **fipp)
                fclose(fip->ofp);
                if (!stat(fip->oname, &buf) && (buf.st_size == 0))
                        unlink(fip->oname);
-               free(fip->oname);
                free(fip);
        }
 }
+
+void dbg_ping(void) {}
index 86dbc583beb453cd9eceb370a0341e674d640e84..58bd595aa6f1672ceb86f4a457afbd1e886fd551 100644 (file)
@@ -88,6 +88,17 @@ void __output_avg2(FILE *ofp, char *hdr, struct avgs_info *ap)
        }
 }
 
+void __pip_output_avg2(struct p_info *pip, void *arg)
+{
+       __output_avg2((FILE *)arg, pip->name, &pip->avgs);
+}
+
+void __dip_output_avg2(struct d_info *dip, void *arg)
+{
+       char dev_info[12];
+       __output_avg2((FILE *)arg, make_dev_hdr(dev_info, 12, dip), &dip->avgs);
+}
+
 char *make_dev_hdr(char *pad, size_t len, struct d_info *dip)
 {
        if (dip->map == NULL)
@@ -99,46 +110,30 @@ char *make_dev_hdr(char *pad, size_t len, struct d_info *dip)
        return pad;
 }
 
-void __output_dip_avg(FILE *ofp, struct d_info *dip, struct avg_info *ap)
+struct __oda {
+       FILE *ofp;
+       ai_dip_t (*func)(struct d_info *);
+};
+void __output_dip_avg(struct d_info *dip, void *arg)
 {
+       struct __oda *odap = arg;
+       ai_dip_t ap = odap->func(dip);
        if (ap->n > 0) {
                char dev_info[12];
                ap->avg = BIT_TIME(ap->total) / (double)ap->n;
-               __output_avg(ofp, make_dev_hdr(dev_info, 12, dip), ap);
+               __output_avg(odap->ofp, make_dev_hdr(dev_info, 12, dip), ap);
        }
 }
 
 void output_dip_avg(FILE *ofp, char *hdr, ai_dip_t (*func)(struct d_info *))
 {
-       struct d_info *dip;
-
+       struct __oda oda = { .ofp = ofp, .func = func};
        output_hdr(ofp, hdr);
-       if (devices == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
-                       __output_dip_avg(ofp, dip, func(dip));
-               }
-       }
-       else {
-               int i;
-               unsigned int mjr, mnr;
-               char *p = devices;
-
-               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
-                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       __output_dip_avg(ofp, dip, func(dip));
-
-                       p = strchr(p, ';');
-                       if (p) p++;
-               }
-       }
-
+       dip_foreach_out(__output_dip_avg, &oda);
        fprintf(ofp, "\n");
 }
 
-void __output_dip_merge_ratio(FILE *ofp, struct d_info *dip)
+void __output_dip_merge_ratio(struct d_info *dip, void *arg)
 {
        double blks_avg;
        char scratch[12];
@@ -147,7 +142,8 @@ void __output_dip_merge_ratio(FILE *ofp, struct d_info *dip)
        if (q2c_n > 0.0 && d2c_n > 0.0) {
                ratio = q2c_n / d2c_n;
                blks_avg = (double)dip->avgs.blks.total / d2c_n;
-               fprintf(ofp, "%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
+               fprintf((FILE *)arg, 
+                       "%10s | %8llu %8llu %7.1lf | %8llu %8llu %8llu %8llu\n",
                        make_dev_hdr(scratch, 12, dip),
                        (unsigned long long)dip->avgs.q2c.n,
                        (unsigned long long)dip->n_ds,
@@ -162,32 +158,9 @@ void __output_dip_merge_ratio(FILE *ofp, struct d_info *dip)
 
 void output_dip_merge_ratio(FILE *ofp)
 {
-       struct d_info *dip;
-
        fprintf(ofp, "%10s | %8s %8s %7s | %8s %8s %8s %8s\n", "DEV", "#Q", "#D", "Ratio", "BLKmin", "BLKavg", "BLKmax", "Total");
        fprintf(ofp, "---------- | -------- -------- ------- | -------- -------- -------- --------\n");
-       if (devices == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
-                       __output_dip_merge_ratio(ofp, dip);
-               }
-       }
-       else {
-               int i;
-               unsigned int mjr, mnr;
-               char *p = devices;
-
-               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
-                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       __output_dip_merge_ratio(ofp, dip);
-
-                       p = strchr(p, ';');
-                       if (p) p++;
-               }
-       }
-
+       dip_foreach_out(__output_dip_merge_ratio, ofp);
        fprintf(ofp, "\n");
 }
 
@@ -231,7 +204,7 @@ char *d2c_v_q2C(struct d_info *dip, char *s)
        return s;
 }
 
-void __output_dip_prep_ohead(FILE *ofp, struct d_info *dip)
+void __output_dip_prep_ohead(struct d_info *dip, void *arg)
 {
        char dev_info[12];
        char s1[16], s2[16], s3[16];
@@ -242,7 +215,7 @@ void __output_dip_prep_ohead(FILE *ofp, struct d_info *dip)
                CALC_AVG(&dip->avgs.i2d);
                CALC_AVG(&dip->avgs.d2c);
 
-               fprintf(ofp, "%10s | %6s %6s %6s\n",
+               fprintf((FILE *)arg, "%10s | %6s %6s %6s\n",
                        make_dev_hdr(dev_info, 12, dip),
                        q2i_v_q2C(dip, s1), i2d_v_q2C(dip, s2),
                        d2c_v_q2C(dip, s3));
@@ -251,209 +224,87 @@ void __output_dip_prep_ohead(FILE *ofp, struct d_info *dip)
 
 void output_dip_prep_ohead(FILE *ofp)
 {
-       struct d_info *dip;
-
        fprintf(ofp, "%10s | %6s %6s %6s\n", "DEV", "Q2I", "I2D", "D2C");
        fprintf(ofp, "---------- | ------ ------ ------\n");
-
-       if (devices == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
-                       __output_dip_prep_ohead(ofp, dip);
-               }
-       }
-       else {
-               int i;
-               unsigned int mjr, mnr;
-               char *p = devices;
-
-               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
-                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       __output_dip_prep_ohead(ofp, dip);
-
-                       p = strchr(p, ';');
-                       if (p) p++;
-               }
-       }
-
+       dip_foreach_out(__output_dip_prep_ohead, ofp);
        fprintf(ofp, "\n");
 }
 
-void __output_dip_seek_info(FILE *ofp, struct d_info *dip)
+void __output_dip_seek_info(struct d_info *dip, void *arg)
 {
        double mean;
-       int i, nmodes, most_seeks;
+       int i, nmodes;
        long long nseeks;
        char dev_info[12];
-       long long median, *modes;
+       long long median;
+       struct mode m;
+       FILE *ofp = arg;
 
        nseeks = seeki_nseeks(dip->seek_handle);
        if (nseeks > 0) {
                mean = seeki_mean(dip->seek_handle);
                median = seeki_median(dip->seek_handle);
-               nmodes = seeki_mode(dip->seek_handle, &modes, &most_seeks);
+               nmodes = seeki_mode(dip->seek_handle, &m);
 
                fprintf(ofp, "%10s | %15lld %15.1lf %15lld | %lld(%d)",
                        make_dev_hdr(dev_info, 12, dip), nseeks, mean, median, 
-                       nmodes > 0 ? modes[0] : 0, most_seeks);
+                       nmodes > 0 ? m.modes[0] : 0, m.most_seeks);
                for (i = 1; i < nmodes; i++)
-                       fprintf(ofp, " %lld", modes[i]);
+                       fprintf(ofp, " %lld", m.modes[i]);
                fprintf(ofp, "\n");
        }
 }
 
 void output_dip_seek_info(FILE *ofp)
 {
-       struct d_info *dip;
-
        fprintf(ofp, "%10s | %15s %15s %15s | %-15s\n", "DEV", "NSEEKS", 
                        "MEAN", "MEDIAN", "MODE");
        fprintf(ofp, "---------- "
                        "| --------------- --------------- --------------- "
                        "| ---------------\n");
-
-       if (devices == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
-                       __output_dip_seek_info(ofp, dip);
-               }
-       }
-       else {
-               int i;
-               unsigned int mjr, mnr;
-               char *p = devices;
-
-               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
-                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       __output_dip_seek_info(ofp, dip);
-
-                       p = strchr(p, ';');
-                       if (p) p++;
-               }
-       }
-
+       dip_foreach_out(__output_dip_seek_info, ofp);
        fprintf(ofp, "\n");
 }
 
-void __output_pip_avg(FILE *ofp, struct p_info *pip, struct avg_info *ap)
+struct __opa {
+       FILE *ofp;
+       ai_pip_t (*func)(struct p_info *);
+};
+
+void __output_pip_avg(struct p_info *pip, void *arg)
 {
+       struct __opa *opap = arg;
+       ai_pip_t ap = opap->func(pip);
+
        if (ap->n > 0) {
                char proc_name[12];
                snprintf(proc_name, 12, pip->name);
 
                ap->avg = BIT_TIME(ap->total) / (double)ap->n;
-               __output_avg(ofp, proc_name, ap);
+               __output_avg(opap->ofp, proc_name, ap);
        }
 }
 
 void output_pip_avg(FILE *ofp, char *hdr, ai_pip_t (*func)(struct p_info *))
 {
-       struct p_info *pip;
+       struct __opa opa = { .ofp = ofp, .func = func };
 
        output_hdr(ofp, hdr);
-       if (exes == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_procs) {
-                       pip = list_entry(p, struct p_info, head);
-                       __output_pip_avg(ofp, pip, func(pip));
-               }
-       }
-       else {
-               char *exe, *p, *next, *exes_save = strdup(exes);
-
-               p = exes_save;
-               while (exes_save != NULL) {
-                       exe = exes_save;
-                       if ((next = strchr(exes_save, ',')) != NULL) {
-                               *next = '\0';
-                               exes_save = next+1;
-                       }
-                       else
-                               exes_save = NULL;
-
-                       pip = find_process((__u32)-1, exe);
-                       if (pip)
-                               __output_pip_avg(ofp, pip, func(pip));
-               }
-       }
-
+       pip_foreach_out(__output_pip_avg, &opa);
        fprintf(ofp, "\n");
 }
 
 void output_dip_avgs(FILE *ofp)
 {
-       char dev_info[12];
-       struct d_info *dip;
-
        output_hdr2(ofp,"Dev");
-       if (devices == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
-                       __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
-                                       &dip->avgs);
-               }
-       }
-       else {
-               int i;
-               unsigned int mjr, mnr;
-               char *p = devices;
-
-               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
-                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       __output_avg2(ofp, make_dev_hdr(dev_info, 12, dip),
-                                       &dip->avgs);
-
-                       p = strchr(p, ';');
-                       if (p) p++;
-               }
-       }
-
+       dip_foreach_out(__dip_output_avg2, ofp);
        fprintf(ofp, "\n");
 }
 
 void output_pip_avgs(FILE *ofp)
 {
-       char exe[16];
-       struct p_info *pip;
-
        output_hdr2(ofp,"Exe");
-       if (exes == NULL) {
-               struct list_head *p;
-
-               __list_for_each(p, &all_procs) {
-                       pip = list_entry(p, struct p_info, head);
-                       snprintf(exe, 12, pip->name);
-                       __output_avg2(ofp, exe, &pip->avgs);
-               }
-       }
-       else {
-               char *exe, *p, *next, *exes_save = strdup(exes);
-
-               p = exes_save;
-               while (exes_save != NULL && *exes_save != '\0') {
-                       exe = exes_save;
-                       if ((next = strchr(exes_save, ',')) != NULL) {
-                               *next = '\0';
-                               exes_save = next+1;
-                       }
-                       else
-                               exes_save = NULL;
-
-                       pip = find_process((__u32)-1, exe);
-                       if (pip) {
-                               snprintf(exe, 12, pip->name);
-                               __output_avg2(ofp, exe, &pip->avgs);
-                       }
-               }
-       }
-
+       pip_foreach_out(__pip_output_avg2, ofp);
        fprintf(ofp, "\n");
 }
 
@@ -500,8 +351,10 @@ int output_avgs(FILE *ofp)
        output_section_hdr(ofp, "Device Overhead");
        output_dip_prep_ohead(ofp);
 
-       output_section_hdr(ofp, "Device Seek Information");
-       output_dip_seek_info(ofp);
+       if (seek_name) {
+               output_section_hdr(ofp, "Device Seek Information");
+               output_dip_seek_info(ofp);
+       }
 
        return 0;
 }
@@ -543,45 +396,27 @@ int output_regions(FILE *ofp, char *header, struct region_info *reg,
        return 1;
 }
 
-float __output_dev(FILE *ofp, struct d_info *dip, float base)
+struct __od {
+       FILE *ofp;
+       float base;
+};
+void __output_dev(struct d_info *dip, void *arg)
 {
        char header[128];
-       sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
-       if (output_regions(ofp, header, &dip->regions, base))
-               base += 1.0;
+       struct __od *odp = arg;
 
-       return base;
+       sprintf(header, "%d,%d", MAJOR(dip->device), MINOR(dip->device));
+       if (output_regions(odp->ofp, header, &dip->regions, odp->base))
+               odp->base += 1.0;
 }
 
 float output_devs(FILE *ofp, float base)
 {
-       struct d_info *dip;
+       struct __od od = { .ofp = ofp, .base = base };
 
        fprintf(ofp, "# Per device\n" );
-       if (devices == NULL) {
-               struct list_head *p;
-               __list_for_each(p, &all_devs) {
-                       dip = list_entry(p, struct d_info, head);
-                       base = __output_dev(ofp, dip, base);
-               }
-       }
-       else {
-               int i;
-               unsigned int mjr, mnr;
-               char *p = devices;
-
-               while (p && ((i = sscanf(p, "%u,%u", &mjr, &mnr)) == 2)) {
-                       dip = __dip_find((__u32)((mjr << MINORBITS) | mnr));
-                       ASSERT(dip);
-
-                       base = __output_dev(ofp, dip, base);
-
-                       p = strchr(p, ';');
-                       if (p) p++;
-               }
-       }
-
-       return base;
+       dip_foreach_out(__output_dev, &od);
+       return od.base;
 }
 
 static inline int exe_match(char *exe, char *name)
@@ -589,47 +424,24 @@ static inline int exe_match(char *exe, char *name)
        return (exe == NULL) || (strstr(name, exe) != NULL);
 }
 
-float __output_procs(FILE *ofp, float base, char *match)
+struct __op {
+       FILE *ofp;
+       float base;
+};
+void __output_procs(struct p_info *pip, void *arg)
 {
-       struct p_info *pip;
-       struct list_head *p;
-
-       __list_for_each(p, &all_procs) {
-               pip = list_entry(p, struct p_info, head);
-
-               if (exe_match(match, pip->name) &&
-                               output_regions(ofp, pip->name,
-                                              &pip->regions, base))
-                       base += 1.0;
-       }
-
-       return base;
+       struct __op *opp = arg;
+       output_regions(opp->ofp, pip->name, &pip->regions, opp->base);
+       opp->base += 1.0;
 }
 
 float output_procs(FILE *ofp, float base)
 {
-       fprintf(ofp, "# Per process\n" );
-       if (exes == NULL)
-               base = __output_procs(ofp, base, NULL);
-       else {
-               char *exe, *next, *p, *exes_save = strdup(exes);
-
-               p = exes_save;
-               while (exes_save != NULL) {
-                       exe = exes_save;
-                       if ((next = strchr(exes_save, ',')) != NULL) {
-                               *next = '\0';
-                               exes_save = next+1;
-                       }
-                       else
-                               exes_save = NULL;
-
-                       base = __output_procs(ofp, base, exe);
-               }
-               free(p);
-       }
+       struct __op op = { .ofp = ofp, .base = base };
 
-       return base;
+       fprintf(ofp, "# Per process\n" );
+       pip_foreach_out(__output_procs, &op);
+       return op.base;
 }
 
 int output_ranges(FILE *ofp)
index 42cd4177d60adbfc27aaf73d0afdbf9f5179c990..8e6c5ffae24161ccb0bb4d2a42773b601e93f865 100644 (file)
 
 #include "globals.h"
 
-#define N_PID_HASH     128
-#define PID_HASH(pid)  ((pid) & (N_PID_HASH-1))
-struct list_head       *pid_heads = NULL;
+struct pn_info {
+       struct rb_node rb_node;
+       struct p_info *pip;
+       union {
+               char *name;
+               __u32 pid;
+       }  u;
+};
+
+struct rb_root root_pid, root_name;
 
-static void init_pid_heads(void)
+struct p_info * __find_process_pid(__u32 pid)
 {
-       int i;
+       struct pn_info *this;
+       struct rb_node *n = root_pid.rb_node;
+
+       while (n) {
+               this = rb_entry(n, struct pn_info, rb_node);
+               if (pid < this->u.pid)
+                       n = n->rb_left;
+               else if (pid > this->u.pid)
+                       n = n->rb_right;
+               else
+                       return this->pip;
+       }
 
-       pid_heads = zmalloc(N_PID_HASH * sizeof(struct list_head));
-       for (i = 0; i < N_PID_HASH; i++)
-               INIT_LIST_HEAD(&pid_heads[i]);
+       return NULL;
 }
 
-static inline struct p_info *pid_to_proc(__u32 pid)
+struct p_info *__find_process_name(char *name)
 {
-       struct p_pid *pp;
-       struct list_head *p, *head;
-
-       if (pid_heads == NULL) init_pid_heads();
-
-       head = &pid_heads[PID_HASH(pid)];
-       __list_for_each(p, head) {
-               pp = list_entry(p, struct p_pid, head);
-               if (pp->pid == pid)
-                       return pp->pip;
+       int cmp;
+       struct pn_info *this;
+       struct rb_node *n = root_name.rb_node;
+
+       while (n) {
+               this = rb_entry(n, struct pn_info, rb_node);
+               cmp = strcmp(name, this->u.name);
+               if (cmp < 0)
+                       n = n->rb_left;
+               else if (cmp > 0)
+                       n = n->rb_right;
+               else
+                       return this->pip;
        }
 
        return NULL;
 }
 
-void insert_proc_hash(struct p_info *pip, __u32 pid)
+struct p_info *find_process(__u32 pid, char *name)
 {
-       struct p_pid *pp = zmalloc(sizeof(*pp));
+       struct p_info *pip;
 
-       if (pid_heads == NULL) init_pid_heads();
+       if (pid != ((__u32)-1) && ((pip = __find_process_pid(pid)) != NULL))
+               return pip;
 
-       pp->pip = pip;
-       pp->pid = pid;
+       if (name)
+               return __find_process_name(name);
 
-       list_add_tail(&pp->head, &pid_heads[PID_HASH(pid)]);
+       return NULL;
 }
 
-int __find_process_pid(__u32 pid)
+static void insert_pid(struct p_info *that)
 {
-       return pid_to_proc(pid) != NULL;
+       struct pn_info *this;
+       struct rb_node *parent = NULL;
+       struct rb_node **p = &root_pid.rb_node;
+
+       while (*p) {
+               parent = *p;
+               this = rb_entry(parent, struct pn_info, rb_node);
+
+               if (that->pid < this->u.pid)
+                       p = &(*p)->rb_left;
+               else if (that->pid > this->u.pid)
+                       p = &(*p)->rb_right;
+               else {
+                       ASSERT(strcmp(that->name, this->pip->name) == 0);
+                       return; // Already there
+               }
+       }
+
+       this = malloc(sizeof(struct pn_info));
+       this->u.pid = that->pid;
+       this->pip = that;
+
+       rb_link_node(&this->rb_node, parent, p);
+       rb_insert_color(&this->rb_node, &root_pid);
 }
 
-struct p_info *find_process(__u32 pid, char *name)
+static void insert_name(struct p_info *that)
 {
-       struct p_info *pip;
-       struct list_head *p;
+       int cmp;
+       struct pn_info *this;
+       struct rb_node *parent = NULL;
+       struct rb_node **p = &root_name.rb_node;
+
+       while (*p) {
+               parent = *p;
+               this = rb_entry(parent, struct pn_info, rb_node);
+               cmp = strcmp(that->name, this->u.name);
+
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else if (cmp > 0)
+                       p = &(*p)->rb_right;
+               else
+                       return; // Already there...
+       }
 
-       if (pid != ((__u32)-1) && (pip = pid_to_proc(pid)))
-               return pip;
+       this = malloc(sizeof(struct pn_info));
+       this->u.name = strdup(that->name);
+       this->pip = that;
 
-       if (name) {
-               __list_for_each(p, &all_procs) {
-                       pip = list_entry(p, struct p_info, head);
-                       if (name && !strcmp(pip->name, name)) {
-                               if (pid != ((__u32)-1))
-                                       insert_proc_hash(pip, pid);
-                               return pip;
-                       }
-               }
-       }
+       rb_link_node(&this->rb_node, parent, p);
+       rb_insert_color(&this->rb_node, &root_name);
+}
 
-       return NULL;
+static void insert(struct p_info *pip)
+{
+       insert_pid(pip);
+       insert_name(pip);
 }
 
 void add_process(__u32 pid, char *name)
@@ -96,13 +151,15 @@ void add_process(__u32 pid, char *name)
        struct p_info *pip = find_process(pid, name);
 
        if (pip == NULL) {
-               pip = zmalloc(sizeof(*pip));
+               size_t len = sizeof(struct p_info) + strlen(name) + 1;
 
-               list_add_tail(&pip->head, &all_procs);
-               insert_proc_hash(pip, pid);
-               pip->last_q = (__u64)-1;
-               pip->name = strdup(name);
+               pip = memset(malloc(len), 0, len);
+               pip->pid = pid;
                init_region(&pip->regions);
+               pip->last_q = (__u64)-1;
+               strcpy(pip->name, name);
+
+               insert(pip);
        }
 }
 
@@ -113,3 +170,37 @@ void pip_update_q(struct io *iop)
                update_qregion(&iop->pip->regions, iop->t.time);
        }
 }
+
+void __foreach(struct rb_node *n, void (*f)(struct p_info *, void *), void *arg)
+{
+       if (n) {
+               __foreach(n->rb_left, f, arg);
+               f(rb_entry(n, struct pn_info, rb_node)->pip, arg);
+               __foreach(n->rb_right, f, arg);
+       }
+}
+
+void pip_foreach_out(void (*f)(struct p_info *, void *), void *arg)
+{
+       if (exes == NULL)
+               __foreach(root_name.rb_node, f, arg);
+       else {
+               struct p_info *pip;
+               char *exe, *p, *next, *exes_save = strdup(exes);
+
+               p = exes_save;
+               while (exes_save != NULL) {
+                       exe = exes_save;
+                       if ((next = strchr(exes_save, ',')) != NULL) {
+                               *next = '\0';
+                               exes_save = next+1;
+                       }
+                       else
+                               exes_save = NULL;
+
+                       pip = __find_process_name(exe);
+                       if (pip)
+                               f(pip, arg);
+               }
+       }
+}
index 3003611a8e8d595b2c80ebc5d080e3ef992e5665..f5f38511819f12714d7dd5a84cdb793e1c66b989 100644 (file)
  */
 #include "globals.h"
 
-static struct file_info *all_files = NULL;
+static struct file_info *seek_files = NULL;
 
 struct seek_bkt {
+       struct rb_node rb_node;
        long long sectors;
        int nseeks;
 };
 
 struct seeki {
        FILE *rfp, *wfp;
-       struct seek_bkt *seek_bkts;
-       int nseek_bkts;
-       long long total_seeks;
+       struct rb_root root;
+       long long tot_seeks;
        double total_sectors;
        long long last_start, last_end;
 };
 
-FILE *seek_open(__u32 device, char rw)
+static FILE *seek_open(__u32 device, char rw)
 {
        FILE *fp;
        char *oname;
@@ -52,14 +52,41 @@ FILE *seek_open(__u32 device, char rw)
        if ((fp = fopen(oname, "w")) == NULL)
                perror(oname);
        else
-               add_file(&all_files, fp, oname);
+               add_file(&seek_files, fp, oname);
 
        return fp;
 }
 
+static void __insert(struct rb_root *root, long long sectors)
+{
+       struct seek_bkt *sbp;
+       struct rb_node *parent = NULL;
+       struct rb_node **p = &root->rb_node;
+
+       while (*p) {
+               parent = *p;
+               sbp = rb_entry(parent, struct seek_bkt, rb_node);
+               if (sectors < sbp->sectors)
+                       p = &(*p)->rb_left;
+               else if (sectors > sbp->sectors)
+                       p = &(*p)->rb_right;
+               else {
+                       sbp->nseeks++;
+                       return;
+               }
+       }
+
+       sbp = malloc(sizeof(struct seek_bkt));
+       sbp->nseeks = 1;
+       sbp->sectors = sectors;
+
+       rb_link_node(&sbp->rb_node, parent, p);
+       rb_insert_color(&sbp->rb_node, root);
+}
+
 void seek_clean(void)
 {
-       clean_files(&all_files);
+       clean_files(&seek_files);
 }
 
 long long seek_dist(struct seeki *sip, struct io *iop)
@@ -87,19 +114,16 @@ void *seeki_init(__u32 device)
 
        sip->rfp = seek_open(device, 'r');
        sip->wfp = seek_open(device, 'w');
-       sip->seek_bkts = NULL;
-       sip->nseek_bkts = 0;
-       sip->total_seeks = 0;
+       sip->tot_seeks = 0;
        sip->total_sectors = 0.0;
        sip->last_start = sip->last_end = 0;
+       memset(&sip->root, 0, sizeof(sip->root));
 
        return sip;
 }
 
 void seeki_add(void *handle, struct io *iop)
 {
-       int left, mid, right;
-       struct seek_bkt *bkt;
        struct seeki *sip = handle;
        long long dist = seek_dist(sip, iop);
        FILE *fp = IOP_READ(iop) ? sip->rfp : sip->wfp;
@@ -108,86 +132,87 @@ void seeki_add(void *handle, struct io *iop)
                fprintf(fp, "%15.9lf %13lld\n", BIT_TIME(iop->t.time), dist);
 
        dist = llabs(dist);
-       sip->total_seeks++;
+       sip->tot_seeks++;
        sip->total_sectors += dist;
-
-       left = 0;
-       right = sip->nseek_bkts-1;
-       while (left <= right) {
-               mid = (left+right)/2;
-               bkt = &sip->seek_bkts[mid];
-               if (dist == bkt->sectors) {
-                       bkt->nseeks++;
-                       return;
-               }
-
-               if (dist > bkt->sectors)
-                       left = mid + 1;
-               else
-                       right = mid - 1;
-       }
-
-       sip->seek_bkts = realloc(sip->seek_bkts, 
-                                (sip->nseek_bkts+1) * sizeof(struct seek_bkt));
-       if (sip->nseek_bkts > left)
-               memmove(&sip->seek_bkts[left+1], &sip->seek_bkts[left], 
-                       (sip->nseek_bkts - left) * sizeof(struct seek_bkt));
-       (bkt = &sip->seek_bkts[left])->sectors = dist;
-       bkt->nseeks = 1;
-       sip->nseek_bkts++;
+       __insert(&sip->root, dist);
 }
 
 long long seeki_nseeks(void *handle)
 {
-       return ((struct seeki *)handle)->total_seeks;
+       return ((struct seeki *)handle)->tot_seeks;
 }
 
 double seeki_mean(void *handle)
 {
        struct seeki *sip = handle;
-       return sip->total_sectors / sip->total_seeks;
+       return sip->total_sectors / sip->tot_seeks;
+}
+
+int __median(struct rb_node *n, long long sofar, long long target, long 
+                  long *rvp)
+{
+       struct seek_bkt *sbp;
+
+       sbp = rb_entry(n, struct seek_bkt, rb_node);
+       if ((sofar + sbp->nseeks) >= target) {
+               *rvp = sbp->sectors;
+               return 1;
+       }
+
+       if (n->rb_left && __median(n->rb_left, sofar, target, rvp))
+               return 1;
+
+       if (n->rb_right && __median(n->rb_right, sofar, target, rvp))
+               return 1;
+
+       return 0;
+
 }
 
 long long seeki_median(void *handle)
 {
-       int i;
-       struct seek_bkt *p;
+       long long rval = 0LL;
        struct seeki *sip = handle;
-       long long sofar = 0, target = sip->total_seeks / 2;
 
-       if (sip->total_seeks == 0) return 0;
-       for (i = 0, p = sip->seek_bkts; i < sip->nseek_bkts; i++, p++)
-               if ((sofar + p->nseeks) < target)
-                       sofar += p->nseeks;
-               else
-                       break;
+       if (sip->root.rb_node)
+               (void)__median(sip->root.rb_node, 0LL, sip->tot_seeks / 2, 
+                              &rval);
 
-       return p->sectors;
+       return rval;
 }
 
-int seeki_mode(void *handle, long long **modes_p, int *nseeks_p)
+void __mode(struct rb_node *n, struct mode *mp)
+{
+       struct seek_bkt *sbp;
+
+       if (n->rb_left) __mode(n->rb_left, mp);
+       if (n->rb_right) __mode(n->rb_right, mp);
+
+       sbp = rb_entry(n, struct seek_bkt, rb_node);
+       if (mp->modes == NULL) {
+               mp->modes = malloc(sizeof(long long));
+               mp->nmds = 0;
+       }
+       else if (sbp->nseeks > mp->most_seeks)
+               mp->nmds = 0;
+       else if (sbp->nseeks == mp->most_seeks)
+               mp->modes = realloc(mp->modes, (mp->nmds + 1) * 
+                                                       sizeof(long long));
+       else
+               return;
+
+       mp->most_seeks = sbp->nseeks;
+       mp->modes[mp->nmds++] = sbp->sectors;
+}
+
+int seeki_mode(void *handle, struct mode *mp)
 {
-       int i;
-       struct seek_bkt *p;
-       int most_seeks = 0;
        struct seeki *sip = handle;
-       int nmodes = 0;
-       long long *modes = NULL;
-
-       for (i = 0, p = sip->seek_bkts; i < sip->nseek_bkts; i++, p++)
-               if ((modes == NULL) || (p->nseeks > most_seeks)) {
-                       most_seeks = p->nseeks;
-                       modes = realloc(modes, sizeof(long long));
-                       *modes = p->sectors;
-                       nmodes = 1;
-               }
-               else if (p->nseeks == most_seeks) {
-                       most_seeks = p->nseeks;
-                       modes = realloc(modes, (nmodes+1) * sizeof(long long));
-                       modes[nmodes++] = p->sectors;
-               }
+       struct rb_root *root = &sip->root;
+
+       memset(mp, 0, sizeof(struct mode));
+       if (root->rb_node) 
+               __mode(root->rb_node, mp);
 
-       *nseeks_p = most_seeks;
-       *modes_p = modes;
-       return nmodes;
+       return mp->nmds;
 }
index 5250232aab9390f5d764f96e6bdce42bd42ba891..f44cea5d73ba2bffa52c51bf9f5f3138e268b4e9 100644 (file)
  */
 #include "globals.h"
 
-static inline void release_iop(struct io *iop)
+void im2d_func(struct io *d_iop, struct io *im_iop)
 {
-       if (iop->pdu) free(iop->pdu);
-       IO_FREE(iop);
+       update_i2d(im_iop, d_iop->t.time - im_iop->t.time);
 }
 
-struct io *dip_find_exact(struct list_head *head, struct io *iop_in)
+void q2c_func(struct io *c_iop, struct io *q_iop)
 {
-       struct io *iop;
-       struct list_head *p;
+       __u64 q2c = c_iop->t.time - q_iop->t.time;
 
-       if (head != NULL) __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (is_bit(iop_in, iop))
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_in(struct list_head *head, struct io *iop_in)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       if (head != NULL) __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (in_bit(iop, iop_in))
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_start(struct list_head *head, __u64 sector)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       if (head != NULL) __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (BIT_START(iop) == sector)
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_end(struct list_head *head, __u64 sector)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       if (head != NULL) __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (BIT_END(iop) == sector)
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_in_sec(struct list_head *head, __u64 sector)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       if (head != NULL) __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (BIT_START(iop) <= sector && sector <= BIT_END(iop))
-                       return iop;
-       }
-       return NULL;
-}
-
-struct io *dip_find_qa(struct list_head *head, struct blk_io_trace *t)
-{
-       struct io *iop;
-       struct list_head *p;
-
-       if (head != NULL) __list_for_each(p, head) {
-               iop = list_entry(p, struct io, dev_head);
-               if (iop->t.cpu == t->cpu && iop->t.sequence == (t->sequence-1))
-                       return iop;
-       }
-       return NULL;
+       update_q2c(q_iop, q2c);
+       latency_q2c(q_iop->dip, q_iop->t.time, q2c);
 }
 
-void dip_add_ms(struct list_head *head, struct io *d_iop)
-{
-       struct io *m_iop;
-       struct list_head *p;
-       struct io_list *iolp;
-
-       if (head != NULL) __list_for_each(p, head) {
-               m_iop = list_entry(p, struct io, dev_head);
-               if (in_bit(m_iop, d_iop)) {
-                       iolp = malloc(sizeof(*iolp));
-                       io_link(&iolp->iop, m_iop);
-                       list_add_tail(&iolp->head, &d_iop->u.d.d_im_head);
-               }
-       }
-}
-
-void dip_add_qs(struct list_head *head, struct io *i_iop)
+static inline void handle_im(struct io *im_iop)
 {
        struct io *q_iop;
-       struct list_head *p;
-       struct io_list *iolp;
 
-       if (head != NULL) __list_for_each(p, head) {
-               q_iop = list_entry(p, struct io, dev_head);
-               if (in_bit(q_iop, i_iop)) {
-                       iolp = malloc(sizeof(*iolp));
-                       io_link(&iolp->iop, q_iop);
-                       list_add_tail(&iolp->head, &i_iop->u.i.i_qs_head);
-               }
-       }
+       q_iop = dip_find_sec(im_iop->dip, IOP_Q, BIT_START(im_iop));
+       if (q_iop)
+               update_q2i(q_iop, im_iop->t.time - q_iop->t.time);
 }
 
-void handle_queue(struct io *iop)
+void handle_queue(struct io *q_iop)
 {
-       struct io *tmp;
-
-       io_setup(iop, IOP_Q);
-
-       update_lq(&last_q, &all_avgs.q2q, iop->t.time);
-       update_qregion(&all_regions, iop->t.time);
-       dip_update_q(iop->dip, iop);
-       pip_update_q(iop);
-
-       tmp = dip_find_exact(dip_get_head(iop->dip, IOP_A), iop);
-       if (tmp) {
-               iop->u.q.qp_type = Q_A;
-               io_link(&iop->u.q.qp.q_a, tmp);
-       }
-       else
-               iop->u.q.qp_type = Q_NONE;
+       io_setup(q_iop, IOP_Q, 1);
+       update_lq(&last_q, &all_avgs.q2q, q_iop->t.time);
+       update_qregion(&all_regions, q_iop->t.time);
+       dip_update_q(q_iop->dip, q_iop);
+       pip_update_q(q_iop);
 }
 
-void handle_merge(struct io *iop)
+void handle_remap(struct io *a_iop)
 {
        struct io *q_iop;
+       struct blk_io_trace_remap *rp = a_iop->pdu;
+       struct d_info *dip = __dip_find(be32_to_cpu(rp->device));
 
-       io_setup(iop, IOP_M);
-
-       q_iop = dip_find_exact(dip_get_head(iop->dip, IOP_Q), iop);
+       io_setup(a_iop, IOP_A, 0);
+       q_iop = dip_find_sec(dip, IOP_Q, be64_to_cpu(rp->sector));
        if (q_iop)
-               io_link(&iop->u.m.m_q, q_iop);
-
-       iostat_merge(iop);
+               update_q2a(q_iop, a_iop->t.time - q_iop->t.time);
+       io_release(a_iop);
 }
 
-void handle_insert(struct io *iop)
+void handle_insert(struct io *i_iop)
 {
-       struct io_list *iolp = malloc(sizeof(*iolp));
-
-       io_setup(iop, IOP_I);
-       INIT_LIST_HEAD(&iop->u.i.i_qs_head);
-       dip_add_qs(dip_get_head(iop->dip, IOP_Q), iop);
-
-       iostat_insert(iop);
+       io_setup(i_iop, IOP_I, 1);
+       iostat_insert(i_iop);
+       handle_im(i_iop);
 }
 
-void handle_complete(struct io *iop)
+void handle_merge(struct io *m_iop)
 {
-       struct io *d_iop;
-
-       io_setup(iop, IOP_C);
-       update_blks(iop);
-       update_cregion(&all_regions, iop->t.time);
-       update_cregion(&iop->dip->regions, iop->t.time);
-       if (iop->pip)
-               update_cregion(&iop->pip->regions, iop->t.time);
-
-       d_iop = dip_find_exact(dip_get_head(iop->dip, IOP_D), iop);
-       if (d_iop) {
-               io_link(&iop->u.c.c_d, d_iop);
-               iostat_complete(iop);
-               add_cy(iop);
-       }
-       else
-               io_free(iop);
+       io_setup(m_iop, IOP_M, 1);
+       iostat_merge(m_iop);
+       handle_im(m_iop);
 }
 
-void handle_issue(struct io *iop)
+void handle_issue(struct io *d_iop)
 {
-       struct io *i_iop;
-       struct io_list *iolp = malloc(sizeof(*iolp));
-
-       io_setup(iop, IOP_D);
-       iop->dip->n_ds++;
-
-       INIT_LIST_HEAD(&iop->u.d.d_im_head);
-       i_iop = dip_find_in(dip_get_head(iop->dip, IOP_I), iop);
-       if (i_iop) {
-               io_link(&iolp->iop, i_iop);
-               list_add_tail(&iolp->head, &iop->u.d.d_im_head);
-       }
-
-       dip_add_ms(dip_get_head(iop->dip, IOP_M), iop);
-       seeki_add(iop->dip->seek_handle, iop);
-
-       iostat_issue(iop);
-}
-
-void handle_split(struct io *iop)
-{
-       struct io *q_iop;
+       io_setup(d_iop, IOP_D, 1);
+       d_iop->dip->n_ds++;
 
-       pending_xs++;
-       io_setup(iop, IOP_X);
+       dip_foreach(d_iop, IOP_I, im2d_func, 0);
+       dip_foreach(d_iop, IOP_M, im2d_func, 0);
 
-       q_iop = dip_find_exact(dip_get_head(iop->dip, IOP_Q), iop);
-       if (q_iop)
-               io_link(&iop->u.x.x_q, q_iop);
+       if (seek_name)
+               seeki_add(d_iop->dip->seek_handle, d_iop);
+       iostat_issue(d_iop);
 }
 
-void handle_remap(struct io *iop)
+void handle_complete(struct io *c_iop)
 {
-       struct io *q_iop, *a_iop;
-       struct blk_io_trace_remap *rp = iop->pdu;
-       __u32 dev = be32_to_cpu(rp->device);
-       __u64 sector = be64_to_cpu(rp->sector);
+       struct io *d_iop;
 
-       io_setup(iop, IOP_A);
-       q_iop = dip_find_in_sec(dip_get_head_dev(dev, IOP_Q), sector);
-       if (q_iop) {
-               iop->u.a.ap_type = A_Q;
-               io_link(&iop->u.a.ap.a_q, q_iop);
-               return;
-       }
+       io_setup(c_iop, IOP_C, 0);
+       update_blks(c_iop);
+       update_cregion(&all_regions, c_iop->t.time);
+       update_cregion(&c_iop->dip->regions, c_iop->t.time);
+       if (c_iop->pip)
+               update_cregion(&c_iop->pip->regions, c_iop->t.time);
 
-       a_iop = dip_find_in_sec(dip_get_head_dev(dev, IOP_A), sector);
-       if (a_iop) {
-               iop->u.a.ap_type = A_A;
-               io_link(&iop->u.a.ap.a_a, a_iop);
-               return;
+       d_iop = dip_find_sec(c_iop->dip, IOP_D, BIT_START(c_iop));
+       if (d_iop) {
+               __u64 d2c = c_iop->t.time - d_iop->t.time;
+               update_d2c(d_iop, d2c);
+               latency_d2c(d_iop->dip, c_iop->t.time, d2c);
+               iostat_complete(d_iop, c_iop);
+               dip_foreach(d_iop, IOP_I, NULL, 1);
+               dip_foreach(d_iop, IOP_M, NULL, 1);
+               io_release(d_iop);
        }
 
-       iop->u.a.ap_type = A_NONE;
+       dip_foreach(c_iop, IOP_Q, q2c_func, 1);
+       io_release(c_iop);
 }
 
-void extract_i(struct io *i_iop)
+void rq_im2d_func(struct io *d_iop, struct io *im_iop)
 {
-       struct io_list *iolp;
-       struct list_head *p, *q;
-
-       ASSERT(i_iop != NULL && i_iop->type == IOP_I);
-       list_for_each_safe(p, q, &i_iop->u.i.i_qs_head) {
-               iolp = list_entry(p, struct io_list, head);
-               LIST_DEL(&iolp->head);
-
-               ASSERT(iolp->iop->type == IOP_Q);
-               (void)__io_put(iolp->iop);
-
-               free(iolp);
-       }
+       unupdate_i2d(im_iop, d_iop->t.time - im_iop->t.time);
 }
 
 /*
  * Careful surgery
  * (1) Need to remove D & its I & M's
- * (2) Need to leave I's Q and M's Q's -- *no* io_put (__io_put instead)
+ * (2) Need to leave I's Q and M's Q's
+ * (3) XXX: Need to downward adjust stats, but we don't carry PREVIOUS
+ *     XXX: min/maxes?! We'll just adjust what we can, and hope that 
+ *     XXX: the min/maxes are "pretty close". (REQUEUEs are rare, right?)
  */
-void handle_requeue(struct io *iop)
+void handle_requeue(struct io *r_iop)
 {
        struct io *d_iop;
-       struct io_list *iolp;
-       struct list_head *p, *q;
 
-       d_iop = dip_find_start(dip_get_head_dev(iop->t.device, IOP_D),
-                              iop->t.sector);
+       io_setup(r_iop, IOP_R, 0);
+       d_iop = dip_find_sec(r_iop->dip, IOP_D, BIT_START(r_iop));
        if (d_iop) {
-               list_for_each_safe(p, q, &d_iop->u.d.d_im_head) {
-                       iolp = list_entry(p, struct io_list, head);
-                       LIST_DEL(&iolp->head);
-
-                       if (iolp->iop->type == IOP_M)
-                               (void)__io_put(iolp->iop->u.m.m_q);
-                       else
-                               extract_i(iolp->iop);
-
-                       iolp->iop->users = 0;
-                       io_free(iolp->iop);
-                       free(iolp);
-               }
-
-               d_iop->users = 0;
-               io_free(d_iop);
+               dip_foreach(d_iop, IOP_I, rq_im2d_func, 1);
+               dip_foreach(d_iop, IOP_M, rq_im2d_func, 1);
+               iostat_unissue(d_iop);
+               io_release(d_iop);
        }
-
-       release_iop(iop);
-
+       io_release(r_iop);
 }
 
 void __add_trace(struct io *iop)
 {
-       n_traces++;
+       time_t now = time(NULL);
 
+       n_traces++;
        iostat_check_time(iop->t.time);
-       if (verbose && (n_traces % 10000) == 0) {
-               printf("%10lu t, %10lu m %1lu f\r",
-                      n_traces, n_io_allocs, n_io_frees);
-               fflush(stdout);
+
+       if (verbose && ((now - last_vtrace) > 0)) {
+               printf("%10lu t\r", n_traces);
                if ((n_traces % 1000000) == 0) printf("\n");
+               fflush(stdout);
+               last_vtrace = now;
        }
 
        switch (iop->t.action & 0xffff) {
-       case __BLK_TA_QUEUE:            handle_queue(iop);      break;
-       case __BLK_TA_BACKMERGE:        handle_merge(iop);      break;
-       case __BLK_TA_FRONTMERGE:       handle_merge(iop);      break;
-       case __BLK_TA_ISSUE:            handle_issue(iop);      break;
-       case __BLK_TA_COMPLETE:         handle_complete(iop);   break;
-       case __BLK_TA_INSERT:           handle_insert(iop);     break;
-       case __BLK_TA_SPLIT:            handle_split(iop);      break;
-       case __BLK_TA_REMAP:            handle_remap(iop);      break;
-       case __BLK_TA_REQUEUE:          handle_requeue(iop);    break;
+       case __BLK_TA_QUEUE:            handle_queue(iop); break;
+       case __BLK_TA_BACKMERGE:        handle_merge(iop); break;
+       case __BLK_TA_FRONTMERGE:       handle_merge(iop); break;
+       case __BLK_TA_ISSUE:            handle_issue(iop); break;
+       case __BLK_TA_COMPLETE:         handle_complete(iop); break;
+       case __BLK_TA_INSERT:           handle_insert(iop); break;
+       case __BLK_TA_REMAP:            handle_remap(iop); break;
+       case __BLK_TA_REQUEUE:          handle_requeue(iop); break;
+       default:                        io_release(iop); break;
        }
 }
 
@@ -344,11 +179,12 @@ void add_trace(struct io *iop)
 
                if (slash)
                        *slash = '\0';
+
                add_process(iop->t.pid, iop->pdu);
-               release_iop(iop);
+               io_release(iop);
        }
        else if (iop->t.action & BLK_TC_ACT(BLK_TC_PC))
-               release_iop(iop);
+               io_release(iop);
        else
                __add_trace(iop);
 }
diff --git a/btt/traverse.c b/btt/traverse.c
deleted file mode 100644 (file)
index d48755a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * blktrace output analysis: generate a timeline & gather statistics
- *
- * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-#include "globals.h"
-
-int tl_map[] = {
-       IOP_Q,
-       IOP_A,  /* IOP_X */
-       IOP_A,
-       IOP_I,  /* IOP_M */
-       IOP_I,
-       IOP_D,
-       IOP_C,
-       IOP_Y,
-};
-
-
-typedef void (*iop_func_t)(__u64 *, struct io*);
-
-void iop_q_func(__u64 *timeline, struct io *iop);
-void iop_x_func(__u64 *timeline, struct io *iop);
-void iop_a_func(__u64 *timeline, struct io *iop);
-void iop_m_func(__u64 *timeline, struct io *iop);
-void iop_i_func(__u64 *timeline, struct io *iop);
-void iop_d_func(__u64 *timeline, struct io *iop);
-void iop_c_func(__u64 *timeline, struct io *iop);
-void iop_y_func(__u64 *timeline, struct io *iop);
-
-iop_func_t traverse_func[] = {
-       iop_q_func,
-       iop_x_func,
-       iop_a_func,
-       iop_m_func,
-       iop_i_func,
-       iop_d_func,
-       iop_c_func,
-       iop_y_func,
-};
-
-void __traverse(__u64 *timeline, struct io *iop)
-{
-       if (iop != NULL && !iop->traversed) {
-               iop->traversed++;
-               timeline[tl_map[iop->type]] = iop->t.time;
-               (traverse_func[iop->type])(timeline, iop);
-               timeline[tl_map[iop->type]] = 0;
-       }
-}
-
-void traverse(struct io *iop)
-{
-       __u64 timeline[N_IOP_TYPES];
-
-       memset(timeline, 0, N_IOP_TYPES * sizeof(__u64));
-       __traverse(timeline, iop);
-}
-
-void iop_q_update(__u64 *timeline, struct io *iop, __u64 q_time)
-{
-       __u64 q2c = timeline[IOP_C] - q_time;
-
-       update_q2c(iop, q2c);
-       latency_q2c(iop->dip, iop->t.time, q2c);
-
-       if (timeline[IOP_A] > 0.0)      // IOP_X too
-               update_q2a(iop, timeline[IOP_A] - q_time);
-       else                            //IOP_M too
-               update_q2i(iop, timeline[IOP_I] - q_time);
-
-       update_i2d(iop, timeline[IOP_D] - timeline[IOP_I]);
-}
-
-void iop_q_func(__u64 *timeline, struct io *iop)
-{
-       iop_q_update(timeline, iop, iop->t.time);
-       if (iop->u.q.qp_type == Q_A)
-               __traverse(timeline, iop->u.q.qp.q_a);
-       else if (iop->u.q.qp_type == Q_X)
-               __traverse(timeline, iop->u.q.qp.q_x);
-}
-
-void iop_x_func(__u64 *timeline, struct io *iop)
-{
-       __traverse(timeline, iop->u.x.x_q);
-}
-
-void iop_a_func(__u64 *timeline, struct io *iop)
-{
-       if (iop->u.a.ap_type == A_Q)
-               __traverse(timeline, iop->u.a.ap.a_q);
-       else if (iop->u.a.ap_type == A_A)
-               __traverse(timeline, iop->u.a.ap.a_a);
-}
-
-void iop_m_func(__u64 *timeline, struct io *iop)
-{
-       __traverse(timeline, iop->u.m.m_q);
-}
-
-void iop_i_func(__u64 *timeline, struct io *iop)
-{
-       struct list_head *p;
-       struct io_list *iolp;
-
-       __list_for_each(p, &iop->u.i.i_qs_head) {
-               iolp = list_entry(p, struct io_list, head);
-               __traverse(timeline, iolp->iop);
-       }
-}
-
-void iop_d_func(__u64 *timeline, struct io *iop)
-{
-       struct list_head *p;
-       struct io_list *iolp;
-       __u64 d2c = timeline[IOP_C] - iop->t.time;
-
-       __list_for_each(p, &iop->u.d.d_im_head) {
-               iolp = list_entry(p, struct io_list, head);
-               __traverse(timeline, iolp->iop);
-       }
-
-       update_d2c(iop, d2c);
-       latency_d2c(iop->dip, iop->t.time, d2c);
-}
-
-void iop_c_func(__u64 *timeline, struct io *iop)
-{
-       __traverse(timeline, iop->u.c.c_d);
-}
-
-void iop_y_func(__u64 *timeline, struct io *iop)
-{
-       __traverse(timeline, iop->u.y.y_c1);
-       __traverse(timeline, iop->u.y.y_c2);
-}