From: Jens Axboe Date: Sat, 27 Aug 2005 07:38:00 +0000 (+0200) Subject: Fixed the sorting and parsing of traces with payloads X-Git-Tag: blktrace-0.99~239 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=8fc0abbc65934154363812eb8f7b400a73441905;p=blktrace.git Fixed the sorting and parsing of traces with payloads --- diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..5bd8d9e --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,5 @@ +20050826: + - Committed initial version + - Misc fixes + - Bug with pdu_len in blkparse.c, rewrote to index in rbtree and + ditch usage of qsort() diff --git a/Makefile b/Makefile index 6b2f30a..6d00bef 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TRACE_LIBS = -lpthread all: $(PROG) -blkparse: blkparse.o +blkparse: blkparse.o rbtree.o blktrace: blktrace.o $(TRACE_LIBS) clean: diff --git a/blkparse.c b/blkparse.c index 64d8c38..a5bd7f1 100644 --- a/blkparse.c +++ b/blkparse.c @@ -4,8 +4,10 @@ #include #include #include +#include -#include "blktrace.h" +#include "blktrace.h" +#include "rbtree.h" #define NELEMS(pfi) ((pfi)->stat.st_size / sizeof(struct blk_io_trace)) @@ -23,9 +25,18 @@ struct per_file_info { int dfd; char *dname; + void *trace_buf; + unsigned long long start_time; }; +static struct rb_root rb_root; + +struct trace { + struct blk_io_trace *bit; + struct rb_node rb_node; +}; + struct per_file_info per_file_info[MAX_CPUS]; struct per_file_info *current; @@ -271,12 +282,98 @@ int compar(const void *t1, const void *t2) return v1 - v2; } +inline int trace_rb_insert(struct trace *t) +{ + struct rb_node **p = &rb_root.rb_node; + struct rb_node *parent = NULL; + struct trace *__t; + + while (*p) { + parent = *p; + __t = rb_entry(parent, struct trace, rb_node); + + if (t->bit->sequence < __t->bit->sequence) + p = &(*p)->rb_left; + else if (t->bit->sequence > __t->bit->sequence) + p = &(*p)->rb_right; + else { + fprintf(stderr, "sequence alias %u!\n", t->bit->sequence); + return 1; + } + } + + rb_link_node(&t->rb_node, parent, p); + rb_insert_color(&t->rb_node, &rb_root); + return 0; +} + +int sort_entries(void *traces, unsigned long offset) +{ + struct blk_io_trace *bit; + struct trace *t; + void *start = traces; + int nelems = 0; + + memset(&rb_root, 0, sizeof(rb_root)); + + do { + bit = traces; + t = malloc(sizeof(*t)); + t->bit = bit; + memset(&t->rb_node, 0, sizeof(t->rb_node)); + + if (trace_rb_insert(t)) + return -1; + + traces += sizeof(*bit) + bit->pdu_len; + nelems++; + } while (traces < start + offset); + + return nelems; +} + +void show_entries(void) +{ + struct rb_node *n = rb_first(&rb_root); + struct blk_io_trace *bit; + struct trace *t; + int cpu; + + do { + if (!n) + break; + + t = rb_entry(n, struct trace, rb_node); + bit = t->bit; + + cpu = bit->magic; + if (cpu >= MAX_CPUS) { + fprintf(stderr, "CPU number too large (%d)\n", cpu); + return; + } + + current = &per_file_info[cpu]; + + /* + * offset time by first trace event. + * + * NOTE: This is *cpu* relative, thus you can not + * compare times ACROSS cpus. + */ + if (current->start_time == 0) + current->start_time = bit->time; + + bit->time -= current->start_time; + + dump_trace(bit); + } while ((n = rb_next(n)) != NULL); +} + int main(int argc, char *argv[]) { - char *p, *dev; - int i, nfiles, nelems, nb, ret; + char *dev; + int i, nfiles, nelems, ret; struct per_file_info *pfi; - struct blk_io_trace *traces, *tip; if (argc != 2) { fprintf(stderr, "Usage %s \n", argv[0]); @@ -285,7 +382,6 @@ int main(int argc, char *argv[]) dev = argv[1]; - printf("First pass:\n"); nfiles = nelems = 0; for (i = 0, pfi = &per_file_info[0]; i < MAX_CPUS; i++, pfi++) { pfi->cpu = i; @@ -295,39 +391,6 @@ int main(int argc, char *argv[]) sprintf(pfi->fname, "%s_out.%d", dev, i); if (stat(pfi->fname, &pfi->stat) < 0) break; - if (!S_ISREG(pfi->stat.st_mode)) { - fprintf(stderr, "Bad file type %s\n", pfi->fname); - return 1; - } - - nfiles++; - pfi->nelems = NELEMS(pfi); - nelems += pfi->nelems; - printf("\t%2d %10s %15d\n", i, pfi->fname, pfi->nelems); - - } - printf("\t %15d\n", nelems); - - if (!i) { - fprintf(stderr, "No files found\n"); - return 1; - } - - traces = malloc(nelems * sizeof(struct blk_io_trace)); - if (traces == NULL) { - fprintf(stderr, "Can not allocate %d\n", - nelems * (int) sizeof(struct blk_io_trace)); - return 1; - } - - printf("Second pass:\n"); - p = (char *)traces; - for (i = 0, pfi = per_file_info; i < nfiles; i++, pfi++) { - pfi->fd = open(pfi->fname, O_RDONLY); - if (pfi->fd < 0) { - perror(pfi->fname); - return 1; - } pfi->dname = malloc(128); snprintf(pfi->dname, 127, "%s_dat.%d", dev, i); @@ -345,47 +408,34 @@ int main(int argc, char *argv[]) return 1; } - printf("\tProcessing %s...", pfi->fname); fflush(stdout); - nb = pfi->stat.st_size; - ret = read(pfi->fd, p, nb); - if (ret != nb) { + printf("Processing %s\n", pfi->fname); + + pfi->trace_buf = malloc(pfi->stat.st_size); + + pfi->fd = open(pfi->fname, O_RDONLY); + if (pfi->fd < 0) { perror(pfi->fname); - fprintf(stderr,"\nFATAL: read(%d) -> %d\n", nb, ret); return 1; } - printf("\n"); fflush(stdout); - p += nb; - close(pfi->fd); - } - - printf("Sorting..."); fflush(stdout); - qsort(traces, nelems, sizeof(struct blk_io_trace), compar); - printf("\n\n"); - - for (i = 0, tip = traces; i < nelems; i++, tip++) { - int cpu = tip->magic; - - if (cpu >= MAX_CPUS) { - fprintf(stderr, "CPU number too large (%d)\n", cpu); + if (read(pfi->fd, pfi->trace_buf, pfi->stat.st_size) != pfi->stat.st_size) { + fprintf(stderr, "error reading\n"); return 1; } - current = &per_file_info[cpu]; - - /* - * offset time by first trace event. - * - * NOTE: This is *cpu* relative, thus you can not - * compare times ACROSS cpus. - */ - if (current->start_time == 0) - current->start_time = tip->time; + ret = sort_entries(pfi->trace_buf, pfi->stat.st_size); + if (ret == -1) + return 1; - tip->time -= current->start_time; + close(pfi->fd); + nfiles++; + pfi->nelems = ret; + nelems += pfi->nelems; + printf("\t%2d %10s %15d\n", i, pfi->fname, pfi->nelems); - dump_trace(tip); } + show_entries(); + show_stats(); return 0; } diff --git a/blktrace.c b/blktrace.c index c7150f2..2681a8e 100644 --- a/blktrace.c +++ b/blktrace.c @@ -166,8 +166,8 @@ void *extract(void *arg) tip->cpu, ip); exit(1); } else if (ret > 0) { - fprintf(stderr,"Thread %d misread %s %d,%ld\n", - tip->cpu, ip, ret, sizeof(t)); + fprintf(stderr,"Thread %d misread %s %d,%d\n", + tip->cpu, ip, ret, (int)sizeof(t)); exit(1); } else { usleep(10000); diff --git a/rbtree.c b/rbtree.c new file mode 100644 index 0000000..37bc021 --- /dev/null +++ b/rbtree.c @@ -0,0 +1,386 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 + + linux/lib/rbtree.c +*/ + +#include "rbtree.h" + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + + if ((node->rb_right = right->rb_left)) + right->rb_left->rb_parent = node; + right->rb_left = node; + + if ((right->rb_parent = node->rb_parent)) + { + if (node == node->rb_parent->rb_left) + node->rb_parent->rb_left = right; + else + node->rb_parent->rb_right = right; + } + else + root->rb_node = right; + node->rb_parent = right; +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + + if ((node->rb_left = left->rb_right)) + left->rb_right->rb_parent = node; + left->rb_right = node; + + if ((left->rb_parent = node->rb_parent)) + { + if (node == node->rb_parent->rb_right) + node->rb_parent->rb_right = left; + else + node->rb_parent->rb_left = left; + } + else + root->rb_node = left; + node->rb_parent = left; +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = node->rb_parent) && parent->rb_color == RB_RED) + { + gparent = parent->rb_parent; + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && uncle->rb_color == RB_RED) + { + uncle->rb_color = RB_BLACK; + parent->rb_color = RB_BLACK; + gparent->rb_color = RB_RED; + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + parent->rb_color = RB_BLACK; + gparent->rb_color = RB_RED; + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && uncle->rb_color == RB_RED) + { + uncle->rb_color = RB_BLACK; + parent->rb_color = RB_BLACK; + gparent->rb_color = RB_RED; + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + parent->rb_color = RB_BLACK; + gparent->rb_color = RB_RED; + __rb_rotate_left(gparent, root); + } + } + + root->rb_node->rb_color = RB_BLACK; +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (other->rb_color == RB_RED) + { + other->rb_color = RB_BLACK; + parent->rb_color = RB_RED; + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || + other->rb_left->rb_color == RB_BLACK) + && (!other->rb_right || + other->rb_right->rb_color == RB_BLACK)) + { + other->rb_color = RB_RED; + node = parent; + parent = node->rb_parent; + } + else + { + if (!other->rb_right || + other->rb_right->rb_color == RB_BLACK) + { + register struct rb_node *o_left; + if ((o_left = other->rb_left)) + o_left->rb_color = RB_BLACK; + other->rb_color = RB_RED; + __rb_rotate_right(other, root); + other = parent->rb_right; + } + other->rb_color = parent->rb_color; + parent->rb_color = RB_BLACK; + if (other->rb_right) + other->rb_right->rb_color = RB_BLACK; + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (other->rb_color == RB_RED) + { + other->rb_color = RB_BLACK; + parent->rb_color = RB_RED; + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || + other->rb_left->rb_color == RB_BLACK) + && (!other->rb_right || + other->rb_right->rb_color == RB_BLACK)) + { + other->rb_color = RB_RED; + node = parent; + parent = node->rb_parent; + } + else + { + if (!other->rb_left || + other->rb_left->rb_color == RB_BLACK) + { + register struct rb_node *o_right; + if ((o_right = other->rb_right)) + o_right->rb_color = RB_BLACK; + other->rb_color = RB_RED; + __rb_rotate_left(other, root); + other = parent->rb_left; + } + other->rb_color = parent->rb_color; + parent->rb_color = RB_BLACK; + if (other->rb_left) + other->rb_left->rb_color = RB_BLACK; + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + node->rb_color = RB_BLACK; +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + child = node->rb_right; + parent = node->rb_parent; + color = node->rb_color; + + if (child) + child->rb_parent = parent; + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + if (node->rb_parent == old) + parent = node; + node->rb_parent = old->rb_parent; + node->rb_color = old->rb_color; + node->rb_right = old->rb_right; + node->rb_left = old->rb_left; + + if (old->rb_parent) + { + if (old->rb_parent->rb_left == old) + old->rb_parent->rb_left = node; + else + old->rb_parent->rb_right = node; + } else + root->rb_node = node; + + old->rb_left->rb_parent = node; + if (old->rb_right) + old->rb_right->rb_parent = node; + goto color; + } + + parent = node->rb_parent; + color = node->rb_color; + + if (child) + child->rb_parent = parent; + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *rb_last(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *rb_next(struct rb_node *node) +{ + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while (node->rb_parent && node == node->rb_parent->rb_right) + node = node->rb_parent; + + return node->rb_parent; +} + +struct rb_node *rb_prev(struct rb_node *node) +{ + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while (node->rb_parent && node == node->rb_parent->rb_left) + node = node->rb_parent; + + return node->rb_parent; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = victim->rb_parent; + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + victim->rb_left->rb_parent = new; + if (victim->rb_right) + victim->rb_right->rb_parent = new; + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/rbtree.h b/rbtree.h new file mode 100644 index 0000000..e722b1e --- /dev/null +++ b/rbtree.h @@ -0,0 +1,151 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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 + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include + +struct rb_node +{ + struct rb_node *rb_parent; + int rb_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +}; + +struct rb_root +{ + struct rb_node *rb_node; +}; + +#undef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define RB_ROOT (struct rb_root) { NULL, } +#define rb_entry(ptr, type, member) container_of(ptr, type, member) + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(struct rb_node *); +extern struct rb_node *rb_prev(struct rb_node *); +extern struct rb_node *rb_first(struct rb_root *); +extern struct rb_node *rb_last(struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent = parent; + node->rb_color = RB_RED; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */