Linux Btrfs filesystem development
 help / color / mirror / Atom feed
From: Jan Schmidt <list.btrfs@jan-o-sch.net>
To: Wang Shilong <wangsl-fnst@cn.fujitsu.com>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH] Btrfs: add a rb_tree to improve performance of ulist search
Date: Thu, 11 Apr 2013 15:25:29 +0200	[thread overview]
Message-ID: <5166B9C9.6090108@jan-o-sch.net> (raw)
In-Reply-To: <5166495E.8030107@cn.fujitsu.com>

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@cn.fujitsu.com>
> Reviewed-by: Miao Xie <miaox@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.btrfs@jan-o-sch.net>

  reply	other threads:[~2013-04-11 13:25 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-11  5:25 [PATCH] Btrfs: add a rb_tree to improve performance of ulist search Wang Shilong
2013-04-11 13:25 ` Jan Schmidt [this message]
2013-04-11 13:45   ` Wang Shilong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5166B9C9.6090108@jan-o-sch.net \
    --to=list.btrfs@jan-o-sch.net \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=wangsl-fnst@cn.fujitsu.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox