patch: optimize mbnambuf routines in msdosfs

Nate Lawson nate at root.org
Sat Mar 5 23:51:50 PST 2005


In my profiling, I found mbnambuf_* were the top 4 CPU hogs on my system 
when doing directory IO on an msdosfs partition.  After examination, no 
wonder:  repeated malloc/free, excessive strcpy, etc.

The mbnambuf is indexed by the windows ID, a sequential one-based value. 
    The attached patch optimizes this routine with this in mind, using 
the ID to index into a single array and concatenating each WIN_CHARS 
chunk at once.  (The last chunk is variable-length.)

The part I'd like review for especially is the struct dirent semantics. 
  The sys/dirent.h says that the names should always be null-terminated 
to a multiple of 4 bytes.  The original code did not do this and neither 
does mine.  (It always null terminates, but the result can be an odd 
number of bytes long.)

This code has been tested as working on an FS with dificult filename 
sizes (255, 13, 26, etc.)  It gives a whopping 77.1% decrease in 
profiled time (total across all functions) and a 73.7% decrease in wall 
time.  Test was "ls -laR > /dev/null"

Individual performance gains are below:
mbnambuf_init:  -90.7%
mbnambuf_write: -18.7%
mbnambuf_flush: -67.1%

-- 
Nate
-------------- next part --------------
Index: msdosfs_conv.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_conv.c,v
retrieving revision 1.39
diff -u -r1.39 msdosfs_conv.c
--- msdosfs_conv.c	8 Feb 2005 07:51:14 -0000	1.39
+++ msdosfs_conv.c	2 Mar 2005 17:48:52 -0000
@@ -101,11 +102,13 @@
 static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *);
 static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *);
 
+#if 0
 struct mbnambuf {
 	char *		p;
 	size_t		n;
 };
 static struct mbnambuf subent[WIN_MAXSUBENTRIES];
+#endif
 
 /*
  * Convert the unix version of time to dos's idea of time to be used in
@@ -1194,6 +1198,7 @@
 	return (wc);
 }
 
+#if 0
 /*
  * Make subent empty
  */
@@ -1251,3 +1257,55 @@
 	mbnambuf_init();
 	return (dp->d_name);
 }
+#else
+
+static char *nambuf_ptr;
+static size_t nambuf_len;
+static int nambuf_max_id;
+
+void
+mbnambuf_init(void)
+{
+
+        if (nambuf_ptr == NULL) { 
+		nambuf_ptr = malloc(MAXNAMLEN + 1, M_MSDOSFSMNT, M_WAITOK);
+		nambuf_ptr[MAXNAMLEN] = '\0';
+	}
+	nambuf_len = 0;
+	nambuf_max_id = -1;
+}
+
+void
+mbnambuf_write(char *name, int id)
+{
+	size_t count;
+
+	count = WIN_CHARS;
+	if (id > nambuf_max_id) {
+		count = strlen(name);
+		nambuf_len = id * WIN_CHARS + count;
+		if (nambuf_len > MAXNAMLEN) {
+			printf("msdosfs: file name %d too long\n", nambuf_len);
+			return;
+		}
+		nambuf_max_id = id;
+	}
+	memcpy(nambuf_ptr + (id * WIN_CHARS), name, count);
+}
+
+char *
+mbnambuf_flush(struct dirent *dp)
+{
+
+	if (nambuf_len > sizeof(dp->d_name) - 1) {
+		mbnambuf_init();
+		return (NULL);
+	}
+	nambuf_ptr[nambuf_len] = '\0';
+	memcpy(dp->d_name, nambuf_ptr, nambuf_len + 1);
+	dp->d_namlen = nambuf_len;
+
+	mbnambuf_init();
+	return (dp->d_name);
+}
+#endif


More information about the freebsd-arch mailing list