cache-autotune-20050817
authorNiklas Edmundsson <Niklas.Edmundsson@hpc2n.umu.se>
Wed, 17 Aug 2005 17:16:50 +0000 (17:16 +0000)
committerJim Rees <rees@umich.edu>
Wed, 17 Aug 2005 17:16:50 +0000 (17:16 +0000)
This patch tries to implement the afsd default tuning parameters
discussed in the thread starting at
https://www.openafs.org/pipermail/openafs-devel/2005-May/012158.html

I took the liberty of adding chunksize-tuning to the memcache too,
with the motivation that people using large memcaches usually wants
better bulk performance too.

It seems to work for me using both disk cache and memcache of various
sizes.

src/afs/afs_chunk.c
src/afs/afs_chunkops.h
src/afsd/afsd.c

index 562192b..d4845b6 100644 (file)
@@ -22,92 +22,8 @@ RCSID
  * Chunk module.
  */
 
-afs_int32 afs_FirstCSize = AFS_DEFAULTCSIZE;
-afs_int32 afs_OtherCSize = AFS_DEFAULTCSIZE;
-afs_int32 afs_LogChunk = AFS_DEFAULTLSIZE;
-
-#ifdef notdef
-int
-afs_ChunkOffset(offset)
-     afs_int32 offset;
-{
-
-    AFS_STATCNT(afs_ChunkOffset);
-    if (offset < afs_FirstCSize)
-       return offset;
-    else
-       return ((offset - afs_FirstCSize) & (afs_OtherCSize - 1));
-}
-
-
-int
-afs_Chunk(offset)
-     afs_int32 offset;
-{
-    AFS_STATCNT(afs_Chunk);
-    if (offset < afs_FirstCSize)
-       return 0;
-    else
-       return (((offset - afs_FirstCSize) >> afs_LogChunk) + 1);
-}
-
-
-int
-afs_ChunkBase(offset)
-     int offset;
-{
-    AFS_STATCNT(afs_ChunkBase);
-    if (offset < afs_FirstCSize)
-       return 0;
-    else
-       return (((offset - afs_FirstCSize) & ~(afs_OtherCSize - 1)) +
-               afs_FirstCSize);
-}
-
-
-int
-afs_ChunkSize(offset)
-     afs_int32 offset;
-{
-    AFS_STATCNT(afs_ChunkSize);
-    if (offset < afs_FirstCSize)
-       return afs_FirstCSize;
-    else
-       return afs_OtherCSize;
-}
-
-
-int
-afs_ChunkToBase(chunk)
-     afs_int32 chunk;
-{
-    AFS_STATCNT(afs_ChunkToBase);
-    if (chunk == 0)
-       return 0;
-    else
-       return (afs_FirstCSize + ((chunk - 1) << afs_LogChunk));
-}
-
-
-int
-afs_ChunkToSize(chunk)
-     afs_int32 chunk;
-{
-    AFS_STATCNT(afs_ChunkToSize);
-    if (chunk == 0)
-       return afs_FirstCSize;
-    else
-       return afs_OtherCSize;
-}
-
-/* sizes are a power of two */
-int
-afs_SetChunkSize(chunk)
-     afs_int32 chunk;
-{
-    AFS_STATCNT(afs_SetChunkSize);
-    afs_LogChunk = chunk;
-    afs_FirstCSize = afs_OtherCSize = (1 << chunk);
-}
-
-#endif /* notdef */
+/* Place the defaults in afsd instead of all around the code, so
+ * AFS_SETCHUNKSIZE() needs to be called before doing anything */
+afs_int32 afs_FirstCSize = 0;
+afs_int32 afs_OtherCSize = 0;
+afs_int32 afs_LogChunk = 0;
index 9a482dc..53dc1fb 100644 (file)
       Chunks are 0 based and go up by exactly 1, covering the file.
       The other fields are internal and shouldn't be used */
 /* basic parameters */
-#ifdef AFS_NOCHUNKING
-
-#define        AFS_OTHERCSIZE  0x10000
-#define        AFS_LOGCHUNK    16
-#define        AFS_FIRSTCSIZE  0x40000000
-
-#else /* AFS_NOCHUNKING */
 
 #define AFS_OTHERCSIZE  (afs_OtherCSize)
 #define AFS_LOGCHUNK    (afs_LogChunk)
 #define AFS_DEFAULTCSIZE 0x10000
 #define AFS_DEFAULTLSIZE 16
 
