[Xen-devel] [PATCH v5 2/2] Refactor rangeset structure for better performance.

2015-08-14 Thread Yu Zhang
This patch refactors struct rangeset to base it on the red-black
tree structure, instead of on the current doubly linked list. By
now, ioreq leverages rangeset to keep track of the IO/memory
resources to be emulated. Yet when number of ranges inside one
ioreq server is very high, traversing a doubly linked list could
be time consuming. With this patch, the time complexity for
searching a rangeset can be improved from O(n) to O(log(n)).
Interfaces of rangeset still remain the same, and no new APIs
introduced.

Signed-off-by: Yu Zhang 
---
 xen/common/rangeset.c | 82 +--
 1 file changed, 60 insertions(+), 22 deletions(-)

diff --git a/xen/common/rangeset.c b/xen/common/rangeset.c
index 6c6293c..cde0d06 100644
--- a/xen/common/rangeset.c
+++ b/xen/common/rangeset.c
@@ -10,11 +10,12 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 /* An inclusive range [s,e] and pointer to next range in ascending order. */
 struct range {
-struct list_head list;
+struct rb_node node;
 unsigned long s, e;
 };
 
@@ -24,7 +25,7 @@ struct rangeset {
 struct domain   *domain;
 
 /* Ordered list of ranges contained in this set, and protecting lock. */
-struct list_head range_list;
+struct rb_root   range_tree;
 
 /* Number of ranges that can be allocated */
 long nr_ranges;
@@ -45,41 +46,78 @@ struct rangeset {
 static struct range *find_range(
 struct rangeset *r, unsigned long s)
 {
-struct range *x = NULL, *y;
+struct rb_node *node;
+struct range   *x;
+struct range   *prev = NULL;
 
-list_for_each_entry ( y, &r->range_list, list )
+node = r->range_tree.rb_node;
+while ( node )
 {
-if ( y->s > s )
-break;
-x = y;
+x = container_of(node, struct range, node);
+if ( (s >= x->s) && (s <= x->e) )
+return x;
+if ( s < x->s )
+node = node->rb_left;
+else
+{
+prev = x;
+node = node->rb_right;
+}
 }
 
-return x;
+return prev;
 }
 
 /* Return the lowest range in the set r, or NULL if r is empty. */
 static struct range *first_range(
 struct rangeset *r)
 {
-if ( list_empty(&r->range_list) )
-return NULL;
-return list_entry(r->range_list.next, struct range, list);
+struct rb_node *node;
+
+node = rb_first(&r->range_tree);
+if ( node != NULL )
+return container_of(node, struct range, node);
+
+return NULL;
 }
 
 /* Return range following x in ascending order, or NULL if x is the highest. */
 static struct range *next_range(
 struct rangeset *r, struct range *x)
 {
-if ( x->list.next == &r->range_list )
-return NULL;
-return list_entry(x->list.next, struct range, list);
+struct rb_node *node;
+
+node = rb_next(&x->node);
+if ( node )
+return container_of(node, struct range, node);
+
+return NULL;
 }
 
 /* Insert range y after range x in r. Insert as first range if x is NULL. */
 static void insert_range(
 struct rangeset *r, struct range *x, struct range *y)
 {
-list_add(&y->list, (x != NULL) ? &x->list : &r->range_list);
+struct rb_node **node;
+struct rb_node *parent = NULL;
+
+if ( x == NULL )
+node = &r->range_tree.rb_node;
+else
+{
+node = &x->node.rb_right;
+parent = &x->node;
+}
+
+while ( *node )
+{
+parent = *node;
+node = &parent->rb_left;
+}
+
+/* Add new node and rebalance the red-black tree. */
+rb_link_node(&y->node, parent, node);
+rb_insert_color(&y->node, &r->range_tree);
 }
 
 /* Remove a range from its list and free it. */
@@ -88,7 +126,7 @@ static void destroy_range(
 {
 r->nr_ranges++;
 
-list_del(&x->list);
+rb_erase(&x->node, &r->range_tree);
 xfree(x);
 }
 
@@ -319,7 +357,7 @@ bool_t rangeset_contains_singleton(
 bool_t rangeset_is_empty(
 const struct rangeset *r)
 {
-return ((r == NULL) || list_empty(&r->range_list));
+return ((r == NULL) || RB_EMPTY_ROOT(&r->range_tree));
 }
 
 struct rangeset *rangeset_new(
@@ -332,7 +370,7 @@ struct rangeset *rangeset_new(
 return NULL;
 
 rwlock_init(&r->lock);
-INIT_LIST_HEAD(&r->range_list);
+r->range_tree = RB_ROOT;
 r->nr_ranges = -1;
 
 BUG_ON(flags & ~RANGESETF_prettyprint_hex);
@@ -410,7 +448,7 @@ void rangeset_domain_destroy(
 
 void rangeset_swap(struct rangeset *a, struct rangeset *b)
 {
-LIST_HEAD(tmp);
+struct rb_node* tmp;
 
 if ( a < b )
 {
@@ -423,9 +461,9 @@ void rangeset_swap(struct rangeset *a, struct rangeset *b)
 write_lock(&a->lock);
 }
 
-list_splice_init(&a->range_list, &tmp);
-list_splice_init(&b->range_list, &a->range_list);
-list_splice(&tmp, &b->range_list);
+tmp = a->range_tree.rb_node;
+a->range_tree.rb_node = b->range_tree.rb_node;
+b->range_tree.rb_node = tmp;
 
 write_unlock(&a->lock

Re: [Xen-devel] [PATCH v5 2/2] Refactor rangeset structure for better performance.

2015-08-14 Thread Paul Durrant
> -Original Message-
> From: Yu Zhang [mailto:yu.c.zh...@linux.intel.com]
> Sent: 14 August 2015 13:03
> To: xen-devel@lists.xen.org; Paul Durrant; Ian Jackson; Stefano Stabellini; 
> Ian
> Campbell; Wei Liu; Keir (Xen.org); jbeul...@suse.com; Andrew Cooper
> Cc: Kevin Tian; zhiyuan...@intel.com
> Subject: [PATCH v5 2/2] Refactor rangeset structure for better performance.
> 
> This patch refactors struct rangeset to base it on the red-black
> tree structure, instead of on the current doubly linked list. By
> now, ioreq leverages rangeset to keep track of the IO/memory
> resources to be emulated. Yet when number of ranges inside one
> ioreq server is very high, traversing a doubly linked list could
> be time consuming. With this patch, the time complexity for
> searching a rangeset can be improved from O(n) to O(log(n)).
> Interfaces of rangeset still remain the same, and no new APIs
> introduced.
> 
> Signed-off-by: Yu Zhang 

Looks ok to me :-)

Reviewed-by: Paul Durrant 

> ---
>  xen/common/rangeset.c | 82
> +--
>  1 file changed, 60 insertions(+), 22 deletions(-)
> 
> diff --git a/xen/common/rangeset.c b/xen/common/rangeset.c
> index 6c6293c..cde0d06 100644
> --- a/xen/common/rangeset.c
> +++ b/xen/common/rangeset.c
> @@ -10,11 +10,12 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
> 
>  /* An inclusive range [s,e] and pointer to next range in ascending order. */
>  struct range {
> -struct list_head list;
> +struct rb_node node;
>  unsigned long s, e;
>  };
> 
> @@ -24,7 +25,7 @@ struct rangeset {
>  struct domain   *domain;
> 
>  /* Ordered list of ranges contained in this set, and protecting lock. */
> -struct list_head range_list;
> +struct rb_root   range_tree;
> 
>  /* Number of ranges that can be allocated */
>  long nr_ranges;
> @@ -45,41 +46,78 @@ struct rangeset {
>  static struct range *find_range(
>  struct rangeset *r, unsigned long s)
>  {
> -struct range *x = NULL, *y;
> +struct rb_node *node;
> +struct range   *x;
> +struct range   *prev = NULL;
> 
> -list_for_each_entry ( y, &r->range_list, list )
> +node = r->range_tree.rb_node;
> +while ( node )
>  {
> -if ( y->s > s )
> -break;
> -x = y;
> +x = container_of(node, struct range, node);
> +if ( (s >= x->s) && (s <= x->e) )
> +return x;
> +if ( s < x->s )
> +node = node->rb_left;
> +else
> +{
> +prev = x;
> +node = node->rb_right;
> +}
>  }
> 
> -return x;
> +return prev;
>  }
> 
>  /* Return the lowest range in the set r, or NULL if r is empty. */
>  static struct range *first_range(
>  struct rangeset *r)
>  {
> -if ( list_empty(&r->range_list) )
> -return NULL;
> -return list_entry(r->range_list.next, struct range, list);
> +struct rb_node *node;
> +
> +node = rb_first(&r->range_tree);
> +if ( node != NULL )
> +return container_of(node, struct range, node);
> +
> +return NULL;
>  }
> 
>  /* Return range following x in ascending order, or NULL if x is the highest. 
> */
>  static struct range *next_range(
>  struct rangeset *r, struct range *x)
>  {
> -if ( x->list.next == &r->range_list )
> -return NULL;
> -return list_entry(x->list.next, struct range, list);
> +struct rb_node *node;
> +
> +node = rb_next(&x->node);
> +if ( node )
> +return container_of(node, struct range, node);
> +
> +return NULL;
>  }
> 
>  /* Insert range y after range x in r. Insert as first range if x is NULL. */
>  static void insert_range(
>  struct rangeset *r, struct range *x, struct range *y)
>  {
> -list_add(&y->list, (x != NULL) ? &x->list : &r->range_list);
> +struct rb_node **node;
> +struct rb_node *parent = NULL;
> +
> +if ( x == NULL )
> +node = &r->range_tree.rb_node;
> +else
> +{
> +node = &x->node.rb_right;
> +parent = &x->node;
> +}
> +
> +while ( *node )
> +{
> +parent = *node;
> +node = &parent->rb_left;
> +}
> +
> +/* Add new node and rebalance the red-black tree. */
> +rb_link_node(&y->node, parent, node);
> +rb_insert_color(&y->node, &r->range_tree);
>  }
> 
>  /* Remove a range from its list and free it. */
> @@ -88,7 +126,7 @@ static void destroy_range(
>  {
>  r->nr_ranges++;
> 
> -list_del(&x->list);
> +rb_erase(&x->node, &r->range_tree);
>  xfree(x);
>  }
> 
> @@ -319,7 +357,7 @@ bool_t rangeset_contains_singleton(
>  bool_t rangeset_is_empty(
>  const struct rangeset *r)
>  {
> -return ((r == NULL) || list_empty(&r->range_list));
> +return ((r == NULL) || RB_EMPTY_ROOT(&r->range_tree));
>  }
> 
>  struct rangeset *rangeset_new(
> @@ -332,7 +370,7 @@ struct rangeset *rangeset_new(
>  return NULL;
> 
>  rwlock_init(&r->lock);