On Thu, April 11, 2013 at 07:25 (+0200), Wang Shilong wrote:
> Walking backref tree and btrfs quota rely on ulist very much.
> This patch tries to use rb_tree to speed up search time.
> 
> The original code always checks whether an element
> exists before adding a new element, however it costs O(n).
> 
> I try to add a rb_tree in the ulist,this is only used to speed up
> search. I also do some measurements with quota enabled.
> 
> fsstress -p 4 -n 10000
> 
> Without this path:
> real    0m51.058s       2m4.745s        1m28.222s       1m5.137s
> user    0m0.035s        0m0.041s        0m0.105s        0m0.100s
> sys     0m12.009s       0m11.246s       0m10.901s       0m10.999s       
> 0m11.287s
> 
> With this path:
> real    0m55.295s       0m50.960s       1m2.214s        0m48.273s
> user    0m0.053s        0m0.095s        0m0.135s        0m0.107s
> sys     0m7.766s        0m6.013s        0m6.319s        0m6.030s        
> 0m6.532s
> 
> After applying the patch,the execute time is down by ~42%.(11.287s->6.532s)
> 
> Signed-off-by: Wang Shilong <wangsl-f...@cn.fujitsu.com>
> Reviewed-by: Miao Xie <mi...@cn.fujitsu.com>
> ---
>  fs/btrfs/ulist.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++-------
>  fs/btrfs/ulist.h |    6 +++++
>  2 files changed, 56 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/btrfs/ulist.c b/fs/btrfs/ulist.c
> index ddc61ca..7b417e2 100644
> --- a/fs/btrfs/ulist.c
> +++ b/fs/btrfs/ulist.c
> @@ -53,6 +53,7 @@ void ulist_init(struct ulist *ulist)
>       ulist->nnodes = 0;
>       ulist->nodes = ulist->int_nodes;
>       ulist->nodes_alloced = ULIST_SIZE;
> +     ulist->root = RB_ROOT;
>  }
>  EXPORT_SYMBOL(ulist_init);
>  
> @@ -72,6 +73,7 @@ void ulist_fini(struct ulist *ulist)
>       if (ulist->nodes_alloced > ULIST_SIZE)
>               kfree(ulist->nodes);
>       ulist->nodes_alloced = 0;       /* in case ulist_fini is called twice */
> +     ulist->root = RB_ROOT;
>  }
>  EXPORT_SYMBOL(ulist_fini);
>  
> @@ -123,6 +125,45 @@ void ulist_free(struct ulist *ulist)
>  }
>  EXPORT_SYMBOL(ulist_free);
>  
> +static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val)
> +{
> +     struct rb_node *n = ulist->root.rb_node;
> +     struct ulist_node *u = NULL;
> +
> +     while (n) {
> +             u = rb_entry(n, struct ulist_node, rb_node);
> +             if (u->val < val)
> +                     n = n->rb_right;
> +             else if (u->val > val)
> +                     n = n->rb_left;
> +             else
> +                     return u;
> +     }
> +     return NULL;
> +}
> +
> +static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins)
> +{
> +     struct rb_node **p = &ulist->root.rb_node;
> +     struct rb_node *parent = NULL;
> +     struct ulist_node *cur = NULL;
> +
> +     while (*p) {
> +             parent = *p;
> +             cur = rb_entry(parent, struct ulist_node, rb_node);
> +
> +             if (cur->val < ins->val)
> +                     p = &(*p)->rb_right;
> +             else if (cur->val > ins->val)
> +                     p = &(*p)->rb_left;
> +             else
> +                     return -EEXIST;
> +     }
> +     rb_link_node(&ins->rb_node, parent, p);
> +     rb_insert_color(&ins->rb_node, &ulist->root);
> +     return 0;
> +}
> +
>  /**
>   * ulist_add - add an element to the ulist
>   * @ulist:   ulist to add the element to
> @@ -151,14 +192,13 @@ int ulist_add(struct ulist *ulist, u64 val, u64 aux, 
> gfp_t gfp_mask)
>  int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
>                   u64 *old_aux, gfp_t gfp_mask)
>  {
> -     int i;
> -
> -     for (i = 0; i < ulist->nnodes; ++i) {
> -             if (ulist->nodes[i].val == val) {
> -                     if (old_aux)
> -                             *old_aux = ulist->nodes[i].aux;
> -                     return 0;
> -             }
> +     int ret = 0;
> +     struct ulist_node *node = NULL;
> +     node = ulist_rbtree_search(ulist, val);
> +     if (node) {
> +             if (old_aux)
> +                     *old_aux = node->aux;
> +             return 0;
>       }
>  
>       if (ulist->nnodes >= ulist->nodes_alloced) {
> @@ -187,6 +227,8 @@ int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
>       }
>       ulist->nodes[ulist->nnodes].val = val;
>       ulist->nodes[ulist->nnodes].aux = aux;
> +     ret = ulist_rbtree_insert(ulist, &ulist->nodes[ulist->nnodes]);
> +     BUG_ON(ret);
>       ++ulist->nnodes;
>  
>       return 1;
> diff --git a/fs/btrfs/ulist.h b/fs/btrfs/ulist.h
> index 21a1963..cb5f89d 100644
> --- a/fs/btrfs/ulist.h
> +++ b/fs/btrfs/ulist.h
> @@ -8,6 +8,9 @@
>  #ifndef __ULIST__
>  #define __ULIST__
>  
> +#include<linux/list.h>
> +#include<linux/rbtree.h>

I didn't expect the space after "#include" being optional. If it compiles, I'm
fine with it. With a space, it would look more familiar, though.

> +
>  /*
>   * ulist is a generic data structure to hold a collection of unique u64
>   * values. The only operations it supports is adding to the list and
> @@ -34,6 +37,7 @@ struct ulist_iterator {
>  struct ulist_node {
>       u64 val;                /* value to store */
>       u64 aux;                /* auxiliary value saved along with the val */
> +     struct rb_node rb_node; /* used to speed up search */
>  };
>  
>  struct ulist {
> @@ -54,6 +58,8 @@ struct ulist {
>        */
>       struct ulist_node *nodes;
>  
> +     struct rb_root root;
> +
>       /*
>        * inline storage space for the first ULIST_SIZE entries
>        */
> 

Makes a lot of sense. Thanks!

Reviewed-by: Jan Schmidt <list.bt...@jan-o-sch.net>
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to