-#endif /* AFS_NOCHUNKING */
-
-#define AFS_MINCHUNK 13                /* 8k is minimum */
-#define AFS_MAXCHUNK 18                /* 256K is maximum */
-
 #define AFS_CHUNKOFFSET(offset) ((offset < afs_FirstCSize) ? offset : \
                         ((offset - afs_FirstCSize) & (afs_OtherCSize - 1)))
 
index 2f47921..84debcf 100644 (file)
@@ -229,10 +229,10 @@ struct in_addr_42 {
 afs_int32 enable_rxbind = 0;
 afs_int32 afs_shutdown = 0;
 afs_int32 cacheBlocks;         /*Num blocks in the cache */
-afs_int32 cacheFiles = 1000;   /*Optimal # of files in workstation cache */
+afs_int32 cacheFiles;          /*Optimal # of files in workstation cache */
 afs_int32 rwpct = 0;
 afs_int32 ropct = 0;
-afs_int32 cacheStatEntries = 300;      /*Number of stat cache entries */
+afs_int32 cacheStatEntries;    /*Number of stat cache entries */
 char cacheBaseDir[1024];       /*Where the workstation AFS cache lives */
 char confDir[1024];            /*Where the workstation AFS configuration lives */
 char fullpn_DCacheFile[1024];  /*Full pathname of DCACHEFILE */
@@ -247,6 +247,7 @@ int sawCacheBaseDir = 0;
 int sawCacheBlocks = 0;
 int sawDCacheSize = 0;
 int sawBiod = 0;
+int sawCacheStatEntries = 0;
 char cacheMountDir[1024];      /*Mount directory for AFS */
 char rootVolume[64] = "root.afs";      /*AFS root volume name */
 afs_int32 cacheSetTime = FALSE;        /*Keep checking time to avoid drift? */
@@ -261,8 +262,8 @@ static int filesSet = 0;    /*True if number of files explicitly set */
 static int nFilesPerDir = 2048;        /* # files per cache dir */
 static int nDaemons = 2;       /* Number of background daemons */
 static int chunkSize = 0;      /* 2^chunkSize bytes per chunk */
-static int dCacheSize = 300;   /* # of dcache entries */
-static int vCacheSize = 50;    /* # of volume cache entries */
+static int dCacheSize;         /* # of dcache entries */
+static int vCacheSize = 200;   /* # of volume cache entries */
 static int rootVolSet = 0;     /*True if root volume name explicitly set */
 int addrNum;                   /*Cell server address index being printed */
 static int cacheFlags = 0;     /*Flags to cache manager */
@@ -591,7 +592,7 @@ CreateCacheSubDir(basename, dirNum)
     /* Build the new cache subdirectory */
     sprintf(dir, "%s/D%d", basename, dirNum);
 
-    if (afsd_verbose)
+    if (afsd_debug)
        printf("%s: Creating cache subdir '%s'\n", rn, dir);
 
     if ((ret = mkdir(dir, 0700)) != 0) {
@@ -661,7 +662,7 @@ CreateCacheFile(fname, statp)
     int cfd;                   /*File descriptor to AFS cache file */
     int closeResult;           /*Result of close() */
 
-    if (afsd_verbose)
+    if (afsd_debug)
        printf("%s: Creating cache file '%s'\n", rn, fname);
     cfd = open(fname, createAndTrunc, ownerRWmode);
     if (cfd <= 0) {
@@ -693,13 +694,26 @@ static void
 CreateFileIfMissing(char *fullpn, int missing)
 {
     if (missing) {
-       if (afsd_verbose)
-           printf("CreateFileIfMissing: Creating '%s'\n", fullpn);
        if (CreateCacheFile(fullpn, NULL))
            printf("CreateFileIfMissing: Can't create '%s'\n", fullpn);
     }
 }
 
+static void
+UnlinkUnwantedFile(char *rn, char *fullpn_FileToDelete, char *fileToDelete)
+{
+    if (unlink(fullpn_FileToDelete)) {
+       if ((errno == EISDIR || errno == EPERM) && *fileToDelete == 'D') {
+           if (rmdir(fullpn_FileToDelete)) {
+               printf("%s: Can't rmdir '%s', errno is %d\n", rn,
+                      fullpn_FileToDelete, errno);
+           }
+       } else
+           printf("%s: Can't unlink '%s', errno is %d\n", rn,
+                  fullpn_FileToDelete, errno);
+    }
+}
+
 /*-----------------------------------------------------------------------------
   * SweepAFSCache
   *
@@ -906,16 +920,7 @@ doSweepAFSCache(vFilesFound, directory, dirNum, maxDir)
            sprintf(fileToDelete, "%s", currp->d_name);
            if (afsd_verbose)
                printf("%s: Deleting '%s'\n", rn, fullpn_FileToDelete);
-           if (unlink(fullpn_FileToDelete)) {
-               if (errno == EISDIR && *fileToDelete == 'D') {
-                   if (rmdir(fullpn_FileToDelete)) {
-                       printf("%s: Can't rmdir '%s', errno is %d\n", rn,
-                              fullpn_FileToDelete, errno);
-                   }
-               } else
-                   printf("%s: Can't unlink '%s', errno is %d\n", rn,
-                          fullpn_FileToDelete, errno);
-           }
+           UnlinkUnwantedFile(rn, fullpn_FileToDelete, fileToDelete);
        }
     }
 
@@ -1025,16 +1030,7 @@ doSweepAFSCache(vFilesFound, directory, dirNum, maxDir)
        /* Remove any directories >= maxDir -- they should be empty */
        for (; highDir >= maxDir; highDir--) {
            sprintf(fileToDelete, "D%d", highDir);
-           if (unlink(fullpn_FileToDelete)) {
-               if (errno == EISDIR && *fileToDelete == 'D') {
-                   if (rmdir(fullpn_FileToDelete)) {
-                       printf("%s: Can't rmdir '%s', errno is %d\n", rn,
-                              fullpn_FileToDelete, errno);
-                   }
-               } else
-                   printf("%s: Can't unlink '%s', errno is %d\n", rn,
-                          fullpn_FileToDelete, errno);
-           }
+           UnlinkUnwantedFile(rn, fullpn_FileToDelete, fileToDelete);
        }
     }
 
@@ -1196,13 +1192,10 @@ SweepAFSCache(vFilesFound)
 }
 
 static
-ConfigCell(aci, arock, adir)
-     register struct afsconf_cell *aci;
-     char *arock;
-     struct afsconf_dir *adir;
+ConfigCell(struct afsconf_cell *aci, char *arock, struct afsconf_dir *adir)
 {
-    register int isHomeCell;
-    register int i, code;
+    int isHomeCell;
+    int i, code;
     afs_int32 cellFlags = 0;
     afs_int32 hosts[MAXHOSTSPERCELL];
 
@@ -1230,10 +1223,8 @@ ConfigCell(aci, arock, adir)
 }
 
 static
-ConfigCellAlias(aca, arock, adir)
-     register struct afsconf_cellalias *aca;
-     char *arock;
-     struct afsconf_dir *adir;
+ConfigCellAlias(struct afsconf_cellalias *aca,
+               char *arock, struct afsconf_dir *adir)
 {
     /* push the alias into the kernel */
     call_syscall(AFSOP_ADDCELLALIAS, aca->aliasName, aca->realName);
@@ -1314,13 +1305,11 @@ AfsdbLookupHandler()
 #endif
 #endif
 
-mainproc(as, arock)
-     struct cmd_syndesc *as;
-     char *arock;
+mainproc(struct cmd_syndesc *as, char *arock)
 {
     static char rn[] = "afsd"; /*Name of this routine */
-    register afs_int32 code;   /*Result of fork() */
-    register int i;
+    afs_int32 code;            /*Result of fork() */
+    int i;
     int currVFile;             /*Current AFS cache file number passed in */
     int mountFlags;            /*Flags passed to mount() */
     int lookupResult;          /*Result of GetLocalCellName() */
@@ -1363,14 +1352,13 @@ mainproc(as, arock)
     if (as->parms[3].items) {
        /* -stat */
        cacheStatEntries = atoi(as->parms[3].items->data);
+       sawCacheStatEntries = 1;
     }
     if (as->parms[4].items) {
        /* -memcache */
        cacheBaseDir[0] = '\0';
        sawCacheBaseDir = 1;
        cacheFlags |= AFSCALL_INIT_MEMCACHE;
-       if (chunkSize == 0)
-           chunkSize = 13;
     }
     if (as->parms[5].items) {
        /* -cachedir */
@@ -1601,7 +1589,13 @@ mainproc(as, arock)
        /* memory cache: size described either as blocks or dcache entries, but
         * not both.
         */
+       if (filesSet) {
+           fprintf(stderr, "%s: -files ignored with -memcache\n", rn);
+       }
        if (sawDCacheSize) {
+           if (chunkSize == 0) {
+               chunkSize = 13; /* 8k default chunksize for memcache */
+           }
            if (sawCacheBlocks) {
                printf
                    ("%s: can't set cache blocks and dcache size simultaneously when diskless.\n",
@@ -1609,18 +1603,26 @@ mainproc(as, arock)
                exit(1);
            }
            /* compute the cache size based on # of chunks times the chunk size */
-           i = (chunkSize == 0 ? 13 : chunkSize);
-           i = (1 << i);       /* bytes per chunk */
+           i = (1 << chunkSize);       /* bytes per chunk */
            cacheBlocks = i * dCacheSize;
            sawCacheBlocks = 1; /* so that ParseCacheInfoFile doesn't overwrite */
        } else {
+           if (chunkSize == 0) {
+               /* Try to autotune the memcache chunksize based on size
+                * of memcache. This is done on the assumption that approx
+                * 1024 chunks is suitable, it's a balance between enough
+                * chunks to be useful and ramping up nicely when using larger
+                * memcache to improve bulk read/write performance
+                */
+               for (i = 14;
+                    i <= 21 && (1 << i) / 1024 < (cacheBlocks / 1024); i++);
+               chunkSize = i - 1;
+           }
            /* compute the dcache size from overall cache size and chunk size */
-           i = (chunkSize == 0 ? 13 : chunkSize);
-           /* dCacheSize = (cacheBlocks << 10) / (1<<i); */
-           if (i > 10) {
-               dCacheSize = (cacheBlocks >> (i - 10));
-           } else if (i < 10) {
-               dCacheSize = (cacheBlocks << (10 - i));
+           if (chunkSize > 10) {
+               dCacheSize = (cacheBlocks >> (chunkSize - 10));
+           } else if (chunkSize < 10) {
+               dCacheSize = (cacheBlocks << (10 - chunkSize));
            } else {
                dCacheSize = cacheBlocks;
            }
@@ -1628,8 +1630,11 @@ mainproc(as, arock)
             * by ParseCacheInfoFile.
             */
        }
-       /* kernel computes # of dcache entries as min of cacheFiles and dCacheSize,
-        * so we now make them equal.
+       if (afsd_verbose)
+           printf("%s: chunkSize autotuned to %d\n", rn, chunkSize);
+
+       /* kernel computes # of dcache entries as min of cacheFiles and
+        * dCacheSize, so we now make them equal.
         */
        cacheFiles = dCacheSize;
     } else {
@@ -1638,43 +1643,87 @@ mainproc(as, arock)
         * but only if -files isn't given on the command line.
         * Don't let # files be so small as to prevent full utilization 
         * of the cache unless user has explicitly asked for it.
-        * average V-file is ~10K, according to tentative empirical studies.
         */
+       if (chunkSize == 0) {
+           /* Set chunksize to 256kB - 1MB depending on cache size */
+           if (cacheBlocks < 500000) {
+               chunkSize = 18;
+           } else if (cacheBlocks < 1000000) {
+               chunkSize = 19;
+           } else {
+               chunkSize = 20;
+           }
+       }
        if (!filesSet) {
-           cacheFiles = cacheBlocks / 10;
-           if (cacheFiles < 100)
-               cacheFiles = 100;
+           cacheFiles = cacheBlocks / 32;      /* Assume 32k avg filesize */
+
+           cacheFiles = max(cacheFiles, 1000);
+
            /* Always allow more files than chunks.  Presume average V-file 
             * is ~67% of a chunk...  (another guess, perhaps Honeyman will
             * have a grad student write a paper).  i is KILOBYTES.
             */
-           i = 1 << (chunkSize ==
-                     0 ? 6 : (chunkSize < 10 ? 0 : chunkSize - 10));
+           i = 1 << (chunkSize < 10 ? 0 : chunkSize - 10);
            cacheFiles = max(cacheFiles, 1.5 * (cacheBlocks / i));
+
            /* never permit more files than blocks, while leaving space for
             * VolumeInfo and CacheItems files.  VolumeInfo is usually 20K,
             * CacheItems is 50 Bytes / file (== 1K/20)
             */
-#define VOLINFOSZ 20
 #define CACHEITMSZ (cacheFiles / 20)
-#ifdef AFS_AIX_ENV
-           cacheFiles =
-               min(cacheFiles, (cacheBlocks - VOLINFOSZ - CACHEITMSZ) / 4);
-#else
-           cacheFiles =
-               min(cacheFiles, cacheBlocks - VOLINFOSZ - CACHEITMSZ);
-#endif
+#define VOLINFOSZ 50           /* 40kB has been seen, be conservative */
+#define CELLINFOSZ 4           /* Assuming disk block size is 4k ... */
+#define INFOSZ (VOLINFOSZ+CELLINFOSZ+CACHEITMSZ)
+
+           /* Sanity check: If the obtained number of disk cache files
+            * is larger than the number of available (4k) disk blocks, we're
+            * doing something wrong. Fail hard so we can fix the bug instead
+            * of silently hiding it like before */
+
+           if (cacheFiles > (cacheBlocks - INFOSZ) / 4) {
+               fprintf(stderr,
+                       "%s: ASSERT: cacheFiles %d  diskblocks %d\n",
+                       rn, cacheFiles, (cacheBlocks - INFOSZ) / 4);
+               exit(1);
+           }
            if (cacheFiles < 100)
                fprintf(stderr, "%s: WARNING: cache probably too small!\n",
                        rn);
+
+           if (afsd_verbose)
+               printf("%s: cacheFiles autotuned to %d\n", rn, cacheFiles);
        }
+       /* Sanity check chunkSize */
+       i = max(cacheBlocks / 1000, cacheBlocks / cacheFiles);
+       chunkSize = min(chunkSize, i);
+       chunkSize = max(chunkSize, 2);
+       if (afsd_verbose)
+           printf("%s: chunkSize autotuned to %d\n", rn, chunkSize);
+
        if (!sawDCacheSize) {
-           if ((cacheFiles / 2) > dCacheSize)
-               dCacheSize = cacheFiles / 2;
-           if (dCacheSize > 2000)
+           dCacheSize = cacheFiles / 2;
+           if (dCacheSize > 10000) {
+               dCacheSize = 10000;
+           }
+           if (dCacheSize < 2000) {
                dCacheSize = 2000;
+           }
+           if (afsd_verbose)
+               printf("%s: dCacheSize autotuned to %d\n", rn, dCacheSize);
        }
     }
+    if (!sawCacheStatEntries) {
+       if (chunkSize <= 13) {
+           cacheStatEntries = dCacheSize / 4;
+       } else if (chunkSize >= 16) {
+           cacheStatEntries = dCacheSize * 1.5;
+       } else {
+           cacheStatEntries = dCacheSize;
+       }
+       if (afsd_verbose)
+           printf("%s: cacheStatEntries autotuned to %d\n", rn,
+                  cacheStatEntries);
+    }
 
     /*
      * Create and zero the inode table for the desired cache files.
@@ -2134,9 +2183,7 @@ mainproc(as, arock)
 
 
 
-main(argc, argv)
-     int argc;
-     char **argv;
+main(int argc, char **argv)
 {
     struct cmd_syndesc *ts;
 
@@ -2208,7 +2255,7 @@ main(argc, argv)
                "Prefer backup volumes for mointpoints in backup volumes");
     cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
                "Bind the Rx socket (one interface only)");
-    cmd_AddParm(ts, "-settime", CMD_FLAG, CMD_OPTIONAL, "don't set the time");
+    cmd_AddParm(ts, "-settime", CMD_FLAG, CMD_OPTIONAL, "set the time");
     cmd_AddParm(ts, "-rxpck", CMD_SINGLE, CMD_OPTIONAL,
                "set rx_extraPackets to this value");
     cmd_AddParm(ts, "-splitcache", CMD_SINGLE, CMD_OPTIONAL,
@@ -2407,15 +2454,14 @@ aix_vmount()
     return (error);
 }
 
-vmountdata(vmtp, obj, stub, host, hostsname, info, args)
-     struct vmount *vmtp;
-     char *obj, *stub, *host, *hostsname, *info, *args;
+vmountdata(struct vmount * vmtp, char *obj, char *stub, char *host,
+          char *hostsname, char *info, char *args)
 {
-    register struct data {
+    struct data {
        short vmt_off;
        short vmt_size;
     } *vdp, *vdprev;
-    register int size;
+    int size;
 
     vdp = (struct data *)vmtp->vmt_data;
     vdp->vmt_off = sizeof(struct vmount);