public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Store sysfs dirent structs in rbtree
@ 2010-06-24  2:56 Nathan Fontenot
  2010-06-24 18:04 ` Cornelia Huck
  0 siblings, 1 reply; 3+ messages in thread
From: Nathan Fontenot @ 2010-06-24  2:56 UTC (permalink / raw)
  To: linux-kernel

On very large systems, i.e. those with > 1 TB of memory, the boot times become
exponentially worse due to the string compares used to ensure duplicate sysfs
directories are not created.  I am working with systems that create roughly
63,000 memory sections in sysfs at boot time.  This translates into just over 9
minutes of creating sysfs entries for the memory on the system at boot.  Other
systems have observed 40 minutes for 1.5 TB and times measured in hours for 2
TB systems.

This patch updates the sysfs code to store the sysfs directory entries in a
reb-black tree sorted aphabetically.  This significantly reduces the number of
string compares required to determine if a new directory is a duplicate.  On
the 1 TB system the sysfs memory creation time went from 9.1 minutes to 2.2
minutes.

Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
 fs/sysfs/dir.c   |   60 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 fs/sysfs/sysfs.h |    3 ++
 2 files changed, 56 insertions(+), 7 deletions(-)

Index: linux-2.6/fs/sysfs/dir.c
===================================================================
--- linux-2.6.orig/fs/sysfs/dir.c	2010-06-23 15:07:22.000000000 -0500
+++ linux-2.6/fs/sysfs/dir.c	2010-06-23 20:12:46.000000000 -0500
@@ -30,6 +30,37 @@
 static DEFINE_SPINLOCK(sysfs_ino_lock);
 static DEFINE_IDA(sysfs_ino_ida);
 
+static struct sysfs_dirent *to_sysfs_dirent(struct rb_node *node)
+{
+	struct sysfs_elem_dir *sysdir;
+
+	sysdir = rb_entry(node, struct sysfs_elem_dir, rb_node);
+	return container_of(sysdir, struct sysfs_dirent, s_dir);
+}
+
+static void sysfs_dirent_insert(struct sysfs_dirent *sd)
+{
+	struct sysfs_dirent *parent_sd = sd->s_parent;
+	struct sysfs_dirent *d;
+	struct rb_node **p = &parent_sd->s_dir.rb_root.rb_node;
+	struct rb_node *parent = NULL;
+
+	while (*p) {
+		int cmp_val;
+		parent = *p;
+		d = to_sysfs_dirent(parent);
+
+		cmp_val = strcmp(d->s_name, sd->s_name);
+		if (cmp_val < 0)
+			p = &parent->rb_left;
+		if (cmp_val > 0)
+			p = &parent->rb_right;
+	}
+
+	rb_link_node(&sd->s_dir.rb_node, parent, p);
+	rb_insert_color(&sd->s_dir.rb_node, &parent_sd->s_dir.rb_root);
+}
+
 /**
  *	sysfs_link_sibling - link sysfs_dirent into sibling list
  *	@sd: sysfs_dirent of interest
@@ -57,6 +88,9 @@
 	}
 	sd->s_sibling = *pos;
 	*pos = sd;
+
+	/* Add entry to rb tree */
+	sysfs_dirent_insert(sd);
 }
 
 /**
@@ -81,6 +115,8 @@
 			break;
 		}
 	}
+
+	rb_erase(&sd->s_dir.rb_node, &sd->s_parent->s_dir.rb_root);
 }
 
 /**
@@ -536,14 +572,24 @@
 				       const void *ns,
 				       const unsigned char *name)
 {
-	struct sysfs_dirent *sd;
-
-	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
-		if (ns && sd->s_ns && (sd->s_ns != ns))
-			continue;
-		if (!strcmp(sd->s_name, name))
-			return sd;
+	struct sysfs_dirent *d;
+	struct rb_node **p = &parent_sd->s_dir.rb_root.rb_node;
+	struct rb_node *parent = NULL;
+
+	while (*p) {
+		int cmp_val;
+		parent = *p;
+		d = to_sysfs_dirent(parent);
+
+		cmp_val = strcmp(d->s_name, name);
+		if (cmp_val == 0)
+			return d;
+		else if (cmp_val < 0)
+			p = &parent->rb_left;
+		else /* (cmp_val > 0) */
+			p = &parent->rb_right;
 	}
+
 	return NULL;
 }
 
Index: linux-2.6/fs/sysfs/sysfs.h
===================================================================
--- linux-2.6.orig/fs/sysfs/sysfs.h	2010-06-23 15:07:22.000000000 -0500
+++ linux-2.6/fs/sysfs/sysfs.h	2010-06-23 20:12:46.000000000 -0500
@@ -10,12 +10,15 @@
 
 #include <linux/lockdep.h>
 #include <linux/fs.h>
+#include <linux/rbtree.h>
 
 struct sysfs_open_dirent;
 
 /* type-specific structures for sysfs_dirent->s_* union members */
 struct sysfs_elem_dir {
 	struct kobject		*kobj;
+	struct rb_root		rb_root;
+	struct rb_node		rb_node;
 	/* children list starts here and goes through sd->s_sibling */
 	struct sysfs_dirent	*children;
 };

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

* Re: [PATCH] Store sysfs dirent structs in rbtree
  2010-06-24  2:56 [PATCH] Store sysfs dirent structs in rbtree Nathan Fontenot
@ 2010-06-24 18:04 ` Cornelia Huck
  2010-06-25  1:58   ` Nathan Fontenot
  0 siblings, 1 reply; 3+ messages in thread
From: Cornelia Huck @ 2010-06-24 18:04 UTC (permalink / raw)
  To: Nathan Fontenot; +Cc: linux-kernel

On Wed, 23 Jun 2010 21:56:04 -0500,
Nathan Fontenot <nfont@austin.ibm.com> wrote:

> +static void sysfs_dirent_insert(struct sysfs_dirent *sd)
> +{
> +	struct sysfs_dirent *parent_sd = sd->s_parent;
> +	struct sysfs_dirent *d;
> +	struct rb_node **p = &parent_sd->s_dir.rb_root.rb_node;
> +	struct rb_node *parent = NULL;
> +
> +	while (*p) {
> +		int cmp_val;
> +		parent = *p;
> +		d = to_sysfs_dirent(parent);
> +
> +		cmp_val = strcmp(d->s_name, sd->s_name);
> +		if (cmp_val < 0)
> +			p = &parent->rb_left;
> +		if (cmp_val > 0)
> +			p = &parent->rb_right;
> +	}
> +
> +	rb_link_node(&sd->s_dir.rb_node, parent, p);
> +	rb_insert_color(&sd->s_dir.rb_node, &parent_sd->s_dir.rb_root);
> +}

This will run into trouble if you have duplicate names in different
namespaces. You won't see it with your patch though, since...

> @@ -536,14 +572,24 @@
>  				       const void *ns,
>  				       const unsigned char *name)
>  {
> -	struct sysfs_dirent *sd;
> -
> -	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
> -		if (ns && sd->s_ns && (sd->s_ns != ns))
> -			continue;
> -		if (!strcmp(sd->s_name, name))
> -			return sd;
> +	struct sysfs_dirent *d;
> +	struct rb_node **p = &parent_sd->s_dir.rb_root.rb_node;
> +	struct rb_node *parent = NULL;
> +
> +	while (*p) {
> +		int cmp_val;
> +		parent = *p;
> +		d = to_sysfs_dirent(parent);
> +
> +		cmp_val = strcmp(d->s_name, name);
> +		if (cmp_val == 0)
> +			return d;
> +		else if (cmp_val < 0)
> +			p = &parent->rb_left;
> +		else /* (cmp_val > 0) */
> +			p = &parent->rb_right;
>  	}
> +
>  	return NULL;
>  }

...you removed the namespace check down here.

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

* Re: [PATCH] Store sysfs dirent structs in rbtree
  2010-06-24 18:04 ` Cornelia Huck
@ 2010-06-25  1:58   ` Nathan Fontenot
  0 siblings, 0 replies; 3+ messages in thread
From: Nathan Fontenot @ 2010-06-25  1:58 UTC (permalink / raw)
  To: Cornelia Huck; +Cc: linux-kernel

On 06/24/2010 01:04 PM, Cornelia Huck wrote:
> On Wed, 23 Jun 2010 21:56:04 -0500,
> Nathan Fontenot <nfont@austin.ibm.com> wrote:
> 
>> +static void sysfs_dirent_insert(struct sysfs_dirent *sd)
>> +{
>> +	struct sysfs_dirent *parent_sd = sd->s_parent;
>> +	struct sysfs_dirent *d;
>> +	struct rb_node **p = &parent_sd->s_dir.rb_root.rb_node;
>> +	struct rb_node *parent = NULL;
>> +
>> +	while (*p) {
>> +		int cmp_val;
>> +		parent = *p;
>> +		d = to_sysfs_dirent(parent);
>> +
>> +		cmp_val = strcmp(d->s_name, sd->s_name);
>> +		if (cmp_val < 0)
>> +			p = &parent->rb_left;
>> +		if (cmp_val > 0)
>> +			p = &parent->rb_right;
>> +	}
>> +
>> +	rb_link_node(&sd->s_dir.rb_node, parent, p);
>> +	rb_insert_color(&sd->s_dir.rb_node, &parent_sd->s_dir.rb_root);
>> +}
> 
> This will run into trouble if you have duplicate names in different
> namespaces. You won't see it with your patch though, since...
> 
>> @@ -536,14 +572,24 @@
>>  				       const void *ns,
>>  				       const unsigned char *name)
>>  {
>> -	struct sysfs_dirent *sd;
>> -
>> -	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
>> -		if (ns && sd->s_ns && (sd->s_ns != ns))
>> -			continue;
>> -		if (!strcmp(sd->s_name, name))
>> -			return sd;
>> +	struct sysfs_dirent *d;
>> +	struct rb_node **p = &parent_sd->s_dir.rb_root.rb_node;
>> +	struct rb_node *parent = NULL;
>> +
>> +	while (*p) {
>> +		int cmp_val;
>> +		parent = *p;
>> +		d = to_sysfs_dirent(parent);
>> +
>> +		cmp_val = strcmp(d->s_name, name);
>> +		if (cmp_val == 0)
>> +			return d;
>> +		else if (cmp_val < 0)
>> +			p = &parent->rb_left;
>> +		else /* (cmp_val > 0) */
>> +			p = &parent->rb_right;
>>  	}
>> +
>>  	return NULL;
>>  }
> 
> ...you removed the namespace check down here.

Yep, I missed namespaces completely with this patch.  I'll try again.

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


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

end of thread, other threads:[~2010-06-25  1:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-24  2:56 [PATCH] Store sysfs dirent structs in rbtree Nathan Fontenot
2010-06-24 18:04 ` Cornelia Huck
2010-06-25  1:58   ` Nathan Fontenot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox