All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nathan Fontenot <nfont@austin.ibm.com>
To: linux-kernel@vger.kernel.org
Subject: [PATCH] Store sysfs dirent structs in rbtree
Date: Wed, 23 Jun 2010 21:56:04 -0500	[thread overview]
Message-ID: <4C22C944.4040700@austin.ibm.com> (raw)

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;
 };

             reply	other threads:[~2010-06-24  2:56 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-24  2:56 Nathan Fontenot [this message]
2010-06-24 18:04 ` [PATCH] Store sysfs dirent structs in rbtree Cornelia Huck
2010-06-25  1:58   ` Nathan Fontenot

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=4C22C944.4040700@austin.ibm.com \
    --to=nfont@austin.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

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

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