linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/12] rbtree updates
@ 2012-07-13  0:31 Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 01/12] rbtree: reference Documentation/rbtree.txt for usage instructions Michel Lespinasse
                   ` (11 more replies)
  0 siblings, 12 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

Change log since v1:
- Added tree graphs as comments as suggested by Peter
- Fixed coding style in rest of lib/rbtree.c as suggested by Peter
- made clear rb_parent_color is private, not to be directly accessed,
  by renaming it to __rb_parent_color
- collapsed some low level optimization patches instead of splitting out
  the parts that were related to tree rotatoins from the parts that were
  related to color flips.
- Added build system support in patch 5

These are quite minor changes against v1, which already got good reviews
from Peter, so I think all that is required now is for Andrea to say he
doesn't oppose this.

--

I recently started looking at the rbtree code (with an eye towards
improving the augmented rbtree support, but I haven't gotten there
yet). I noticed a lot of possible speed improvements, which I am now
proposing in this patch set.

Patches 1-4 are preparatory: remove internal functions from rbtree.h
so that users won't be tempted to use them instead of the documented
APIs, clean up some incorrect usages I've noticed (in particular, with
the recently added fs/proc/proc_sysctl.c rbtree usage), reference the
documentation so that people have one less excuse to miss it, etc.

Patch 5 is a small module I wrote to check the rbtree performance.
It creates 100 nodes with random keys and repeatedly inserts and erases
them from an rbtree. Additionally, it has code to check for rbtree
invariants after each insert or erase operation.

Patches 6-12 is where the rbtree optimizations are done, and they touch
only that one file, lib/rbtree.c . I am getting good results out of these -
in my small benchmark doing rbtree insertion (including search) and erase,
I'm seeing a 30% runtime reduction on Sandybridge E5, which is more than
I initially thought would be possible. (the results aren't as impressive
on my two other test hosts though, AMD barcelona and Intel Westmere, where
I am seeing 14% runtime reduction only). The code size - both source
(ommiting comments) and compiled - is also shorter after these changes.
However, I do admit that the updated code is more arduous to read - one
big reason for that is the removal of the tree rotation helpers, which
added some overhead but also made it easier to reason about things locally.
Overall, I believe this is an acceptable compromise, given that this code
doesn't get modified very often, and that I have good tests for it.

Upon Peter's suggestion, I added comments showing the rtree configuration
before every rotation. I think they help; however it's still best to have
a copy of the cormen/leiserson/rivest book when digging into this code.

This patchset is against v3.4. This code doesn't change very often, so
the patchset should apply to the latest and greatest too.

My proposal would be for this to go in -mm tree to be used as a base to add
on the augmented rbtree support enhancements, which I am already working on.

Michel Lespinasse (12):
  rbtree: reference Documentation/rbtree.txt for usage instructions
  rbtree: empty nodes have no color
  rbtree: fix incorrect rbtree node insertion in fs/proc/proc_sysctl.c
  rbtree: move some implementation details from rbtree.h to rbtree.c
  rbtree: performance and correctness test
  rbtree: break out of rb_insert_color loop after tree rotation
  rbtree: adjust root color in rb_insert_color() only when necessary
  rbtree: low level optimizations in rb_insert_color()
  rbtree: adjust node color in __rb_erase_color() only when necessary
  rbtree: optimize case selection logic in __rb_erase_color()
  rbtree: low level optimizations in __rb_erase_color()
  rbtree: coding style adjustments

 Makefile                   |    2 +-
 fs/proc/proc_sysctl.c      |    5 +-
 include/linux/rbtree.h     |  112 ++---------
 include/linux/timerqueue.h |    2 +-
 lib/Kconfig.debug          |    1 +
 lib/rbtree.c               |  487 ++++++++++++++++++++++++++++----------------
 tests/Kconfig              |   18 ++
 tests/Makefile             |    1 +
 tests/rbtree_test.c        |  135 ++++++++++++
 9 files changed, 487 insertions(+), 276 deletions(-)
 create mode 100644 tests/Kconfig
 create mode 100644 tests/Makefile
 create mode 100644 tests/rbtree_test.c

-- 
1.7.7.3


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v2 01/12] rbtree: reference Documentation/rbtree.txt for usage instructions
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 02/12] rbtree: empty nodes have no color Michel Lespinasse
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

include/linux/rbtree.h included some basic usage instructions, while
Documentation/rbtree.txt had some more complete and easier to follow
instructions.  Replacing the former with a reference to the latter.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 include/linux/rbtree.h |   67 +-----------------------------------------------
 1 files changed, 1 insertions(+), 66 deletions(-)

diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index 033b507..e6a8077 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -23,72 +23,7 @@
   I know it's not the cleaner way,  but in C (not in C++) to get
   performances and genericity...
 
-  Some example of insert and search follows here. The search is a plain
-  normal search over an ordered tree. The insert instead must be implemented
-  in two steps: First, the code must insert the element in order as a red leaf
-  in the tree, and then the support library function rb_insert_color() must
-  be called. Such function will do the not trivial work to rebalance the
-  rbtree, if necessary.
-
------------------------------------------------------------------------
-static inline struct page * rb_search_page_cache(struct inode * inode,
-						 unsigned long offset)
-{
-	struct rb_node * n = inode->i_rb_page_cache.rb_node;
-	struct page * page;
-
-	while (n)
-	{
-		page = rb_entry(n, struct page, rb_page_cache);
-
-		if (offset < page->offset)
-			n = n->rb_left;
-		else if (offset > page->offset)
-			n = n->rb_right;
-		else
-			return page;
-	}
-	return NULL;
-}
-
-static inline struct page * __rb_insert_page_cache(struct inode * inode,
-						   unsigned long offset,
-						   struct rb_node * node)
-{
-	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
-	struct rb_node * parent = NULL;
-	struct page * page;
-
-	while (*p)
-	{
-		parent = *p;
-		page = rb_entry(parent, struct page, rb_page_cache);
-
-		if (offset < page->offset)
-			p = &(*p)->rb_left;
-		else if (offset > page->offset)
-			p = &(*p)->rb_right;
-		else
-			return page;
-	}
-
-	rb_link_node(node, parent, p);
-
-	return NULL;
-}
-
-static inline struct page * rb_insert_page_cache(struct inode * inode,
-						 unsigned long offset,
-						 struct rb_node * node)
-{
-	struct page * ret;
-	if ((ret = __rb_insert_page_cache(inode, offset, node)))
-		goto out;
-	rb_insert_color(node, &inode->i_rb_page_cache);
- out:
-	return ret;
-}
------------------------------------------------------------------------
+  See Documentation/rbtree.txt for documentation and samples.
 */
 
 #ifndef	_LINUX_RBTREE_H
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 02/12] rbtree: empty nodes have no color
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 01/12] rbtree: reference Documentation/rbtree.txt for usage instructions Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 03/12] rbtree: fix incorrect rbtree node insertion in fs/proc/proc_sysctl.c Michel Lespinasse
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

Empty nodes have no color.  We can make use of this property to
simplify the code emitted by the RB_EMPTY_NODE and RB_CLEAR_NODE
macros.  Also, we can get rid of the rb_init_node function which had
been introduced by commit 88d19cf37952a7e1e38b2bf87a00f0e857e63180
to avoid some issue with the empty node's color not being initialized.

I'm not sure what the RB_EMPTY_NODE checks in rb_prev() / rb_next()
are doing there, though. axboe introduced them in commit 10fd48f2376d.
The way I see it, the 'empty node' abstraction is only used by rbtree
users to flag nodes that they haven't inserted in any rbtree, so asking
the predecessor or successor of such nodes doesn't make any sense.

One final rb_init_node() caller was recently added in sysctl code
to implement faster sysctl name lookups. This code doesn't make use
of RB_EMPTY_NODE at all, and from what I could see it only called
rb_init_node() under the mistaken assumption that such initialization
was required before node insertion.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 fs/proc/proc_sysctl.c      |    4 +---
 include/linux/rbtree.h     |   15 +++++----------
 include/linux/timerqueue.h |    2 +-
 lib/rbtree.c               |    4 ++--
 4 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 21d836f..33aea86 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -168,10 +168,8 @@ static void init_header(struct ctl_table_header *head,
 	head->node = node;
 	if (node) {
 		struct ctl_table *entry;
-		for (entry = table; entry->procname; entry++, node++) {
-			rb_init_node(&node->node);
+		for (entry = table; entry->procname; entry++, node++)
 			node->header = head;
-		}
 	}
 }
 
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index e6a8077..2049087 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -67,17 +67,12 @@ static inline void rb_set_color(struct rb_node *rb, int color)
 #define RB_ROOT	(struct rb_root) { NULL, }
 #define	rb_entry(ptr, type, member) container_of(ptr, type, member)
 
-#define RB_EMPTY_ROOT(root)	((root)->rb_node == NULL)
-#define RB_EMPTY_NODE(node)	(rb_parent(node) == node)
-#define RB_CLEAR_NODE(node)	(rb_set_parent(node, node))
+#define RB_EMPTY_ROOT(root)  ((root)->rb_node == NULL)
+
+/* 'empty' nodes are nodes that are known not to be inserted in an rbree */
+#define RB_EMPTY_NODE(node)  ((node)->rb_parent_color == (unsigned long)(node))
+#define RB_CLEAR_NODE(node)  ((node)->rb_parent_color = (unsigned long)(node))
 
-static inline void rb_init_node(struct rb_node *rb)
-{
-	rb->rb_parent_color = 0;
-	rb->rb_right = NULL;
-	rb->rb_left = NULL;
-	RB_CLEAR_NODE(rb);
-}
 
 extern void rb_insert_color(struct rb_node *, struct rb_root *);
 extern void rb_erase(struct rb_node *, struct rb_root *);
diff --git a/include/linux/timerqueue.h b/include/linux/timerqueue.h
index 5088727..a520fd7 100644
--- a/include/linux/timerqueue.h
+++ b/include/linux/timerqueue.h
@@ -39,7 +39,7 @@ struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head)
 
 static inline void timerqueue_init(struct timerqueue_node *node)
 {
-	rb_init_node(&node->node);
+	RB_CLEAR_NODE(&node->node);
 }
 
 static inline void timerqueue_init_head(struct timerqueue_head *head)
diff --git a/lib/rbtree.c b/lib/rbtree.c
index d417556..fe43c8c 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -387,7 +387,7 @@ struct rb_node *rb_next(const struct rb_node *node)
 {
 	struct rb_node *parent;
 
-	if (rb_parent(node) == node)
+	if (RB_EMPTY_NODE(node))
 		return NULL;
 
 	/* If we have a right-hand child, go down and then left as far
@@ -416,7 +416,7 @@ struct rb_node *rb_prev(const struct rb_node *node)
 {
 	struct rb_node *parent;
 
-	if (rb_parent(node) == node)
+	if (RB_EMPTY_NODE(node))
 		return NULL;
 
 	/* If we have a left-hand child, go down and then right as far
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 03/12] rbtree: fix incorrect rbtree node insertion in fs/proc/proc_sysctl.c
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 01/12] rbtree: reference Documentation/rbtree.txt for usage instructions Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 02/12] rbtree: empty nodes have no color Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 04/12] rbtree: move some implementation details from rbtree.h to rbtree.c Michel Lespinasse
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

The recently added code to use rbtrees in sysctl did not follow the proper
rbtree interface on insertion - it was calling rb_link_node() which
inserts a new node into the binary tree, but missed the call to
rb_insert_color() which properly balances the rbtree and establishes all
expected rbtree invariants.

I found out about this only because faulty commit also used rb_init_node(),
which I am removing within this patchset. But I think it's an easy mistake
to make, and it makes me wonder if we should change the rbtree API so that
insertions would be done with a single rb_insert() call (even if its
implementation could still inline the rb_link_node() part and call
a private __rb_insert_color function to do the rebalancing).

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 fs/proc/proc_sysctl.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 33aea86..77602c1a 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -142,6 +142,7 @@ static int insert_entry(struct ctl_table_header *head, struct ctl_table *entry)
 	}
 
 	rb_link_node(node, parent, p);
+	rb_insert_color(node, &head->parent->root);
 	return 0;
 }
 
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 04/12] rbtree: move some implementation details from rbtree.h to rbtree.c
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (2 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 03/12] rbtree: fix incorrect rbtree node insertion in fs/proc/proc_sysctl.c Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 05/12] rbtree: performance and correctness test Michel Lespinasse
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

rbtree users must use the documented APIs to manipulate the tree
structure.  Low-level helpers to manipulate node colors and parenthood
are not part of that API, so move them to lib/rbtree.c

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 include/linux/rbtree.h |   34 +++++++++-------------------------
 lib/rbtree.c           |   20 +++++++++++++++++++-
 2 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index 2049087..bf836a2 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -32,37 +32,19 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 
-struct rb_node
-{
-	unsigned long  rb_parent_color;
-#define	RB_RED		0
-#define	RB_BLACK	1
+struct rb_node {
+	unsigned long  __rb_parent_color;
 	struct rb_node *rb_right;
 	struct rb_node *rb_left;
 } __attribute__((aligned(sizeof(long))));
     /* The alignment might seem pointless, but allegedly CRIS needs it */
 
-struct rb_root
-{
+struct rb_root {
 	struct rb_node *rb_node;
 };
 
 
-#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
-#define rb_color(r)   ((r)->rb_parent_color & 1)
-#define rb_is_red(r)   (!rb_color(r))
-#define rb_is_black(r) rb_color(r)
-#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
-#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)
-
-static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
-{
-	rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
-}
-static inline void rb_set_color(struct rb_node *rb, int color)
-{
-	rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
-}
+#define rb_parent(r)   ((struct rb_node *)((r)->__rb_parent_color & ~3))
 
 #define RB_ROOT	(struct rb_root) { NULL, }
 #define	rb_entry(ptr, type, member) container_of(ptr, type, member)
@@ -70,8 +52,10 @@ static inline void rb_set_color(struct rb_node *rb, int color)
 #define RB_EMPTY_ROOT(root)  ((root)->rb_node == NULL)
 
 /* 'empty' nodes are nodes that are known not to be inserted in an rbree */
-#define RB_EMPTY_NODE(node)  ((node)->rb_parent_color == (unsigned long)(node))
-#define RB_CLEAR_NODE(node)  ((node)->rb_parent_color = (unsigned long)(node))
+#define RB_EMPTY_NODE(node)  \
+	((node)->__rb_parent_color == (unsigned long)(node))
+#define RB_CLEAR_NODE(node)  \
+	((node)->__rb_parent_color = (unsigned long)(node))
 
 
 extern void rb_insert_color(struct rb_node *, struct rb_root *);
@@ -98,7 +82,7 @@ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
 static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
 				struct rb_node ** rb_link)
 {
-	node->rb_parent_color = (unsigned long )parent;
+	node->__rb_parent_color = (unsigned long)parent;
 	node->rb_left = node->rb_right = NULL;
 
 	*rb_link = node;
diff --git a/lib/rbtree.c b/lib/rbtree.c
index fe43c8c..ccada9a 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -23,6 +23,24 @@
 #include <linux/rbtree.h>
 #include <linux/export.h>
 
+#define	RB_RED		0
+#define	RB_BLACK	1
+
+#define rb_color(r)   ((r)->__rb_parent_color & 1)
+#define rb_is_red(r)   (!rb_color(r))
+#define rb_is_black(r) rb_color(r)
+#define rb_set_red(r)  do { (r)->__rb_parent_color &= ~1; } while (0)
+#define rb_set_black(r)  do { (r)->__rb_parent_color |= 1; } while (0)
+
+static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
+{
+	rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
+}
+static inline void rb_set_color(struct rb_node *rb, int color)
+{
+	rb->__rb_parent_color = (rb->__rb_parent_color & ~1) | color;
+}
+
 static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
 {
 	struct rb_node *right = node->rb_right;
@@ -255,7 +273,7 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
 			rb_set_parent(old->rb_right, node);
 		}
 
-		node->rb_parent_color = old->rb_parent_color;
+		node->__rb_parent_color = old->__rb_parent_color;
 		node->rb_left = old->rb_left;
 		rb_set_parent(old->rb_left, node);
 
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 05/12] rbtree: performance and correctness test
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (3 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 04/12] rbtree: move some implementation details from rbtree.h to rbtree.c Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13 20:15   ` Andrew Morton
  2012-07-13  0:31 ` [PATCH v2 06/12] rbtree: break out of rb_insert_color loop after tree rotation Michel Lespinasse
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

This small module helps measure the performance of rbtree insert and erase.

Additionally, we run a few correctness tests to check that the rbtrees have
all desired properties:
- contains the right number of nodes in the order desired,
- never two consecutive red nodes on any path,
- all paths to leaf nodes have the same number of black nodes,
- root node is black

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 Makefile            |    2 +-
 lib/Kconfig.debug   |    1 +
 tests/Kconfig       |   18 +++++++
 tests/Makefile      |    1 +
 tests/rbtree_test.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 156 insertions(+), 1 deletions(-)
 create mode 100644 tests/Kconfig
 create mode 100644 tests/Makefile
 create mode 100644 tests/rbtree_test.c

diff --git a/Makefile b/Makefile
index a687963..7bef085 100644
--- a/Makefile
+++ b/Makefile
@@ -708,7 +708,7 @@ export mod_strip_cmd
 
 
 ifeq ($(KBUILD_EXTMOD),)
-core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/ tests/
 
 vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
 		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6777153..b148fa1 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1144,6 +1144,7 @@ config LATENCYTOP
 
 source mm/Kconfig.debug
 source kernel/trace/Kconfig
+source tests/Kconfig
 
 config PROVIDE_OHCI1394_DMA_INIT
 	bool "Remote debugging over FireWire early on boot"
diff --git a/tests/Kconfig b/tests/Kconfig
new file mode 100644
index 0000000..ceca7ba
--- /dev/null
+++ b/tests/Kconfig
@@ -0,0 +1,18 @@
+menuconfig BENCHMARKS
+	bool "In kernel benchmarks"
+	def_bool n
+	help
+	  Includes in kernel benchmark modules in the build. These modules can
+	  be loaded later to trigger benchmarking kernel subsystems.
+	  Output will be generated in the system log.
+
+if BENCHMARKS
+
+config BENCHMARK_RBTREE
+	tristate "Red Black Tree Benchmark"
+	depends on m
+	default m
+	help
+	  A benchmark measuring the performance of the rbtree library.
+
+endif # BENCHMARKS
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..440b77c
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BENCHMARK_RBTREE) += rbtree_test.o
diff --git a/tests/rbtree_test.c b/tests/rbtree_test.c
new file mode 100644
index 0000000..4c6d250
--- /dev/null
+++ b/tests/rbtree_test.c
@@ -0,0 +1,135 @@
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/random.h>
+#include <asm/timex.h>
+
+#define NODES       100
+#define PERF_LOOPS  100000
+#define CHECK_LOOPS 100
+
+struct test_node {
+	struct rb_node rb;
+	u32 key;
+};
+
+static struct rb_root root = RB_ROOT;
+static struct test_node nodes[NODES];
+
+static struct rnd_state rnd;
+
+static void insert(struct test_node *node, struct rb_root *root)
+{
+	struct rb_node **new = &root->rb_node, *parent = NULL;
+
+	while (*new) {
+		parent = *new;
+		if (node->key < rb_entry(parent, struct test_node, rb)->key)
+			new = &parent->rb_left;
+		else
+			new = &parent->rb_right;
+	}
+
+	rb_link_node(&node->rb, parent, new);
+	rb_insert_color(&node->rb, root);
+}
+
+static inline void erase(struct test_node *node, struct rb_root *root)
+{
+	rb_erase(&node->rb, root);
+}
+
+static void init(void)
+{
+	int i;
+	for (i = 0; i < NODES; i++)
+		nodes[i].key = prandom32(&rnd);
+}
+
+static bool is_red(struct rb_node *rb)
+{
+	return !(rb->__rb_parent_color & 1);
+}
+
+static int black_path_count(struct rb_node *rb)
+{
+	int count;
+	for (count = 0; rb; rb = rb_parent(rb))
+		count += !is_red(rb);
+	return count;
+}
+
+static void check(int nr_nodes)
+{
+	struct rb_node *rb;
+	int count = 0;
+	int blacks;
+	u32 prev_key = 0;
+
+	for (rb = rb_first(&root); rb; rb = rb_next(rb)) {
+		struct test_node *node = rb_entry(rb, struct test_node, rb);
+		WARN_ON_ONCE(node->key < prev_key);
+		WARN_ON_ONCE(is_red(rb) &&
+			     (!rb_parent(rb) || is_red(rb_parent(rb))));
+		if (!count)
+			blacks = black_path_count(rb);
+		else
+			WARN_ON_ONCE((!rb->rb_left || !rb->rb_right) &&
+				     blacks != black_path_count(rb));
+		prev_key = node->key;
+		count++;
+	}
+	WARN_ON_ONCE(count != nr_nodes);
+}
+
+static int rbtree_test_init(void)
+{
+	int i, j;
+	cycles_t time1, time2, time;
+
+	printk(KERN_ALERT "rbtree testing");
+
+	prandom32_seed(&rnd, 3141592653589793238);
+	init();
+
+	time1 = get_cycles();
+
+	for (i = 0; i < PERF_LOOPS; i++) {
+		for (j = 0; j < NODES; j++)
+			insert(nodes + j, &root);
+		for (j = 0; j < NODES; j++)
+			erase(nodes + j, &root);
+	}
+
+	time2 = get_cycles();
+	time = time2 - time1;
+
+	time = div_u64(time, PERF_LOOPS);
+	printk(" -> %llu cycles\n", time);
+
+	for (i = 0; i < CHECK_LOOPS; i++) {
+		init();
+		for (j = 0; j < NODES; j++) {
+			check(j);
+			insert(nodes + j, &root);
+		}
+		for (j = 0; j < NODES; j++) {
+			check(NODES - j);
+			erase(nodes + j, &root);
+		}
+		check(0);
+	}
+
+	return -EAGAIN; /* Fail will directly unload the module */
+}
+
+static void rbtree_test_exit(void)
+{
+	printk(KERN_ALERT "test exit\n");
+}
+
+module_init(rbtree_test_init)
+module_exit(rbtree_test_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michel Lespinasse");
+MODULE_DESCRIPTION("Red Black Tree test");
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 06/12] rbtree: break out of rb_insert_color loop after tree rotation
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (4 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 05/12] rbtree: performance and correctness test Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary Michel Lespinasse
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

It is a well known property of rbtrees that insertion never requires
more than two tree rotations.  In our implementation, after one loop
iteration identified one or two necessary tree rotations, we would iterate
and look for more.  However at that point the node's parent would always
be black, which would cause us to exit the loop.

We can make the code flow more obvious by just adding a break statement
after the tree rotations, where we know we are done.  Additionally, in the
cases where two tree rotations are necessary, we don't have to update the
'node' pointer as it wouldn't be used until the next loop iteration, which
we now avoid due to this break statement.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |   14 ++++----------
 1 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index ccada9a..12abb8a 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -109,18 +109,15 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
 				}
 			}
 
-			if (parent->rb_right == node)
-			{
-				register struct rb_node *tmp;
+			if (parent->rb_right == node) {
 				__rb_rotate_left(parent, root);
-				tmp = parent;
 				parent = node;
-				node = tmp;
 			}
 
 			rb_set_black(parent);
 			rb_set_red(gparent);
 			__rb_rotate_right(gparent, root);
+			break;
 		} else {
 			{
 				register struct rb_node *uncle = gparent->rb_left;
@@ -134,18 +131,15 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
 				}
 			}
 
-			if (parent->rb_left == node)
-			{
-				register struct rb_node *tmp;
+			if (parent->rb_left == node) {
 				__rb_rotate_right(parent, root);
-				tmp = parent;
 				parent = node;
-				node = tmp;
 			}
 
 			rb_set_black(parent);
 			rb_set_red(gparent);
 			__rb_rotate_left(gparent, root);
+			break;
 		}
 	}
 
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (5 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 06/12] rbtree: break out of rb_insert_color loop after tree rotation Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-08-31  8:01   ` Adrian Hunter
  2012-07-13  0:31 ` [PATCH v2 08/12] rbtree: low level optimizations in rb_insert_color() Michel Lespinasse
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

The root node of an rbtree must always be black. However, rb_insert_color()
only needs to maintain this invariant when it has been broken - that is,
when it exits the loop due to the current (red) node being the root.
In all other cases (exiting after tree rotations, or exiting due to
an existing black parent) the invariant is already satisfied, so there
is no need to adjust the root node color.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |   19 +++++++++++++++----
 1 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index 12abb8a..d0be5fc 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -91,8 +91,21 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
 {
 	struct rb_node *parent, *gparent;
 
-	while ((parent = rb_parent(node)) && rb_is_red(parent))
-	{
+	while (true) {
+		/*
+		 * Loop invariant: node is red
+		 *
+		 * If there is a black parent, we are done.
+		 * Otherwise, take some corrective action as we don't
+		 * want a red root or two consecutive red nodes.
+		 */
+		parent = rb_parent(node);
+		if (!parent) {
+			rb_set_black(node);
+			break;
+		} else if (rb_is_black(parent))
+			break;
+
 		gparent = rb_parent(parent);
 
 		if (parent == gparent->rb_left)
@@ -142,8 +155,6 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
 			break;
 		}
 	}
-
-	rb_set_black(root->rb_node);
 }
 EXPORT_SYMBOL(rb_insert_color);
 
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 08/12] rbtree: low level optimizations in rb_insert_color()
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (6 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 09/12] rbtree: adjust node color in __rb_erase_color() only when necessary Michel Lespinasse
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

- Use the newly introduced rb_set_parent_color() function to flip the color
  of nodes whose parent is already known.
- Optimize rb_parent() when the node is known to be red - there is no need
  to mask out the color in that case.
- Flipping gparent's color to red requires us to fetch its rb_parent_color
  field, so we can reuse it as the parent value for the next loop iteration.
- Do not use __rb_rotate_left() and __rb_rotate_right() to handle tree
  rotations: we already have pointers to all relevant nodes, and know their
  colors (either because we want to adjust it, or because we've tested it,
  or we can deduce it as black due to the node proximity to a known red node).
  So we can generate more efficient code by making use of the node pointers
  we already have, and setting both the parent and color attributes for
  nodes all at once. Also in Case 2, some node attributes don't have to
  be set because we know another tree rotation (Case 3) will always follow
  and override them.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |  166 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 131 insertions(+), 35 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index d0be5fc..41cf19b 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -23,6 +23,25 @@
 #include <linux/rbtree.h>
 #include <linux/export.h>
 
+/*
+ * red-black trees properties:  http://en.wikipedia.org/wiki/Rbtree
+ *
+ *  1) A node is either red or black
+ *  2) The root is black
+ *  3) All leaves (NULL) are black
+ *  4) Both children of every red node are black
+ *  5) Every simple path from root to leaves contains the same number
+ *     of black nodes.
+ *
+ *  4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two
+ *  consecutive red nodes in a path and every red node is therefore followed by
+ *  a black. So if B is the number of black nodes on every simple path (as per
+ *  5), then the longest possible path due to 4 is 2B.
+ *
+ *  We shall indicate color with case, where black nodes are uppercase and red
+ *  nodes will be lowercase.
+ */
+
 #define	RB_RED		0
 #define	RB_BLACK	1
 
@@ -41,6 +60,17 @@ static inline void rb_set_color(struct rb_node *rb, int color)
 	rb->__rb_parent_color = (rb->__rb_parent_color & ~1) | color;
 }
 
+static inline void rb_set_parent_color(struct rb_node *rb,
+				       struct rb_node *p, int color)
+{
+	rb->__rb_parent_color = (unsigned long)p | color;
+}
+
+static inline struct rb_node *rb_red_parent(struct rb_node *red)
+{
+	return (struct rb_node *)red->__rb_parent_color;
+}
+
 static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
 {
 	struct rb_node *right = node->rb_right;
@@ -87,9 +117,30 @@ static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
 	rb_set_parent(node, left);
 }
 
+/*
+ * Helper function for rotations:
+ * - old's parent and color get assigned to new
+ * - old gets assigned new as a parent and 'color' as a color.
+ */
+static inline void
+__rb_rotate_set_parents(struct rb_node *old, struct rb_node *new,
+			struct rb_root *root, int color)
+{
+	struct rb_node *parent = rb_parent(old);
+	new->__rb_parent_color = old->__rb_parent_color;
+	rb_set_parent_color(old, new, color);
+	if (parent) {
+		if (parent->rb_left == old)
+			parent->rb_left = new;
+		else
+			parent->rb_right = new;
+	} else
+		root->rb_node = new;
+}
+
 void rb_insert_color(struct rb_node *node, struct rb_root *root)
 {
-	struct rb_node *parent, *gparent;
+	struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
 
 	while (true) {
 		/*
@@ -99,59 +150,104 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
 		 * Otherwise, take some corrective action as we don't
 		 * want a red root or two consecutive red nodes.
 		 */
-		parent = rb_parent(node);
 		if (!parent) {
-			rb_set_black(node);
+			rb_set_parent_color(node, NULL, RB_BLACK);
 			break;
 		} else if (rb_is_black(parent))
 			break;
 
-		gparent = rb_parent(parent);
-
-		if (parent == gparent->rb_left)
-		{
-			{
-				register struct rb_node *uncle = gparent->rb_right;
-				if (uncle && rb_is_red(uncle))
-				{
-					rb_set_black(uncle);
-					rb_set_black(parent);
-					rb_set_red(gparent);
-					node = gparent;
-					continue;
-				}
+		gparent = rb_red_parent(parent);
+
+		if (parent == gparent->rb_left) {
+			tmp = gparent->rb_right;
+			if (tmp && rb_is_red(tmp)) {
+				/*
+				 * Case 1 - color flips
+				 *
+				 *       G            g
+				 *      / \          / \
+				 *     p   u  -->   P   U
+				 *    /            /
+				 *   n            N
+				 *
+				 * However, since g's parent might be red, and
+				 * 4) does not allow this, we need to recurse
+				 * at g.
+				 */
+				rb_set_parent_color(tmp, gparent, RB_BLACK);
+				rb_set_parent_color(parent, gparent, RB_BLACK);
+				node = gparent;
+				parent = rb_parent(node);
+				rb_set_parent_color(node, parent, RB_RED);
+				continue;
 			}
 
 			if (parent->rb_right == node) {
-				__rb_rotate_left(parent, root);
+				/*
+				 * Case 2 - left rotate at parent
+				 *
+				 *      G             G
+				 *     / \           / \
+				 *    p   U  -->    n   U
+				 *     \           /
+				 *      n         p
+				 *
+				 * This still leaves us in violation of 4), the
+				 * continuation into Case 3 will fix that.
+				 */
+				parent->rb_right = tmp = node->rb_left;
+				node->rb_left = parent;
+				if (tmp)
+					rb_set_parent_color(tmp, parent,
+							    RB_BLACK);
+				rb_set_parent_color(parent, node, RB_RED);
 				parent = node;
 			}
 
-			rb_set_black(parent);
-			rb_set_red(gparent);
-			__rb_rotate_right(gparent, root);
+			/*
+			 * Case 3 - right rotate at gparent
+			 *
+			 *        G           P
+			 *       / \         / \
+			 *      p   U  -->  n   g
+			 *     /                 \
+			 *    n                   U
+			 */
+			gparent->rb_left = tmp = parent->rb_right;
+			parent->rb_right = gparent;
+			if (tmp)
+				rb_set_parent_color(tmp, gparent, RB_BLACK);
+			__rb_rotate_set_parents(gparent, parent, root, RB_RED);
 			break;
 		} else {
-			{
-				register struct rb_node *uncle = gparent->rb_left;
-				if (uncle && rb_is_red(uncle))
-				{
-					rb_set_black(uncle);
-					rb_set_black(parent);
-					rb_set_red(gparent);
-					node = gparent;
-					continue;
-				}
+			tmp = gparent->rb_left;
+			if (tmp && rb_is_red(tmp)) {
+				/* Case 1 - color flips */
+				rb_set_parent_color(tmp, gparent, RB_BLACK);
+				rb_set_parent_color(parent, gparent, RB_BLACK);
+				node = gparent;
+				parent = rb_parent(node);
+				rb_set_parent_color(node, parent, RB_RED);
+				continue;
 			}
 
 			if (parent->rb_left == node) {
-				__rb_rotate_right(parent, root);
+				/* Case 2 - right rotate at parent */
+				parent->rb_left = tmp = node->rb_right;
+				node->rb_right = parent;
+				if (tmp)
+					rb_set_parent_color(tmp, parent,
+							    RB_BLACK);
+				rb_set_parent_color(parent, node, RB_RED);
 				parent = node;
 			}
 
-			rb_set_black(parent);
-			rb_set_red(gparent);
-			__rb_rotate_left(gparent, root);
+			/* Case 3 - left rotate at gparent */
+			gparent->rb_right = tmp = parent->rb_left;
+			parent->rb_left = gparent;
+			if (tmp)
+				rb_set_parent_color(tmp, gparent, RB_BLACK);
+			__rb_rotate_set_parents(gparent, parent, root, RB_RED);
 			break;
 		}
 	}
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 09/12] rbtree: adjust node color in __rb_erase_color() only when necessary
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (7 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 08/12] rbtree: low level optimizations in rb_insert_color() Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 10/12] rbtree: optimize case selection logic in __rb_erase_color() Michel Lespinasse
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

In __rb_erase_color(), we were always setting a node to black after
exiting the main loop. And in one case, after fixing up the tree to
satisfy all rbtree invariants, we were setting the current node to root
just to guarantee a loop exit, at which point the root would be set to
black. However this is not necessary, as the root of an rbtree is already
known to be black. The only case where the color flip is required is when
we exit the loop due to the current node being red, and it's easiest to
just do the flip at that point instead of doing it after the loop.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |   28 +++++++++++++++++-----------
 1 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index 41cf19b..baf7c83 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -259,10 +259,22 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 {
 	struct rb_node *other;
 
-	while ((!node || rb_is_black(node)) && node != root->rb_node)
-	{
-		if (parent->rb_left == node)
-		{
+	while (true) {
+		/*
+		 * Loop invariant: all leaf paths going through node have a
+		 * black node count that is 1 lower than other leaf paths.
+		 *
+		 * If node is red, we can flip it to black to adjust.
+		 * If node is the root, all leaf paths go through it.
+		 * Otherwise, we need to adjust the tree through color flips
+		 * and tree rotations as per one of the 4 cases below.
+		 */
+		if (node && rb_is_red(node)) {
+			rb_set_black(node);
+			break;
+		} else if (!parent) {
+			break;
+		} else if (parent->rb_left == node) {
 			other = parent->rb_right;
 			if (rb_is_red(other))
 			{
@@ -291,12 +303,9 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 				rb_set_black(parent);
 				rb_set_black(other->rb_right);
 				__rb_rotate_left(parent, root);
-				node = root->rb_node;
 				break;
 			}
-		}
-		else
-		{
+		} else {
 			other = parent->rb_left;
 			if (rb_is_red(other))
 			{
@@ -325,13 +334,10 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 				rb_set_black(parent);
 				rb_set_black(other->rb_left);
 				__rb_rotate_right(parent, root);
-				node = root->rb_node;
 				break;
 			}
 		}
 	}
-	if (node)
-		rb_set_black(node);
 }
 
 void rb_erase(struct rb_node *node, struct rb_root *root)
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 10/12] rbtree: optimize case selection logic in __rb_erase_color()
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (8 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 09/12] rbtree: adjust node color in __rb_erase_color() only when necessary Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 11/12] rbtree: low level optimizations " Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 12/12] rbtree: coding style adjustments Michel Lespinasse
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

In __rb_erase_color(), we have to select one of 3 cases depending on the
color on the 'other' node children. If both children are black, we flip
a few node colors and iterate. Otherwise, we do either one or two
tree rotations, depending on the color of the 'other' child opposite
to 'node', and then we are done.

The corresponding logic had duplicate checks for the color of the 'other'
child opposite to 'node'. It was checking it first to determine if both
children are black, and then to determine how many tree rotations are
required. Rearrange the logic to avoid that extra check.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |   68 +++++++++++++++++++++++++--------------------------------
 1 files changed, 30 insertions(+), 38 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index baf7c83..eb823a3 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -283,28 +283,24 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 				__rb_rotate_left(parent, root);
 				other = parent->rb_right;
 			}
-			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-			    (!other->rb_right || rb_is_black(other->rb_right)))
-			{
-				rb_set_red(other);
-				node = parent;
-				parent = rb_parent(node);
-			}
-			else
-			{
-				if (!other->rb_right || rb_is_black(other->rb_right))
-				{
-					rb_set_black(other->rb_left);
+			if (!other->rb_right || rb_is_black(other->rb_right)) {
+				if (!other->rb_left ||
+				    rb_is_black(other->rb_left)) {
 					rb_set_red(other);
-					__rb_rotate_right(other, root);
-					other = parent->rb_right;
+					node = parent;
+					parent = rb_parent(node);
+					continue;
 				}
-				rb_set_color(other, rb_color(parent));
-				rb_set_black(parent);
-				rb_set_black(other->rb_right);
-				__rb_rotate_left(parent, root);
-				break;
+				rb_set_black(other->rb_left);
+				rb_set_red(other);
+				__rb_rotate_right(other, root);
+				other = parent->rb_right;
 			}
+			rb_set_color(other, rb_color(parent));
+			rb_set_black(parent);
+			rb_set_black(other->rb_right);
+			__rb_rotate_left(parent, root);
+			break;
 		} else {
 			other = parent->rb_left;
 			if (rb_is_red(other))
@@ -314,28 +310,24 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 				__rb_rotate_right(parent, root);
 				other = parent->rb_left;
 			}
-			if ((!other->rb_left || rb_is_black(other->rb_left)) &&
-			    (!other->rb_right || rb_is_black(other->rb_right)))
-			{
-				rb_set_red(other);
-				node = parent;
-				parent = rb_parent(node);
-			}
-			else
-			{
-				if (!other->rb_left || rb_is_black(other->rb_left))
-				{
-					rb_set_black(other->rb_right);
+			if (!other->rb_left || rb_is_black(other->rb_left)) {
+				if (!other->rb_right ||
+				    rb_is_black(other->rb_right)) {
 					rb_set_red(other);
-					__rb_rotate_left(other, root);
-					other = parent->rb_left;
+					node = parent;
+					parent = rb_parent(node);
+					continue;
 				}
-				rb_set_color(other, rb_color(parent));
-				rb_set_black(parent);
-				rb_set_black(other->rb_left);
-				__rb_rotate_right(parent, root);
-				break;
+				rb_set_black(other->rb_right);
+				rb_set_red(other);
+				__rb_rotate_left(other, root);
+				other = parent->rb_left;
 			}
+			rb_set_color(other, rb_color(parent));
+			rb_set_black(parent);
+			rb_set_black(other->rb_left);
+			__rb_rotate_right(parent, root);
+			break;
 		}
 	}
 }
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 11/12] rbtree: low level optimizations in __rb_erase_color()
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (9 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 10/12] rbtree: optimize case selection logic in __rb_erase_color() Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  2012-07-13  0:31 ` [PATCH v2 12/12] rbtree: coding style adjustments Michel Lespinasse
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

