Date: Sat, 05 Mar 2005 23:51:47 -0800 From: Nate Lawson <nate@root.org> To: arch@freebsd.org Subject: patch: optimize mbnambuf routines in msdosfs Message-ID: <422AB693.9040600@root.org>
next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------030500080703020202000908
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
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
--------------030500080703020202000908
Content-Type: text/plain;
name="msd2.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="msd2.diff"
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
--------------030500080703020202000908--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?422AB693.9040600>
