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