In __rb_erase_color(), we often already have pointers to the nodes
being rotated and/or know what their colors must be, so we can
generate more efficient code than the generic __rb_rotate_left()
and __rb_rotate_right() functions.

Also when the current node is red or when flipping the sibling's color,
the parent is already known so we can use the more efficient
rb_set_parent_color() function to set the desired color.

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |  208 ++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 115 insertions(+), 93 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index eb823a3..a38e473 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -39,7 +39,8 @@
  *  5), then the longest possible path due to 4 is 2B.
  *
  *  We shall indicate color with case, where black nodes are uppercase and red
- *  nodes will be lowercase.
+ *  nodes will be lowercase. Unknown color nodes shall be drawn as red within
+ *  parentheses and have some accompanying text comment.
  */
 
 #define	RB_RED		0
@@ -48,17 +49,11 @@
 #define rb_color(r)   ((r)->__rb_parent_color & 1)
 #define rb_is_red(r)   (!rb_color(r))
 #define rb_is_black(r) rb_color(r)
-#define rb_set_red(r)  do { (r)->__rb_parent_color &= ~1; } while (0)
-#define rb_set_black(r)  do { (r)->__rb_parent_color |= 1; } while (0)
 
 static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
 {
 	rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
 }
-static inline void rb_set_color(struct rb_node *rb, int color)
-{
-	rb->__rb_parent_color = (rb->__rb_parent_color & ~1) | color;
-}
 
 static inline void rb_set_parent_color(struct rb_node *rb,
 				       struct rb_node *p, int color)
