Re: [PATCH] Btrfs: add a rb_tree to improve performance of ulist search

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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-fnst@xxxxxxxxxxxxxx>
> Reviewed-by: Miao Xie <miaox@xxxxxxxxxxxxxx>
> ---
>  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.btrfs@xxxxxxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux