All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.