smbd: Tune "dir" a bit.
authorVolker Lendecke <vl@samba.org>
Thu, 21 Mar 2013 21:00:06 +0000 (22:00 +0100)
committerKarolin Seeger <kseeger@samba.org>
Fri, 26 Apr 2013 07:25:03 +0000 (09:25 +0200)
for i in $(seq 1 20000) ; do echo dir ; done | smbclient //127.0.0.1/tmp -U%

without and with this patch:

$ time bin/smbd -d0 -i
smbd version 4.1.0pre1-GIT-1f139ae started.
Copyright Andrew Tridgell and the Samba Team 1992-2013
Beendet

real    0m28.342s
user    0m10.249s
sys     0m10.513s

$ time bin/smbd -d0 -i
smbd version 4.1.0pre1-GIT-1f139ae started.
Copyright Andrew Tridgell and the Samba Team 1992-2013
Beendet

real    0m27.348s
user    0m9.089s
sys     0m10.853s

The "real" timestamp is irrelevant, this also contains the time between
starting smbd and the smbclient job. It's the "user" time. The result that this
patch improves the time spent in user space by 10% is consistent.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Fix bug #9736 - Change to smbd/dir.c code gives significant performance
increases on large directory listings.
(cherry picked from commit 565d1409c7c424fbbeed1e98b042d3970b0acf73)

source3/smbd/dir.c

index 92be816a4e427d78ca2ec23625cba2ba0b81053c..f7bc325d9fe4f57c701510e25f094875ddeaf14e 100644 (file)
@@ -941,12 +941,14 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
                           long *_prev_offset)
 {
        connection_struct *conn = dirptr->conn;
-       bool needslash;
+       size_t slashlen;
+       size_t pathlen;
 
        *_smb_fname = NULL;
        *_mode = 0;
 
-       needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
+       pathlen = strlen(dirptr->path);
+       slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
 
        while (true) {
                long cur_offset;
@@ -990,16 +992,27 @@ bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
                        continue;
                }
 
-               pathreal = talloc_asprintf(ctx, "%s%s%s",
-                                          dirptr->path,
-                                          needslash?"/":"",
-                                          dname);
+               /*
+                * This used to be
+                * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
+                *                            needslash?"/":"", dname);
+                * but this was measurably slower than doing the memcpy.
+                */
+
+               pathreal = talloc_array(
+                       ctx, char,
+                       pathlen + slashlen + talloc_get_size(dname));
                if (!pathreal) {
                        TALLOC_FREE(dname);
                        TALLOC_FREE(fname);
                        return false;
                }
 
+               memcpy(pathreal, dirptr->path, pathlen);
+               pathreal[pathlen] = '/';
+               memcpy(pathreal + slashlen + pathlen, dname,
+                      talloc_get_size(dname));
+
                /* Create smb_fname with NULL stream_name. */
                ZERO_STRUCT(smb_fname);
                smb_fname.base_name = pathreal;