@@ -71,52 +66,6 @@ static inline struct rb_node *rb_red_parent(struct rb_node *red)
 	return (struct rb_node *)red->__rb_parent_color;
 }
 
-static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
-{
-	struct rb_node *right = node->rb_right;
-	struct rb_node *parent = rb_parent(node);
-
-	if ((node->rb_right = right->rb_left))
-		rb_set_parent(right->rb_left, node);
-	right->rb_left = node;
-
-	rb_set_parent(right, parent);
-
-	if (parent)
-	{
-		if (node == parent->rb_left)
-			parent->rb_left = right;
-		else
-			parent->rb_right = right;
-	}
-	else
-		root->rb_node = right;
-	rb_set_parent(node, right);
-}
-
-static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
-{
-	struct rb_node *left = node->rb_left;
-	struct rb_node *parent = rb_parent(node);
-
-	if ((node->rb_left = left->rb_right))
-		rb_set_parent(left->rb_right, node);
-	left->rb_right = node;
-
-	rb_set_parent(left, parent);
-
-	if (parent)
-	{
-		if (node == parent->rb_right)
-			parent->rb_right = left;
-		else
-			parent->rb_left = left;
-	}
-	else
-		root->rb_node = left;
-	rb_set_parent(node, left);
-}
-
 /*
  * Helper function for rotations:
  * - old's parent and color get assigned to new
@@ -257,7 +206,7 @@ EXPORT_SYMBOL(rb_insert_color);
 static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 			     struct rb_root *root)
 {
-	struct rb_node *other;
+	struct rb_node *sibling, *tmp1, *tmp2;
 
 	while (true) {
 		/*
@@ -270,63 +219,136 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
 		 * and tree rotations as per one of the 4 cases below.
 		 */
 		if (node && rb_is_red(node)) {
-			rb_set_black(node);
+			rb_set_parent_color(node, parent, RB_BLACK);
 			break;
 		} else if (!parent) {
 			break;
 		} else if (parent->rb_left == node) {
-			other = parent->rb_right;
-			if (rb_is_red(other))
-			{
-				rb_set_black(other);
-				rb_set_red(parent);
-				__rb_rotate_left(parent, root);
-				other = parent->rb_right;
+			sibling = parent->rb_right;
+			if (rb_is_red(sibling)) {
+				/*
+				 * Case 1 - left rotate at parent
+				 *
+				 *     P               S
+				 *    / \             / \
+				 *   N   s    -->    p   Sr
+				 *      / \         / \
+				 *     Sl  Sr      N   Sl
+				 */
+				parent->rb_right = tmp1 = sibling->rb_left;
+				sibling->rb_left = parent;
+				rb_set_parent_color(tmp1, parent, RB_BLACK);
+				__rb_rotate_set_parents(parent, sibling, root,
+							RB_RED);
+				sibling = tmp1;
 			}
-			if (!other->rb_right || rb_is_black(other->rb_right)) {
-				if (!other->rb_left ||
-				    rb_is_black(other->rb_left)) {
-					rb_set_red(other);
+			tmp1 = sibling->rb_right;
+			if (!tmp1 || rb_is_black(tmp1)) {
+				tmp2 = sibling->rb_left;
+				if (!tmp2 || rb_is_black(tmp2)) {
+					/*
+					 * Case 2 - sibling color flip
+					 * (p could be either color here)
+					 *
+					 *    (p)           (p)
+					 *    / \           / \
+					 *   N   S    -->  N   s
+					 *      / \           / \
+					 *     Sl  Sr        Sl  Sr
+					 *
+					 * This leaves us violating 5), so
+					 * recurse at p. If p is red, the
+					 * recursion will just flip it to black
+					 * and exit. If coming from Case 1,
+					 * p is known to be red.
+					 */
+					rb_set_parent_color(sibling, parent,
+							    RB_RED);
 					node = parent;
 					parent = rb_parent(node);
 					continue;
 				}
-				rb_set_black(other->rb_left);
-				rb_set_red(other);
-				__rb_rotate_right(other, root);
-				other = parent->rb_right;
+				/*
+				 * Case 3 - right rotate at sibling
+				 * (p could be either color here)
+				 *
+				 *   (p)           (p)
+				 *   / \           / \
+				 *  N   S    -->  N   Sl
+				 *     / \             \
+				 *    sl  Sr            s
+				 *                       \
+				 *                        Sr
+				 */
+				sibling->rb_left = tmp1 = tmp2->rb_right;
+				tmp2->rb_right = sibling;
+				parent->rb_right = tmp2;
+				if (tmp1)
+					rb_set_parent_color(tmp1, sibling,
+							    RB_BLACK);
+				tmp1 = sibling;
+				sibling = tmp2;
 			}
-			rb_set_color(other, rb_color(parent));
-			rb_set_black(parent);
-			rb_set_black(other->rb_right);
-			__rb_rotate_left(parent, root);
+			/*
+			 * Case 4 - left rotate at parent + color flips
+			 * (p and sl could be either color here.
+			 *  After rotation, p becomes black, s acquires
+			 *  p's color, and sl keeps its color)
+			 *
+			 *      (p)             (s)
+			 *      / \             / \
+			 *     N   S     -->   P   Sr
+			 *        / \         / \
+			 *      (sl) sr      N  (sl)
+			 */
+			parent->rb_right = tmp2 = sibling->rb_left;
+			sibling->rb_left = parent;
+			rb_set_parent_color(tmp1, sibling, RB_BLACK);
+			if (tmp2)
+				rb_set_parent(tmp2, parent);
+			__rb_rotate_set_parents(parent, sibling, root,
+						RB_BLACK);
 			break;
 		} else {
-			other = parent->rb_left;
-			if (rb_is_red(other))
-			{
-				rb_set_black(other);
-				rb_set_red(parent);
-				__rb_rotate_right(parent, root);
-				other = parent->rb_left;
+			sibling = parent->rb_left;
+			if (rb_is_red(sibling)) {
+				/* Case 1 - right rotate at parent */
+				parent->rb_left = tmp1 = sibling->rb_right;
+				sibling->rb_right = parent;
+				rb_set_parent_color(tmp1, parent, RB_BLACK);
+				__rb_rotate_set_parents(parent, sibling, root,
+							RB_RED);
+				sibling = tmp1;
 			}
-			if (!other->rb_left || rb_is_black(other->rb_left)) {
-				if (!other->rb_right ||
-				    rb_is_black(other->rb_right)) {
-					rb_set_red(other);
+			tmp1 = sibling->rb_left;
+			if (!tmp1 || rb_is_black(tmp1)) {
+				tmp2 = sibling->rb_right;
+				if (!tmp2 || rb_is_black(tmp2)) {
+					/* Case 2 - sibling color flip */
+					rb_set_parent_color(sibling, parent,
+							    RB_RED);
 					node = parent;
 					parent = rb_parent(node);
 					continue;
 				}
-				rb_set_black(other->rb_right);
-				rb_set_red(other);
-				__rb_rotate_left(other, root);
-				other = parent->rb_left;
+				/* Case 3 - right rotate at sibling */
+				sibling->rb_right = tmp1 = tmp2->rb_left;
+				tmp2->rb_left = sibling;
+				parent->rb_left = tmp2;
+				if (tmp1)
+					rb_set_parent_color(tmp1, sibling,
+							    RB_BLACK);
+				tmp1 = sibling;
+				sibling = tmp2;
 			}
-			rb_set_color(other, rb_color(parent));
-			rb_set_black(parent);
-			rb_set_black(other->rb_left);
-			__rb_rotate_right(parent, root);
+			/* Case 4 - left rotate at parent + color flips */
+			parent->rb_left = tmp2 = sibling->rb_right;
+			sibling->rb_right = parent;
+			rb_set_parent_color(tmp1, sibling, RB_BLACK);
+			if (tmp2)
+				rb_set_parent(tmp2, parent);
+			__rb_rotate_set_parents(parent, sibling, root,
+						RB_BLACK);
 			break;
 		}
 	}
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 12/12] rbtree: coding style adjustments
  2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
                   ` (10 preceding siblings ...)
  2012-07-13  0:31 ` [PATCH v2 11/12] rbtree: low level optimizations " Michel Lespinasse
@ 2012-07-13  0:31 ` Michel Lespinasse
  11 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13  0:31 UTC (permalink / raw)
  To: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm, akpm
  Cc: linux-mm, linux-kernel, torvalds

Set comment and indentation style to be consistent with linux coding style
and the rest of the file, as suggested by Peter Zijlstra

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/rbtree.c |   42 +++++++++++++++++++++++-------------------
 1 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/lib/rbtree.c b/lib/rbtree.c
index a38e473..0892670 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -363,8 +363,7 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
 		child = node->rb_right;
 	else if (!node->rb_right)
 		child = node->rb_left;
-	else
-	{
+	else {
 		struct rb_node *old = node, *left;
 
 		node = node->rb_right;
@@ -406,17 +405,15 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
 
 	if (child)
 		rb_set_parent(child, parent);
-	if (parent)
-	{
+	if (parent) {
 		if (parent->rb_left == node)
 			parent->rb_left = child;
 		else
 			parent->rb_right = child;
-	}
-	else
+	} else
 		root->rb_node = child;
 
- color:
+color:
 	if (color == RB_BLACK)
 		__rb_erase_color(child, parent, root);
 }
@@ -529,8 +526,10 @@ struct rb_node *rb_next(const struct rb_node *node)
 	if (RB_EMPTY_NODE(node))
 		return NULL;
 
-	/* If we have a right-hand child, go down and then left as far
-	   as we can. */
+	/*
+	 * If we have a right-hand child, go down and then left as far
+	 * as we can.
+	 */
 	if (node->rb_right) {
 		node = node->rb_right; 
 		while (node->rb_left)
@@ -538,12 +537,13 @@ struct rb_node *rb_next(const struct rb_node *node)
 		return (struct rb_node *)node;
 	}
 
-	/* No right-hand children.  Everything down and left is
-	   smaller than us, so any 'next' node must be in the general
-	   direction of our parent. Go up the tree; any time the
-	   ancestor is a right-hand child of its parent, keep going
-	   up. First time it's a left-hand child of its parent, said
-	   parent is our 'next' node. */
+	/*
+	 * No right-hand children. Everything down and left is smaller than us,
+	 * so any 'next' node must be in the general direction of our parent.
+	 * Go up the tree; any time the ancestor is a right-hand child of its
+	 * parent, keep going up. First time it's a left-hand child of its
+	 * parent, said parent is our 'next' node.
+	 */
 	while ((parent = rb_parent(node)) && node == parent->rb_right)
 		node = parent;
 
@@ -558,8 +558,10 @@ struct rb_node *rb_prev(const struct rb_node *node)
 	if (RB_EMPTY_NODE(node))
 		return NULL;
 
-	/* If we have a left-hand child, go down and then right as far
-	   as we can. */
+	/*
+	 * If we have a left-hand child, go down and then right as far
+	 * as we can.
+	 */
 	if (node->rb_left) {
 		node = node->rb_left; 
 		while (node->rb_right)
@@ -567,8 +569,10 @@ struct rb_node *rb_prev(const struct rb_node *node)
 		return (struct rb_node *)node;
 	}
 
-	/* No left-hand children. Go up till we find an ancestor which
-	   is a right-hand child of its parent */
+	/*
+	 * No left-hand children. Go up till we find an ancestor which
+	 * is a right-hand child of its parent.
+	 */
 	while ((parent = rb_parent(node)) && node == parent->rb_left)
 		node = parent;
 
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 05/12] rbtree: performance and correctness test
  2012-07-13  0:31 ` [PATCH v2 05/12] rbtree: performance and correctness test Michel Lespinasse
@ 2012-07-13 20:15   ` Andrew Morton
  2012-07-13 22:33     ` Michel Lespinasse
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2012-07-13 20:15 UTC (permalink / raw)
  To: Michel Lespinasse
  Cc: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm,
	linux-mm, linux-kernel, torvalds

On Thu, 12 Jul 2012 17:31:50 -0700
Michel Lespinasse <walken@google.com> wrote:

> This small module helps measure the performance of rbtree insert and erase.
> 
> Additionally, we run a few correctness tests to check that the rbtrees have
> all desired properties:
> - contains the right number of nodes in the order desired,
> - never two consecutive red nodes on any path,
> - all paths to leaf nodes have the same number of black nodes,
> - root node is black
> 
> Signed-off-by: Michel Lespinasse <walken@google.com>
> ---
>  Makefile            |    2 +-
>  lib/Kconfig.debug   |    1 +
>  tests/Kconfig       |   18 +++++++
>  tests/Makefile      |    1 +
>  tests/rbtree_test.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++

This patch does a new thing: adds a kernel self-test module into
lib/tests/ and sets up the infrastructure to add new kernel self-test
modules in that directory.

I don't see a problem with this per-se, but it is a new thing which we
should think about.

In previous such cases (eg, kernel/rcutorture.c) we put those modules
into the same directory as the code which is being tested.  So to
follow that pattern, this new code would have gone into lib/.

If we adopt your new proposal then we should perhaps also move tests
such as rcutorture over into tests/.  And that makes one wonder whether
we should have a standalone directory for kernel selftest modules.  eg
tests/self-test-nmodules/.


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 05/12] rbtree: performance and correctness test
  2012-07-13 20:15   ` Andrew Morton
@ 2012-07-13 22:33     ` Michel Lespinasse
  2012-07-13 22:45       ` Andrew Morton
  0 siblings, 1 reply; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13 22:33 UTC (permalink / raw)
  To: Andrew Morton
  Cc: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm,
	linux-mm, linux-kernel, torvalds

On Fri, Jul 13, 2012 at 1:15 PM, Andrew Morton
<akpm@linux-foundation.org> wrote:
> On Thu, 12 Jul 2012 17:31:50 -0700 Michel Lespinasse <walken@google.com> wrote:
>>  Makefile            |    2 +-
>>  lib/Kconfig.debug   |    1 +
>>  tests/Kconfig       |   18 +++++++
>>  tests/Makefile      |    1 +
>>  tests/rbtree_test.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++
>
> This patch does a new thing: adds a kernel self-test module into
> lib/tests/ and sets up the infrastructure to add new kernel self-test
> modules in that directory.
>
> I don't see a problem with this per-se, but it is a new thing which we
> should think about.
>
> In previous such cases (eg, kernel/rcutorture.c) we put those modules
> into the same directory as the code which is being tested.  So to
> follow that pattern, this new code would have gone into lib/.
>
> If we adopt your new proposal then we should perhaps also move tests
> such as rcutorture over into tests/.  And that makes one wonder whether
> we should have a standalone directory for kernel selftest modules.  eg
> tests/self-test-nmodules/.

Ah, I did not realize we had a precedent for in-tree kernel test modules.

I don't think my proposal was significantly better than this
precedent, so I'll just adjust my patch to conform to it:
- move rbtree_test.c to lib/
- modify just lib/Makefile and lib/Kconfig.debug to get the module built.

Will send a replacement patch for this (so you can drop that one patch
from the stack and replace it with)

Thanks,

-- 
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 05/12] rbtree: performance and correctness test
  2012-07-13 22:33     ` Michel Lespinasse
@ 2012-07-13 22:45       ` Andrew Morton
  2012-07-13 23:09         ` Michel Lespinasse
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2012-07-13 22:45 UTC (permalink / raw)
  To: Michel Lespinasse
  Cc: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm,
	linux-mm, linux-kernel, torvalds

On Fri, 13 Jul 2012 15:33:35 -0700
Michel Lespinasse <walken@google.com> wrote:

> On Fri, Jul 13, 2012 at 1:15 PM, Andrew Morton
> <akpm@linux-foundation.org> wrote:
> > On Thu, 12 Jul 2012 17:31:50 -0700 Michel Lespinasse <walken@google.com> wrote:
> >>  Makefile            |    2 +-
> >>  lib/Kconfig.debug   |    1 +
> >>  tests/Kconfig       |   18 +++++++
> >>  tests/Makefile      |    1 +
> >>  tests/rbtree_test.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >
> > This patch does a new thing: adds a kernel self-test module into
> > lib/tests/ and sets up the infrastructure to add new kernel self-test
> > modules in that directory.
> >
> > I don't see a problem with this per-se, but it is a new thing which we
> > should think about.
> >
> > In previous such cases (eg, kernel/rcutorture.c) we put those modules
> > into the same directory as the code which is being tested.  So to
> > follow that pattern, this new code would have gone into lib/.
> >
> > If we adopt your new proposal then we should perhaps also move tests
> > such as rcutorture over into tests/.  And that makes one wonder whether
> > we should have a standalone directory for kernel selftest modules.  eg
> > tests/self-test-nmodules/.
> 
> Ah, I did not realize we had a precedent for in-tree kernel test modules.

hm, well, just because that's what we do now doesn't mean that it was a
good idea ;) These things arrive as a result of individual developers
doing stuff in their little directories and no particular thought was
put into overall structure.

It could be that it would be better to put all these tests into a
central place, rather than sprinkling them around the tree.  If so,
then your patch can lead the way, and we (ie: I) prod past and future
developers into getting with the program.

otoh, perhaps in-kernel test modules will rely on headers and constants
which are private to the implementation directory.  So perhaps
sprinkled-everywhere is the best approach.

> I don't think my proposal was significantly better than this
> precedent, so I'll just adjust my patch to conform to it:
> - move rbtree_test.c to lib/
> - modify just lib/Makefile and lib/Kconfig.debug to get the module built.
> 
> Will send a replacement patch for this (so you can drop that one patch
> from the stack and replace it with)

OK, you could do that too.  That way you avoid the problem and we can
worry about it later (if ever), as a separate activity.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 05/12] rbtree: performance and correctness test
  2012-07-13 22:45       ` Andrew Morton
@ 2012-07-13 23:09         ` Michel Lespinasse
  2012-07-13 23:11           ` Michel Lespinasse
  0 siblings, 1 reply; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13 23:09 UTC (permalink / raw)
  To: Andrew Morton
  Cc: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm,
	linux-mm, linux-kernel, torvalds

On Fri, Jul 13, 2012 at 3:45 PM, Andrew Morton
<akpm@linux-foundation.org> wrote:
> On Fri, 13 Jul 2012 15:33:35 -0700 Michel Lespinasse <walken@google.com> wrote:
>> Ah, I did not realize we had a precedent for in-tree kernel test modules.
>
> hm, well, just because that's what we do now doesn't mean that it was a
> good idea ;) These things arrive as a result of individual developers
> doing stuff in their little directories and no particular thought was
> put into overall structure.
>
> It could be that it would be better to put all these tests into a
> central place, rather than sprinkling them around the tree.  If so,
> then your patch can lead the way, and we (ie: I) prod past and future
> developers into getting with the program.
>
> otoh, perhaps in-kernel test modules will rely on headers and constants
> which are private to the implementation directory.  So perhaps
> sprinkled-everywhere is the best approach.

I think it is at least reasonable. Where we could improve, however,
would be on the Kconfig side of things.

>> I don't think my proposal was significantly better than this
>> precedent, so I'll just adjust my patch to conform to it:
>> - move rbtree_test.c to lib/
>> - modify just lib/Makefile and lib/Kconfig.debug to get the module built.
>>
>> Will send a replacement patch for this (so you can drop that one patch
>> from the stack and replace it with)
>
> OK, you could do that too.  That way you avoid the problem and we can
> worry about it later (if ever), as a separate activity.

Going to attach as a reply to this email.

-- 
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v2 05/12] rbtree: performance and correctness test
  2012-07-13 23:09         ` Michel Lespinasse
@ 2012-07-13 23:11           ` Michel Lespinasse
  0 siblings, 0 replies; 27+ messages in thread
From: Michel Lespinasse @ 2012-07-13 23:11 UTC (permalink / raw)
  To: Andrew Morton
  Cc: aarcange, dwmw2, riel, peterz, daniel.santos, axboe, ebiederm,
	linux-mm, linux-kernel, torvalds

This small module helps measure the performance of rbtree insert and erase.

Additionally, we run a few correctness tests to check that the rbtrees have
all desired properties:
- contains the right number of nodes in the order desired,
- never two consecutive red nodes on any path,
- all paths to leaf nodes have the same number of black nodes,
- root node is black

Signed-off-by: Michel Lespinasse <walken@google.com>
---
 lib/Kconfig.debug |    7 +++
 lib/Makefile      |    2 +
 lib/rbtree_test.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+), 0 deletions(-)
 create mode 100644 lib/rbtree_test.c

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6777153..736f564 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1145,6 +1145,13 @@ config LATENCYTOP
 source mm/Kconfig.debug
 source kernel/trace/Kconfig
 
+config RBTREE_TEST
+	tristate "Red-Black tree test"
+	depends on m && DEBUG_KERNEL
+	help
+	  A benchmark measuring the performance of the rbtree library.
+	  Also includes rbtree invariant checks.
+
 config PROVIDE_OHCI1394_DMA_INIT
 	bool "Remote debugging over FireWire early on boot"
 	depends on PCI && X86
diff --git a/lib/Makefile b/lib/Makefile
index 18515f0..4899899 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -123,6 +123,8 @@ obj-$(CONFIG_SIGNATURE) += digsig.o
 
 obj-$(CONFIG_CLZ_TAB) += clz_tab.o
 
+obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o
+
 hostprogs-y	:= gen_crc32table
 clean-files	:= crc32table.h
 
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c
new file mode 100644
index 0000000..4c6d250
--- /dev/null
+++ b/lib/rbtree_test.c
@@ -0,0 +1,135 @@
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/random.h>
+#include <asm/timex.h>
+
+#define NODES       100
+#define PERF_LOOPS  100000
+#define CHECK_LOOPS 100
+
+struct test_node {
+	struct rb_node rb;
+	u32 key;
+};
+
+static struct rb_root root = RB_ROOT;
+static struct test_node nodes[NODES];
+
+static struct rnd_state rnd;
+
+static void insert(struct test_node *node, struct rb_root *root)
+{
+	struct rb_node **new = &root->rb_node, *parent = NULL;
+
+	while (*new) {
+		parent = *new;
+		if (node->key < rb_entry(parent, struct test_node, rb)->key)
+			new = &parent->rb_left;
+		else
+			new = &parent->rb_right;
+	}
+
+	rb_link_node(&node->rb, parent, new);
+	rb_insert_color(&node->rb, root);
+}
+
+static inline void erase(struct test_node *node, struct rb_root *root)
+{
+	rb_erase(&node->rb, root);
+}
+
+static void init(void)
+{
+	int i;
+	for (i = 0; i < NODES; i++)
+		nodes[i].key = prandom32(&rnd);
+}
+
+static bool is_red(struct rb_node *rb)
+{
+	return !(rb->__rb_parent_color & 1);
+}
+
+static int black_path_count(struct rb_node *rb)
+{
+	int count;
+	for (count = 0; rb; rb = rb_parent(rb))
+		count += !is_red(rb);
+	return count;
+}
+
+static void check(int nr_nodes)
+{
+	struct rb_node *rb;
+	int count = 0;
+	int blacks;
+	u32 prev_key = 0;
+
+	for (rb = rb_first(&root); rb; rb = rb_next(rb)) {
+		struct test_node *node = rb_entry(rb, struct test_node, rb);
+		WARN_ON_ONCE(node->key < prev_key);
+		WARN_ON_ONCE(is_red(rb) &&
+			     (!rb_parent(rb) || is_red(rb_parent(rb))));
+		if (!count)
+			blacks = black_path_count(rb);
+		else
+			WARN_ON_ONCE((!rb->rb_left || !rb->rb_right) &&
+				     blacks != black_path_count(rb));
+		prev_key = node->key;
+		count++;
+	}
+	WARN_ON_ONCE(count != nr_nodes);
+}
+
+static int rbtree_test_init(void)
+{
+	int i, j;
+	cycles_t time1, time2, time;
+
+	printk(KERN_ALERT "rbtree testing");
+
+	prandom32_seed(&rnd, 3141592653589793238);
+	init();
+
+	time1 = get_cycles();
+
+	for (i = 0; i < PERF_LOOPS; i++) {
+		for (j = 0; j < NODES; j++)
+			insert(nodes + j, &root);
+		for (j = 0; j < NODES; j++)
+			erase(nodes + j, &root);
+	}
+
+	time2 = get_cycles();
+	time = time2 - time1;
+
+	time = div_u64(time, PERF_LOOPS);
+	printk(" -> %llu cycles\n", time);
+
+	for (i = 0; i < CHECK_LOOPS; i++) {
+		init();
+		for (j = 0; j < NODES; j++) {
+			check(j);
+			insert(nodes + j, &root);
+		}
+		for (j = 0; j < NODES; j++) {
+			check(NODES - j);
+			erase(nodes + j, &root);
+		}
+		check(0);
+	}
+
+	return -EAGAIN; /* Fail will directly unload the module */
+}
+
+static void rbtree_test_exit(void)
+{
+	printk(KERN_ALERT "test exit\n");
+}
+
+module_init(rbtree_test_init)
+module_exit(rbtree_test_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michel Lespinasse");
+MODULE_DESCRIPTION("Red Black Tree test");
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-07-13  0:31 ` [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary Michel Lespinasse
@ 2012-08-31  8:01   ` Adrian Hunter
  2012-08-31  8:07     ` Michel Lespinasse
  2012-09-08 11:49     ` [tip:perf/core] perf tools: Fix build for another rbtree.c change tip-bot for Adrian Hunter
  0 siblings, 2 replies; 27+ messages in thread
From: Adrian Hunter @ 2012-08-31  8:01 UTC (permalink / raw)
  To: akpm; +Cc: Michel Lespinasse, linux-mm, linux-kernel, acme

On 13/07/12 03:31, Michel Lespinasse wrote:
> The root node of an rbtree must always be black. However, rb_insert_color()
> only needs to maintain this invariant when it has been broken - that is,
> when it exits the loop due to the current (red) node being the root.
> In all other cases (exiting after tree rotations, or exiting due to
> an existing black parent) the invariant is already satisfied, so there
> is no need to adjust the root node color.
> 
> Signed-off-by: Michel Lespinasse <walken@google.com>
> ---
>  lib/rbtree.c |   19 +++++++++++++++----
>  1 files changed, 15 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/rbtree.c b/lib/rbtree.c
> index 12abb8a..d0be5fc 100644
> --- a/lib/rbtree.c
> +++ b/lib/rbtree.c
> @@ -91,8 +91,21 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
>  {
>  	struct rb_node *parent, *gparent;
>  
> -	while ((parent = rb_parent(node)) && rb_is_red(parent))
> -	{
> +	while (true) {

This breaks tools/perf build in linux-next:

../../lib/rbtree.c: In function 'rb_insert_color':
../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
../../lib/rbtree.c: In function '__rb_erase_color':
../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
../../lib/rbtree.c: In function 'rb_erase':
../../lib/rbtree.c:368:2: error: unknown type name 'bool'
make: *** [util/rbtree.o] Error 1

How about:

From: Adrian Hunter <adrian.hunter@intel.com>
Date: Fri, 31 Aug 2012 10:49:27 +0300
Subject: [PATCH] perf tools: fix build for another rbtree.c change

Fixes:

../../lib/rbtree.c: In function 'rb_insert_color':
../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
../../lib/rbtree.c: In function '__rb_erase_color':
../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
../../lib/rbtree.c: In function 'rb_erase':
../../lib/rbtree.c:368:2: error: unknown type name 'bool'
make: *** [util/rbtree.o] Error 1

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/include/linux/rbtree.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
index 7a243a1..2a030c5 100644
--- a/tools/perf/util/include/linux/rbtree.h
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -1 +1,2 @@
+#include <stdbool.h>
 #include "../../../../include/linux/rbtree.h"
-- 
1.7.11.4


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:01   ` Adrian Hunter
@ 2012-08-31  8:07     ` Michel Lespinasse
  2012-08-31  8:15       ` Andrew Morton
  2012-09-08 11:49     ` [tip:perf/core] perf tools: Fix build for another rbtree.c change tip-bot for Adrian Hunter
  1 sibling, 1 reply; 27+ messages in thread
From: Michel Lespinasse @ 2012-08-31  8:07 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: akpm, linux-mm, linux-kernel, acme

On Fri, Aug 31, 2012 at 1:01 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:
> This breaks tools/perf build in linux-next:
>
> ../../lib/rbtree.c: In function 'rb_insert_color':
> ../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
> ../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
> ../../lib/rbtree.c: In function '__rb_erase_color':
> ../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
> ../../lib/rbtree.c: In function 'rb_erase':
> ../../lib/rbtree.c:368:2: error: unknown type name 'bool'
> make: *** [util/rbtree.o] Error 1

I thought Andrew had a patch
rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
that fixed this though a Makefile change ?

-- 
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:07     ` Michel Lespinasse
@ 2012-08-31  8:15       ` Andrew Morton
  2012-08-31  8:35         ` Adrian Hunter
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Morton @ 2012-08-31  8:15 UTC (permalink / raw)
  To: Michel Lespinasse; +Cc: Adrian Hunter, linux-mm, linux-kernel, acme

On Fri, 31 Aug 2012 01:07:24 -0700 Michel Lespinasse <walken@google.com> wrote:

> On Fri, Aug 31, 2012 at 1:01 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:
> > This breaks tools/perf build in linux-next:
> >
> > ../../lib/rbtree.c: In function 'rb_insert_color':
> > ../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
> > ../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
> > ../../lib/rbtree.c: In function '__rb_erase_color':
> > ../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
> > ../../lib/rbtree.c: In function 'rb_erase':
> > ../../lib/rbtree.c:368:2: error: unknown type name 'bool'
> > make: *** [util/rbtree.o] Error 1
> 
> I thought Andrew had a patch
> rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
> that fixed this though a Makefile change ?

Yup.  But it's unclear why we should include the header via the cc
command line?


From: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Subject: rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation

Commit 2cfaf9cc68190c24fdd05e4d104099b3f27c7a44 (rbtree: adjust root color
in rb_insert_color() only when necessary) introduces bool type and constants
to the rbtree.c, and breaks compilation of tools/perf:

../../lib/rbtree.c: In function `rb_insert_color':
../../lib/rbtree.c:95:9: error: `true' undeclared (first use in this function)
../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once
or each function it appears in
../../lib/rbtree.c: In function `__rb_erase_color':
../../lib/rbtree.c:216:9: error: `true' undeclared (first use in this function)
../../lib/rbtree.c: In function `rb_erase':
../../lib/rbtree.c:368:2: error: unknown type name `bool'
make: *** [util/rbtree.o] Error 1

This patch is the easiest solution I can think of.

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Acked-by: Michel Lespinasse <walken@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 tools/perf/Makefile |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff -puN tools/perf/Makefile~rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation tools/perf/Makefile
--- a/tools/perf/Makefile~rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
+++ a/tools/perf/Makefile
@@ -806,7 +806,7 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' -include stdbool.h $<
 
 $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
_


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:15       ` Andrew Morton
@ 2012-08-31  8:35         ` Adrian Hunter
  2012-08-31  8:39           ` Michel Lespinasse
                             ` (2 more replies)
  0 siblings, 3 replies; 27+ messages in thread
From: Adrian Hunter @ 2012-08-31  8:35 UTC (permalink / raw)
  To: Shishkin, Alexander
  Cc: Andrew Morton, Michel Lespinasse, linux-mm, linux-kernel, acme

On 31/08/12 11:15, Andrew Morton wrote:
> On Fri, 31 Aug 2012 01:07:24 -0700 Michel Lespinasse <walken@google.com> wrote:
> 
>> On Fri, Aug 31, 2012 at 1:01 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>>> This breaks tools/perf build in linux-next:
>>>
>>> ../../lib/rbtree.c: In function 'rb_insert_color':
>>> ../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
>>> ../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
>>> ../../lib/rbtree.c: In function '__rb_erase_color':
>>> ../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
>>> ../../lib/rbtree.c: In function 'rb_erase':
>>> ../../lib/rbtree.c:368:2: error: unknown type name 'bool'
>>> make: *** [util/rbtree.o] Error 1
>>
>> I thought Andrew had a patch
>> rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
>> that fixed this though a Makefile change ?
> 
> Yup.  But it's unclear why we should include the header via the cc
> command line?

Dunno

AFAICS tools/perf/util/include/linux is for fixing up the
differences between kernel headers and exported kernel headers.
Hence my change:

diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
index 7a243a1..2a030c5 100644
--- a/tools/perf/util/include/linux/rbtree.h
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -1 +1,2 @@
+#include <stdbool.h>
 #include "../../../../include/linux/rbtree.h"

Alex?

> 
> 
> From: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Subject: rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
> 
> Commit 2cfaf9cc68190c24fdd05e4d104099b3f27c7a44 (rbtree: adjust root color
> in rb_insert_color() only when necessary) introduces bool type and constants
> to the rbtree.c, and breaks compilation of tools/perf:
> 
> ../../lib/rbtree.c: In function `rb_insert_color':
> ../../lib/rbtree.c:95:9: error: `true' undeclared (first use in this function)
> ../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once
> or each function it appears in
> ../../lib/rbtree.c: In function `__rb_erase_color':
> ../../lib/rbtree.c:216:9: error: `true' undeclared (first use in this function)
> ../../lib/rbtree.c: In function `rb_erase':
> ../../lib/rbtree.c:368:2: error: unknown type name `bool'
> make: *** [util/rbtree.o] Error 1
> 
> This patch is the easiest solution I can think of.
> 
> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Acked-by: Michel Lespinasse <walken@google.com>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
> 
>  tools/perf/Makefile |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff -puN tools/perf/Makefile~rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation tools/perf/Makefile
> --- a/tools/perf/Makefile~rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
> +++ a/tools/perf/Makefile
> @@ -806,7 +806,7 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/
>  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
>  
>  $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
> -	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
> +	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' -include stdbool.h $<
>  
>  $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
>  	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
> _
> 
> 
> 


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:35         ` Adrian Hunter
@ 2012-08-31  8:39           ` Michel Lespinasse
  2012-09-06 20:47             ` Olof Johansson
  2012-08-31  9:25           ` Alexander Shishkin
  2012-09-08  1:26           ` Arnaldo Carvalho de Melo
  2 siblings, 1 reply; 27+ messages in thread
From: Michel Lespinasse @ 2012-08-31  8:39 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Shishkin, Alexander, Andrew Morton, linux-mm, linux-kernel, acme

On Fri, Aug 31, 2012 at 1:35 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:
> On 31/08/12 11:15, Andrew Morton wrote:
>> On Fri, 31 Aug 2012 01:07:24 -0700 Michel Lespinasse <walken@google.com> wrote:
>>> I thought Andrew had a patch
>>> rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
>>> that fixed this though a Makefile change ?
>>
>> Yup.  But it's unclear why we should include the header via the cc
>> command line?
>
> Dunno
>
> AFAICS tools/perf/util/include/linux is for fixing up the
> differences between kernel headers and exported kernel headers.
> Hence my change:
>
> diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
> index 7a243a1..2a030c5 100644
> --- a/tools/perf/util/include/linux/rbtree.h
> +++ b/tools/perf/util/include/linux/rbtree.h
> @@ -1 +1,2 @@
> +#include <stdbool.h>
>  #include "../../../../include/linux/rbtree.h"
>
> Alex?

Ah, makes sense to me. I wasn't previously aware of the
tools/perf/util/include/linux directory. I think your fix is fine.
(I don't understand how you hit the issue given the previous Makefile
fix, but I think your fix looks nicer)

-- 
Michel "Walken" Lespinasse
A program is never fully debugged until the last user dies.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:35         ` Adrian Hunter
  2012-08-31  8:39           ` Michel Lespinasse
@ 2012-08-31  9:25           ` Alexander Shishkin
  2012-09-08  1:26           ` Arnaldo Carvalho de Melo
  2 siblings, 0 replies; 27+ messages in thread
From: Alexander Shishkin @ 2012-08-31  9:25 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Andrew Morton, Michel Lespinasse, linux-mm, linux-kernel, acme

Adrian Hunter <adrian.hunter@intel.com> writes:

> On 31/08/12 11:15, Andrew Morton wrote:
>> On Fri, 31 Aug 2012 01:07:24 -0700 Michel Lespinasse <walken@google.com> wrote:
>> 
>>> On Fri, Aug 31, 2012 at 1:01 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>>>> This breaks tools/perf build in linux-next:
>>>>
>>>> ../../lib/rbtree.c: In function 'rb_insert_color':
>>>> ../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
>>>> ../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
>>>> ../../lib/rbtree.c: In function '__rb_erase_color':
>>>> ../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
>>>> ../../lib/rbtree.c: In function 'rb_erase':
>>>> ../../lib/rbtree.c:368:2: error: unknown type name 'bool'
>>>> make: *** [util/rbtree.o] Error 1
>>>
>>> I thought Andrew had a patch
>>> rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
>>> that fixed this though a Makefile change ?
>> 
>> Yup.  But it's unclear why we should include the header via the cc
>> command line?
>
> Dunno
>
> AFAICS tools/perf/util/include/linux is for fixing up the
> differences between kernel headers and exported kernel headers.
> Hence my change:
>
> diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
> index 7a243a1..2a030c5 100644
> --- a/tools/perf/util/include/linux/rbtree.h
> +++ b/tools/perf/util/include/linux/rbtree.h
> @@ -1 +1,2 @@
> +#include <stdbool.h>
>  #include "../../../../include/linux/rbtree.h"
>
> Alex?

Whichever color like best. :) Consider my initial patch a bugreport.

Regards,
--
Alex

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:39           ` Michel Lespinasse
@ 2012-09-06 20:47             ` Olof Johansson
  0 siblings, 0 replies; 27+ messages in thread
From: Olof Johansson @ 2012-09-06 20:47 UTC (permalink / raw)
  To: Michel Lespinasse
  Cc: Adrian Hunter, Shishkin, Alexander, Andrew Morton, linux-mm,
	linux-kernel, acme

On Fri, Aug 31, 2012 at 1:39 AM, Michel Lespinasse <walken@google.com> wrote:
> On Fri, Aug 31, 2012 at 1:35 AM, Adrian Hunter <adrian.hunter@intel.com> wrote:
>> On 31/08/12 11:15, Andrew Morton wrote:
>>> On Fri, 31 Aug 2012 01:07:24 -0700 Michel Lespinasse <walken@google.com> wrote:
>>>> I thought Andrew had a patch
>>>> rbtree-adjust-root-color-in-rb_insert_color-only-when-necessary-fix-perf-compilation
>>>> that fixed this though a Makefile change ?
>>>
>>> Yup.  But it's unclear why we should include the header via the cc
>>> command line?
>>
>> Dunno
>>
>> AFAICS tools/perf/util/include/linux is for fixing up the
>> differences between kernel headers and exported kernel headers.
>> Hence my change:
>>
>> diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
>> index 7a243a1..2a030c5 100644
>> --- a/tools/perf/util/include/linux/rbtree.h
>> +++ b/tools/perf/util/include/linux/rbtree.h
>> @@ -1 +1,2 @@
>> +#include <stdbool.h>
>>  #include "../../../../include/linux/rbtree.h"
>>
>> Alex?
>
> Ah, makes sense to me. I wasn't previously aware of the
> tools/perf/util/include/linux directory. I think your fix is fine.
> (I don't understand how you hit the issue given the previous Makefile
> fix, but I think your fix looks nicer)

Looks like the Makefile change either never landed, or has since been dropped.

Can we please get this one picked up? Without it, perf is unbuildable
on linux-next.


-Olof

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary
  2012-08-31  8:35         ` Adrian Hunter
  2012-08-31  8:39           ` Michel Lespinasse
  2012-08-31  9:25           ` Alexander Shishkin
@ 2012-09-08  1:26           ` Arnaldo Carvalho de Melo
  2 siblings, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-09-08  1:26 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Shishkin, Alexander, Andrew Morton, Michel Lespinasse, linux-mm,
	linux-kernel

Em Fri, Aug 31, 2012 at 11:35:40AM +0300, Adrian Hunter escreveu:
> AFAICS tools/perf/util/include/linux is for fixing up the
> differences between kernel headers and exported kernel headers.
> Hence my change:
> 
> diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
> index 7a243a1..2a030c5 100644
> --- a/tools/perf/util/include/linux/rbtree.h
> +++ b/tools/perf/util/include/linux/rbtree.h
> @@ -1 +1,2 @@
> +#include <stdbool.h>
>  #include "../../../../include/linux/rbtree.h"

I applied this one now, thanks,

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf tools: Fix build for another rbtree.c change
  2012-08-31  8:01   ` Adrian Hunter
  2012-08-31  8:07     ` Michel Lespinasse
@ 2012-09-08 11:49     ` tip-bot for Adrian Hunter
  1 sibling, 0 replies; 27+ messages in thread
From: tip-bot for Adrian Hunter @ 2012-09-08 11:49 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, hpa, mingo, akpm, adrian.hunter, tglx, walken

Commit-ID:  b155a09015135cf59ada8d48109ccbd9891c1b42
Gitweb:     http://git.kernel.org/tip/b155a09015135cf59ada8d48109ccbd9891c1b42
Author:     Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Fri, 31 Aug 2012 10:49:27 +0300
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 7 Sep 2012 22:21:59 -0300

perf tools: Fix build for another rbtree.c change

Fixes:

../../lib/rbtree.c: In function 'rb_insert_color':
../../lib/rbtree.c:95:9: error: 'true' undeclared (first use in this function)
../../lib/rbtree.c:95:9: note: each undeclared identifier is reported only once for each function it appears in
../../lib/rbtree.c: In function '__rb_erase_color':
../../lib/rbtree.c:216:9: error: 'true' undeclared (first use in this function)
../../lib/rbtree.c: In function 'rb_erase':
../../lib/rbtree.c:368:2: error: unknown type name 'bool'
make: *** [util/rbtree.o] Error 1

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Michel Lespinasse <walken@google.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mm@kvack.org
Link: http://lkml.kernel.org/r/50406F60.5040707@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/include/linux/rbtree.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h
index 7a243a1..2a030c5 100644
--- a/tools/perf/util/include/linux/rbtree.h
+++ b/tools/perf/util/include/linux/rbtree.h
@@ -1 +1,2 @@
+#include <stdbool.h>
 #include "../../../../include/linux/rbtree.h"

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2012-09-08 11:49 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-13  0:31 [PATCH v2 00/12] rbtree updates Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 01/12] rbtree: reference Documentation/rbtree.txt for usage instructions Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 02/12] rbtree: empty nodes have no color Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 03/12] rbtree: fix incorrect rbtree node insertion in fs/proc/proc_sysctl.c Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 04/12] rbtree: move some implementation details from rbtree.h to rbtree.c Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 05/12] rbtree: performance and correctness test Michel Lespinasse
2012-07-13 20:15   ` Andrew Morton
2012-07-13 22:33     ` Michel Lespinasse
2012-07-13 22:45       ` Andrew Morton
2012-07-13 23:09         ` Michel Lespinasse
2012-07-13 23:11           ` Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 06/12] rbtree: break out of rb_insert_color loop after tree rotation Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 07/12] rbtree: adjust root color in rb_insert_color() only when necessary Michel Lespinasse
2012-08-31  8:01   ` Adrian Hunter
2012-08-31  8:07     ` Michel Lespinasse
2012-08-31  8:15       ` Andrew Morton
2012-08-31  8:35         ` Adrian Hunter
2012-08-31  8:39           ` Michel Lespinasse
2012-09-06 20:47             ` Olof Johansson
2012-08-31  9:25           ` Alexander Shishkin
2012-09-08  1:26           ` Arnaldo Carvalho de Melo
2012-09-08 11:49     ` [tip:perf/core] perf tools: Fix build for another rbtree.c change tip-bot for Adrian Hunter
2012-07-13  0:31 ` [PATCH v2 08/12] rbtree: low level optimizations in rb_insert_color() Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 09/12] rbtree: adjust node color in __rb_erase_color() only when necessary Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 10/12] rbtree: optimize case selection logic in __rb_erase_color() Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 11/12] rbtree: low level optimizations " Michel Lespinasse
2012-07-13  0:31 ` [PATCH v2 12/12] rbtree: coding style adjustments Michel Lespinasse

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).